linux系统对网络设备驱动定义了4个层:
(1)网络协议接口层
网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接受数据。这一层的存在使得上层协议独立于具体的设备
(2)网络设备接口层
网络设备接口层向协议接口层提供统一的用于描述具体网络设备属性和操作的结构体net_device,该结构体是设备驱动功能层中各函数的容器。实际上,网络设备接口层从宏观上规划具体操作硬件的设备驱动功能层的结构。
(3)提供实际功能的设备驱动功能层
设备驱动功能层各函数是网络设备接口层net_device数据结构的具体成员,是驱使网络设备硬件完成相应动作的程序,它通过hard_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接收操作。
(4)网络设备与媒介层
网络设备与媒介层是完成数据包发送和接收的物理实体,包括网络适配器和具体的传输媒介,网络适配器被设备驱动功能层中的函数物理上驱动。对于linux系统而言,网络设备和媒介都可以是虚拟的。
套接字缓冲区成员的主要成员:
(1)各层协议头h、nh、和mac
3个协议头对应网络协议的不同层次,分别为传输层TCP/UDP(及ICMP和IGMP)协议头h、网络协议头nh和链路层协议头mac。这三个协议头数据结构都被定义为联合体
union{
struct tcphdr *th; /*TCP头部*/
struct udphdr *uh; /*UDP头部*/
struct icmphdr *icmph; /*ICMP头部*/
struct igmphdr *icmph; /*IGMP头部*/
struct iphdr *iph; /*IP头部*/
struct ipv6hdr *ipv6h; /*IPv6头部*/
unsigned char *raw; /*数据链路层头部*/
}h;
union{
struct iphdr *iph; /*IP头部*/
struct ipv6hdr *ipv6h; /*IPv6头部*/
struct arphdr *arph; /*ARP6头部*/
unsigned char *raw ; /*数据链路层头部*/
}nh;
union{
unsigned char *raw; /*数据链路层头部*/
}mac;
(2)数据缓冲区指针head、data、tail和end。
linux 内核必须分配用于容纳数据包的缓冲区,sk_buff结构体定义了4个指向这片缓冲区不同位置的指针head、data、tail和end。
head指针指向内存中已分配的用于承载网络数据的缓冲区的起始地址,sk_buff和相关数据块在分配之后,该指针的值被固定了。
data指针指向对应当前协议层有效数据的起始地址。每个协议层的有效数据含义并不相同。
各层的有效数据信息包含的内容如下
对于传输层,用户数据和传输层协议头属于有效数据。
对于网络层,用户数据、传输层协议头和网络层协议头式其有效数据。
对于数据链路层,用户数据,传输层协议头,网络层协议头和链路层头部都属于有效数据。
tail指针指向对应当前协议层有效数据负载的结尾地址。
end指针指向内存中分配的数据缓冲区的结尾,与head指针对应。和head指针一样,sk_buff被分配之后,end指针的值也就固定不变了。
网络设备的初始化主要完成如下几个方面的工作:
(1)进行硬件上的准备工作,检查网络设备是否存在,如果存在,则检测设备所使用的硬件资源。
(2)进行软件接口上的准备工作,分配net_device结构体并对其数据和函数指针成员赋值。
(3)获得设备的私有信息指针并初始化其各成员的值。如果私有信息中包括自旋锁或信号量等并发或同步机制,则需对其进行初始化。
网络设备的打开函数需要完成如下工作
(1)使能设备使用的硬件资源,申请I/O区域、中断和DMA通道等。
(2)调用linux内核提供的netif_start_queue()函数,激活设备发送队列。
网络设备的关闭函数需要完成如下工作
(1)调用linux内核提供的netif_stop_queue()函数,停止设备传输包。
(2)释放设备所使用的I/O区域、中断和DMA资源。
网络设备驱动完成数据包发送的流程如下
(1)网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。
(2)对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度ETH_ZLEN,则给临时缓冲区的末尾填充0.
(3)设置硬件的寄存器,驱使网络设备进行数据发送操作。
网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buff数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buff传递给上层协议。
阅读(992) | 评论(0) | 转发(0) |