查看文章
 
net_rx() -- 从网卡接收packets
2007年10月16日 星期二 17:11
net_interrupt() --> net_rx()

    net_rx() -- 从网卡接收packets(最多10个数据包)Receive a data packet
    The driver method used to handle incoming packets is responsible for requesting a socket buffer and for filling the packet data space with the packet received. The method dev_alloc_skb() can be used to request a new socket buffer. This method attempts to get a used socket buffer from the socket-buffer cache to avoid slow memory management.
    Occasionally, more than one packet arrives. In the example discussed in this section, we use up to 10 packets that are accepted by the network adapter and introduced as socket buffers to the Linux network architecture. The status of a received packet can generally be verified from specific hardware registers (i.e., whether the packet was received correctly and, if not, which error occurred). If errors occur, then these are generally collected in a net_device_stats structure, which is not part of the net_device structure; it has to be managed in the private data space (dev->priv) of the network device.
    Once a packet has been received correctly and the packet data has been transferred to the packet data range of the socket buffer, the receiving network device dev is registered in the sk_buff structure.
    Subsequently, netif_rx(skb) can place the socket buffers in the input queue. Finally, the statistics for the network device are updated, and the interrupt-handling routine either continues handling the next packet received or terminates the interrupt handling.


/usr/src/linux-2.6.19/drivers/net/isa-skeleton.c

static void net_rx(struct net_device *dev)
{
    struct net_local *lp = netdev_priv(dev);
    int ioaddr     = dev->base_addr;
    int boguscount = 10;
    do {
        int status = inw(ioaddr);
        int pkt_len = inw(ioaddr);
        if (pkt_len == 0)       /* Read all the frames? */
            break;              /* Done for now */
        if (status & 0x40) {    /* There was an error. */
            lp->stats.rx_errors++;
            if (status & 0x20) lp->stats.rx_frame_errors++;
            if (status & 0x10) lp->stats.rx_over_errors++;
            if (status & 0x08) lp->stats.rx_crc_errors++;
            if (status & 0x04) lp->stats.rx_fifo_errors++;
        } else {
            struct sk_buff *skb;
            lp->stats.rx_bytes+=pkt_len;
            skb = dev_alloc_skb(pkt_len); //(1)
            if (skb == NULL) {
                printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
                       dev->name);
                lp->stats.rx_dropped++;
                break;
            }
            skb->dev = dev;
            memcpy(skb_put(skb,pkt_len), (void*)dev->rmem_start, pkt_len);     //(2)
            insw(ioaddr, skb->data, (pkt_len + 1) >> 1);
            netif_rx(skb);
            dev->last_rx = jiffies;
            lp->stats.rx_packets++;
            lp->stats.rx_bytes += pkt_len;
        }
    } while (--boguscount);
    return;
}


(1)
------------------------------------------------------


                    +--->|----------|
                    |    |          |
     |----------|   |    |          |
     | head    -|---+    |          |
     |----------|   |    |          |
     | data   
-|---+    |          |
     |----------|   |    |          |
     | tail   
-|---+    |          |
     |----------|        |          |
     | end    
-|---+    |          |
     |----------|   |    |          |
                    |    |          |
                    |    |          |
                    |    |          |
                    +--->|----------|
                         |          | skb_shared_info
                         |          |
                         |          |
                         |----------|



                    +--->|----------|
                    |    |          |
     |----------|   |    |          | NET_SKB_PAD
     |
-head    |---+    |          |
     |----------|        |          |
     |
-data    |---+--->|----------|----------------
     |----------|   |    |          |
     |
-tail    |---+    |          |
     |----------|        |          |
     |
-end     |---+    |          |
     |----------|   |    |          |
                    |    |          |
                    |    |          |
                    |    |          |
                    +--->|----------|----------------
                         |          | skb_shared_info
                         |          |
                         |          |
                         |----------|

(2)              
------------------------------------------------------               
                    +--->|----------|
                    |    |          |
     |----------|   |    |          | NET_SKB_PAD
     |
-head    |---+    |          |
     |----------|        |          |
     |
-data    |------->|----------|----------------
     |----------|        |          |
     |
-tail    |---+    |          |
     |----------|   |    |          |
     |
-end     |---+    |          | pkt_len
     |----------|   |    |          |
                    |    |          |
                    |    |          |
                    |    |          |
                    +--->|----------|----------------
                         |          | skb_shared_info
                         |          |
                         |          |
                         |----------|



类别:net-detail||添加到搜藏 |分享到i贴吧|浏览(494)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu