大家好,我是极客范的本期栏目编辑小友,现在为大家讲解Linux网络设备驱动程序问题。
Linux网络设备驱动架构
-
|数据包发送|数据包接收|-网络协议接口层
| dev_queue_xmit() | netif_rx() |
| -
|结构net_device | -网络设备的接口层
-
|数据包发送|中断处理|-网络驱动功能层
| hard_start_xmit() |数据包接收|
| -
|网络设备媒体(物理层)|-网络设备和媒体层
-
硬件相关驱动程序(提供硬启动xmit,并使用neTIf_rx报告数据)
5.sk_buff socket buffer,用于linux中各层之间的数据传输。当发送数据包时,内核必须创建一个包含传输数据的sk_buff,然后将sk_buff交给下层,每层将它交给sk_buff中的下一层,每层将在sk_buff中添加不同的协议头,直到它被发送到网络设备。接收原理是一样的。
struct sk_buff {
struct sk _ buff * next
struct sk _ buff * prev
struct net _ device * dev
.
char CB[48];
无符号整数,//数据的真实长度
Data_len,//数据长度
mac _ len//链路层帧头的长度
void(*析构函数)(struct sk _ buff * skb);
sk _ buff _ data _ t transport _ header;
sk _ buff _ data _ t network _ header
sk _ buff _ data _ t mac _ header
sk _ buff _ data _ t tail
sk_buff_data_t结束;
无符号字符*head,
*数据;
无符号int truesize
atomic_t用户;
};
5.1.sk_buff结构:
---*头
|头|
|---*数据
|数据|
|缓存|
|---*尾巴
|尾巴|
---*结束
5.2.分布:
分配套接字缓冲区:用GFP_ATOMIC优先级分配skb,因为这个函数经常在设备驱动中调用。
staTIc inline struct sk _ buff * dev _ alloc _ skb(无符号整数长度)
分配一个套接字缓冲区和一个数据缓冲区,参数len是数据缓冲区的大小,ARM通常对齐32位,参数优先级是内存分配的优先级。
staTIc inline struct sk _ buff * alloc _ skb(无符号整数大小,gfp_t优先级)
5.3.发布:
//用于为非中断上下文释放dev_alloc_skb的内存。
void dev _ kfree _ skb(struct sk _ buff * skb)
//用于中断上下文
staTIc inline void dev _ kfree _ skb _ IRQ(struct sk _
buff *skb) //中断和非中断都可以用 any,其实就是做了一个判断void dev_kfree_skb_any(struct sk_buff *skb) { if (in_irq() || irqs_disabled()) dev_kfree_skb_irq(skb); else dev_kfree_skb(skb); }5.4、变更: 缓冲区尾部增加数据 skb static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) skb->tail += len; skb->len += len;缓冲区开头增加数据static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) skb->data -= len; skb->len += len;
缓冲区开头移除数据static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) skb->len -= len; return skb->data += len;
调节缓冲区头部static inline void skb_reserve(struct sk_buff *skb, int len) skb->data += len; skb->tail += len;
6.net_device结构体struct net_device { char name[IFNAMSIZ];
unsigned long mem_end; unsigned long mem_start; unsigned long base_addr; unsigned int irq;
unsigned char if_port; unsigned char dma; /* DMA channel
int (*init)(struct net_device *dev);
struct net_device_stats* (*get_stats)(struct net_device *dev); struct net_device_stats stats;
....................... unsigned mtu; unsigned short type; unsigned short hard_header_len;
unsigned char dev_addr[MAX_ADDR_LEN];
void *priv;
int (*hard_start_xmit) (struct sk_buff *skb,struct net_device *dev);
unsigned long trans_start;
unsigned long last_rx;
int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev);
int (*set_mac_address)(struct net_device *dev,void *addr);
int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); int (*set_config)(struct net_device *dev,struct ifmap *map);
void (*tx_timeout) (struct net_device *dev);
struct net_device_ops { ..... }; };