如何在接收网络驱动程序的IRQ期间发送数据包?

时间:2016-02-15 20:36:28

标签: linux-kernel network-programming linux-device-driver kernel-module

对于一个研究项目,我目前正在修改一个Linux驱动程序。我对这个话题还比较陌生,所以我不确定我在这里犯了一个明显的错误。

我的目标是在驱动程序IRQ期间捕获传入的ICMP数据包,并立即将回复发送回发送方。现在,无论如何,如果校验和或任何事情是正确的,我只想尽快发回一些东西。为此,我在IRQ期间运行以下代码:

data = skb-> data;

/* we received an ICMP request. Send custom reply. */
if(data[9] == 1){// && data[20] == 8){
   unsigned long start = jiffies;
   unsigned long end;
   u8 * newdata;
   u16 ippacketLength;
   sk_quickreply = dev_alloc_skb(128);

   struct ethhdr *  mac_skb_quick;
   struct iphdr * iph_skb_quick;
   struct ethhdr *  mac_skb = eth_hdr(skb);

   struct iphdr * iph_skb = data;

   quicktransmit = 1;


   /* Put icmp packet */
   skb_push(sk_quickreply, 26);

   /* Put IP header */
   skb_push(sk_quickreply, sizeof(struct iphdr));
   skb_reset_network_header(sk_quickreply);
   iph_skb_quick = ip_hdr(sk_quickreply);
   iph_skb_quick->version = 4;
   iph_skb_quick->ihl = 5;
   iph_skb_quick->ttl = 64;
   iph_skb_quick->daddr = iph_skb->saddr;
   iph_skb_quick->saddr = iph_skb->daddr;
   iph_skb_quick->protocol = 1; //ICMP
   ip_send_check(iph_skb_quick);


   /* Put MAC header */
   eth_header(sk_quickreply, dev, ETH_P_802_3, mac_skb->h_source, mac_skb->h_dest, 14);
   skb_reset_mac_header(sk_quickreply);
   mac_skb_quick = eth_hdr(sk_quickreply);

   rtl8168_mystart_xmit(sk_quickreply,dev);
}

其中rtl8168_mystart_xmit是驱动程序最初提供的hard_start_xmit函数,但我删除了自旋锁:

static int rtl8168_mystart_xmit(struct sk_buff *skb,
               struct net_device *dev)
{

    struct rtl8168_private *tp = netdev_priv(dev);
    unsigned int frags, entry;
    struct TxDesc *txd;
    void __iomem *ioaddr = tp->mmio_addr;
    dma_addr_t mapping;
    u32 len;
    u32 opts1;
    u32 opts2;
    int ret = NETDEV_TX_OK;
    unsigned long flags, large_send;

    printk(KERN_INFO "Starting transmission of fast reply.\n");



    if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
            if (netif_msg_drv(tp)) {
                    printk(KERN_ERR
                           "%s: BUG! Tx Ring full when queue awake!\n",
                           dev->name);
            }
            goto err_stop;
    }

    entry = tp->cur_tx % NUM_TX_DESC;
    txd = tp->TxDescArray + entry;



    if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
            goto err_stop;

    opts1 = DescOwn;
    opts2 = rtl8168_tx_vlan_tag(tp, skb);

      large_send = 0;
    if (dev->features & NETIF_F_TSO) {

            u32 mss = skb_shinfo(skb)->gso_size;

            printk(KERN_INFO "Large send.\n");

            /* TCP Segmentation Offload (or TCP Large Send) */
            if (mss) {
                    if ((tp->mcfg == CFG_METHOD_1) ||
                        (tp->mcfg == CFG_METHOD_2) ||
                        (tp->mcfg == CFG_METHOD_3)) {
                            opts1 |= LargeSend | ((mss & MSSMask) << 16);
                    } else if ((tp->mcfg == CFG_METHOD_11) ||
                               (tp->mcfg == CFG_METHOD_12) ||
                               (tp->mcfg == CFG_METHOD_13)) {
                            opts2 |= LargeSend_DP | ((mss & MSSMask) << 18);
                    } else {
                            opts1 |= LargeSend;
                            opts2 |= (mss & MSSMask) << 18;
                    }
                    large_send = 1;
            }
    }



    if (large_send == 0) {
         printk(KERN_INFO "No large send.\n");
            if (dev->features & NETIF_F_IP_CSUM) {
                    if ((tp->mcfg == CFG_METHOD_1) || (tp->mcfg == CFG_METHOD_2) || (tp->mcfg == CFG_METHOD_3))
                            opts1 |= rtl8168_tx_csum(skb, dev);
                    else
                            opts2 |= rtl8168_tx_csum(skb, dev);
            }
    }



    frags = rtl8168_xmit_frags(tp, skb, opts1, opts2);
    printk(KERN_INFO "Frags: %u\n", frags);
    if (frags) {
            len = skb_headlen(skb);
            opts1 |= FirstFrag;
    } else {
            len = skb->len;

            tp->tx_skb[entry].skb = skb;

            if (tp->UseSwPaddingShortPkt && len < 60) {
                printk(KERN_INFO "Packet uses padding\n");
                    rtl8168_sw_padding_short_pkt(tp, skb, opts1, opts2);
                    opts1 |= FirstFrag;
                    frags++;
            } else {
                printk(KERN_INFO "Packet doesn't use padding\n");
                //This code means, the fragment is the first and the last fragment to be send
                    opts1 |= FirstFrag | LastFrag;
            }
    }


    printk(KERN_INFO "Length: %u\n", len);
    opts1 |= len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
    mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
    tp->tx_skb[entry].len = len;
    txd->addr = cpu_to_le64(mapping);
    txd->opts2 = cpu_to_le32(opts2);
    txd->opts1 = cpu_to_le32(opts1&~DescOwn);
    wmb();
    txd->opts1 = cpu_to_le32(opts1);

    dev->trans_start = jiffies;

    tp->cur_tx += frags + 1;

    wmb();



    RTL_W8(TxPoll, HPQ);    /* set polling bit */






out:
    return ret;
err_stop:
    printk(KERN_INFO "Problem: Jumped to err_stop\n");
    //netif_stop_queue(dev);
    //ret = NETDEV_TX_BUSY;
    //RTLDEV->stats.tx_dropped++;

    spin_unlock_irqrestore(&tp->lock, flags);
    goto out;
}

我正在从第二台计算机发送ping请求,这台计算机已经设置为混杂模式。似乎答案永远不会在第一时间发送。我做错了什么或者甚至可能在IRQ期间传输这样的信息?

提前感谢您的帮助。

0 个答案:

没有答案