Linux设备驱动工程师之路——网络设备驱动基本原理和框架
1.Linux网络子系统
Linux网络子系统的顶部是系统调用接口层。它为用户空间提供的应用程序提供了一种访问内核网络子系统的方法(socket)。位于其下面是一个协议无关层,它提供一种通用的方法来使用传输层协议。然后是具体协议的实现,在Linux中包括内核的协议TCP,UDP,当然还有IP。然后是设备无关层,它提供了协议与设备驱动通信的通用接口,最下面是设备的驱动程序。
设备无关接口将协议与各种网络驱动连接在一起,这一层提供一组通用函数供底层网络设备驱动使用,让它们可以对高层协议栈进行操作。需要从协议层向设备发生数据,需要调用dev_queue_xmit函数,这个函数对数据进行列队,然后交由底层驱动程序的hard_start_xmit方法最终完成传输。接收通常是使用netif_rx执行的。当底层设备程序接收到一个报文(发生中断)时,就会调用netif_rx将数据上传至设备无关层。
下图为设备无关层到驱动层的体系结构
2.网络设备描述(structnet_device)
每一个网络设备都由struct net_device来描述,该结构可使用如下内核函数进行动态分配
struct net_device *alloc_net(intsizeof_priv, const char *mask, void(*setup)(struct net_deive *))
sizeof_priv是私有数据区大小;mask是设备名,setup是初始化函数,在注册该设备时,该函数被调用。也就是net_deivce的init成员。
struct net_device *alloc_etherdev(intsizeof_priv)
这个函数和上面的函数不同之处在于内核知道会将该设备做一个以太网设备看待并做一些相关的初始化。
net_device结构可分为全局成员、硬件相关成员、接口相关成员、设备方法成员和公用成员等五个部分
主要全局成员
char name[INFAMSIZ]
设备名,如:eh%d
unsigned long state
设备状态
unsigned long base_addr
I/O基地址
unsigned int irq
中断号
主要设备方法有
int (*init)(struct net_device *dev)
初始化函数,该函数在register_netdev时被调用来完成对net_device结构的初始化
int (*open)(struct net_device *dev)
打开接口。ifconfig激活时,接口将被打开
int (*stop)(struct net_deivce *dev)
停止接口,ifconfig eth% down时调用
int (*hard_start_xmit)(struct sk_buf*skb,struct net_device *dev)
数据发送函数
int (*do_ioctl)(struct net_deive *dev,struct ifreq *ifr, int cmd)
处理特定于接口的ioctl命令(sock_ioctl)进行调用。
int (*set_mac_address)(struct net_device*dev, void *addr)
改变MAC地址的函数,需要硬件支持该功能。
网络设备的注册
网络设备注册方式与字符驱动不同之处在于它没有主次设备号,并使用下面的函数注册
int register_netdev(struct net_deivce*dev)
网络设备的注销
void unregister_netdev(struct net_device*dev)