cs8900网卡驱动简要解析(6)

是时候讲解数据收发的时候了。用来接收数据的函数是cs8900_receive,它在上文中出现过。那么数据如何处理的?简单的说,1)把数据放到skb中,2)执行netif_rx 函数。

skb又是什么?它是网络设备驱动中,和net_device一样重要的数据结构。skb就是sk_buff结构,也就是套接字缓冲区。它在skbuff.h中定义。有多重要呢?不描述了,干脆把代码列出来,虽然有点长,但毕竟也不是书,大家就忍了吧。反正这个结构是必须清楚的。

struct sk_buff {

/* These two members must be first. */

struct sk_buff *next;

struct sk_buff *prev;

struct sock *sk;

ktime_t tstamp;

struct net_device *dev;

struct dst_entry *dst;

struct sec_path *sp;

/*

* This is the control buffer. It is free to use for every

* layer. Please put your private variables there. If you

* want to keep them across layers you have to do a skb_clone()

* first. This is owned by whoever has the skb queued ATM.

*/

char cb[48];

unsigned int len,

data_len;

__u16 mac_len,

hdr_len;

union {

__wsum csum;

struct {

__u16 csum_start;

__u16 csum_offset;

};

};

__u32 priority;

__u8 local_df:1,

cloned:1,

ip_summed:2,

nohdr:1,

nfctinfo:3;

__u8 pkt_type:3,

fclone:2,

ipvs_property:1,

peeked:1,

nf_trace:1;

__be16 protocol;

void (*destructor)(struct sk_buff *skb);

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)

struct nf_conntrack *nfct;

struct sk_buff *nfct_reasm;

#endif

#ifdef CONFIG_BRIDGE_NETFILTER

struct nf_bridge_info *nf_bridge;

#endif

int iif;

#ifdef CONFIG_NETDEVICES_MULTIQUEUE

__u16 queue_mapping;

#endif

#ifdef CONFIG_NET_SCHED

__u16 tc_index; /* traffic control index */

#ifdef CONFIG_NET_CLS_ACT

__u16 tc_verd; /* traffic control verdict */

#endif

#endif

/* 2 byte hole */

#ifdef CONFIG_NET_DMA

dma_cookie_t dma_cookie;

#endif

#ifdef CONFIG_NETWORK_SECMARK

__u32 secmark;

#endif

__u32 mark;

sk_buff_data_t transport_header;

sk_buff_data_t network_header;

sk_buff_data_t mac_header;

/* These elements must be at the end, see alloc_skb() for details. */

sk_buff_data_t tail;

sk_buff_data_t end;

unsigned char *head,

*data;

unsigned int truesize;

atomic_t users;

};

也许你看到这个庞大的结构(实际上它并不是很庞大)有些晕!但是更令人晕的是内核把sk_buff组织成一个双向链表。而且这个链表的结构要比常见的双向链表的结构还要复杂。sk_buff中用两个指针(nextprev)表示前后一个节点。这个链表还有另一个需求:每个sk_buff结构都必须能够很快找到链表头节点。为了满足这个需求,在第一个节点前面会插入另一个结构sk_buff_head,这是一个辅助节点。在Linux内核世界中,图示永远比代码好理解,所以你要善于看图说话。

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="图片_x0020_1" style="VISIBILITY: visible; WIDTH: 308.25pt; HEIGHT: 219.75pt; mso-wrap-style: square" alt="sk_buff_001.jpg" type="#_x0000_t75" o:spid="_x0000_i1025"><imagedata o:title="sk_buff_001" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image001.jpg"></imagedata></shape>

本来我很想多介绍一下skb,但是又怕那将令大家再一次陷入内核的迷雾,所以还是见好就收吧。你现在知道,网卡传输数据离不开skb,因此我们需要填充这个skb。当skb搞定后,只要下面一句就可以:

netif_rx (skb);

它把skb扔到了上层。netif_rx函数原型在net\core\dev.c中,它有两个返回值:

NET_RX_SUCCESS (no congestion)

NET_RX_DROP (packet was dropped)

一句话总结:网卡的数据接收是通过netif_rx完成的,而传递给netif_rx的是一个包含数据的socket buffer

你可能感兴趣的:(数据结构,.net,linux,F#,ext)