分类: LINUX
2015-03-01 13:43:58
原文地址:网卡与Linux网络驱动 作者:mandagod
常见网卡
PCI接口网卡
PCMCIA接口卡
USB接口卡
以太网MAC层帧格式
数据段 |
PR |
SD |
DA |
SA |
TYPE |
DATA |
PAD |
FCS |
长度 |
56位 |
8位 |
48位 |
48位 |
16位 |
<<1500字节 |
可选 |
32位 |
PR-----同步位。56位的二进制数101010101010...用于接收双方的时钟同步,同时也指明了传输速率,10Mb/s 和100Mb/s网卡的时钟速率不一样,所以100Mb/s网卡也兼容10Mb/s网卡。
SD-----分隔位。分隔同步时钟和后面的数据,为8位的10101011。与同步位不同的是,最后2位11而不是10。
DA-----目的地址。以太网的地址为48位(6字节)地址,它表明该帧传输给哪个网卡。如果为0xFFFFFFFFFFFF,则是广播地址,广播地址的数据可被局域网中所有网卡接收。
SA-----源地址。48位,表明该帧是从哪个网卡发出的。
TYPE----类型字段,表明该帧是什么类型的数据,不同协议的类型字段不同。如:0x0800数据为IP包,0x0806表示为ARP包(小于0x0600的值是用于IEEE802的,表示数据长包的长度)。
DATA----数据段,该数据段不能超过1500字节。因为以太网规定整个传输包的最大长度不能超过1514字节(14字节为DA、SA、TYPE)。
PAD----填充位。由于以太网传输的数据包最小不能小于60字节,除去(DA、SA、TYPE共14字节)外,还必须传输46字节的数据;当数据段的数据不足46字节时,后面补00000...(也可以补其他值)。
FCS----32位数据CRC校验。通常该校验由网卡自动计算,自动生成,自动校验,自动在数据后面填充。
通常在网卡的使用过程中,DA、SA、TYPE、FCS这四个数据段是由网卡自动产生的,不需要关心。DA、SA、TYPE、FCS这4个段的内容才是需要填充的数据。
所有数据位的传输由低位开始(传输的位流用曼彻斯特编码);
以太网的冲突退避算法由硬件自动执行的。
以太网数据包DA、SA、TYPE、FCS总共最小为60字节,最大为1514字节。
以太网卡可接收3种地址的数据,即广播地址、多播地址和自己的地址。但网卡也可以接收任何数据包,这主要在分析网络和监控中使用。
任何两个网卡的物理地址都不相同,它是唯一的。网卡地址由专门的机构分配。根据网卡的段地址(前3字节),可以知道网卡的生产厂家。而网卡的物理地址只是用来区分同一个局域网内部的网卡,所以,实际应用中只需要保证局域网内部没有重复物理地址的网络设备,网络就可以很好地工作。
TCP/IP网络协议栈和常用的网络通信协议
应用层Application |
FTP、HHTP、BSD套接字 |
传输层Trnsport |
TCP、UDP |
网络层Network |
IP、ARP、ICMP、IGMP.... |
数据链路层Data Link |
IEEE802.3(以太网MAC层).... |
物理层Physical |
--- |
(1)ARP
ARP(Address Resolution Protocaol,地址解析协议)的功能实现从IP地址到对应物理地址的转换。网络层用32位的IP地址来标识不同的主机,在MAC曾用48位的MAC地址来标识不同的以太网口。只要知道目的主机的IP地址并不能发送数据帧给它,必须知道目的主机网络接口的MAC地址才能发送数据帧。其工作流程可以总结为:源主机发送一份包含目的主机IP地址的ARP请求数据帧给网上的每个主机(称作ARP广播),目的主机IP收到ARP请求以后,识别出发送端在询问它的IP地址,于是发送一个包含目的主机IP地址及对应的MAC地址的ARP应答给源主机。每台主机上有一个ARP缓存,存放最近的IP地址到硬件地址之间的映射记录。通常每一项生存为20min。
在linux下arp查看缓存:
ryan@ryan-laptop:~$ arp
地址 类型 硬件地址 标志 Mask 接口
192.168.1.1 ether 00:1d:0f:63:50:0e C eth0
(2)ICMP
ICMP(Internet Control Messages Protocol,网络控制报文协议)被封装于IP层数据包中,是IP层的附属协议。IP层用来与其他主机或路由器发送交换错误报文和其他重要控制信息。两个网络的诊断工具ping和traceroute就是用该协议来工作的。
(3)IP
IP(Internet Protocol,网际协议)工作在网络层,是TCP/IP协议族中最为核心的协议。所有的TCP、UDP、ICMP以及IGMP数据都以IP数据报格式传输。IP数据报最长可以达到65535字节,其中抱头占20字节,包含32位的源IP地址和目的地址。有时在嵌入式中为了简化设计,节约资源,没有必要支持大的IP数据包,可以让IP数据报等于数据链路层中的数据长度,可以使得多数IP层以上的协议工作得很好。
(4)TCP
TCP(Transfer Control Protocol,传输控制协议)为两台主机提供基于连接的高可靠性端到端的数据通信。
发送方把应用程序交给它的数据分成合适的小块并附加信息(TCP头),包括顺序号、源、目的端口、控制、纠错信息等字段,称为TCP 数据报,并将TCP数据报交给下面的网络层处理。
接收方确认收到的TCP数据报,并重组将数据报送往高层。
(5)UDP
UDP(User Datagram Protocol,用户数据报协议)是一种无连接、不可靠的传输层协议。实现过程较简单,把应用程序传来的数据加上UDP头(包括端口号、段长等字段)作为UDP数据报发送出去,但并不保证他们能达到目的地。数据传输的可靠性由应用层来提供。
(6)TFTP
TFTP(Trivial File Transfer Protocol,简单文件传输协议)基于UDP协议而实现。此协议设计时是进行小文件传送的, 因此它不具备通常的FTP的许多功能,而只能从文件服务器上获得或写入文件,没有目录的概念,不能进行认证和权限管理。
嵌入式处理器上扩展以太网接口
以太网接口控制器主要包括MAC和PHY两部分,其中MAC控制器作为逻辑控制比较容集成在处理器内部。很多针对网络控制应用的嵌入式处理器都集成了MAC层控制器。MAC控制器和PHY的连接是通过MII(Media Independent Interface,媒体独立接口)、RMII(Reduced MII,精简MII)等接口实现的。在IEEE802协议标准系列中,数据链路层包括LLC(Logical Link Control,逻辑链路控制)和MAC两个子层。其中MAC负责完成数据帧的封装、解封、发送和接收功能。物理层PHY的结构随着传输速率的不同而有一定差异。MII是连接数据链路层和物理层的接口。根据协议,要求MII接口具有的功能提供应的管理信号以及支持全双工模式。
以太网PHY芯片输出的就是传输所需的差分信号。需要一个网络隔离变压器,网络隔离变压器可以起到抑制共模干扰、隔离线路以及阻抗匹配等作用。
常见的Host Bus接口的以太网芯片有:RTL8019、CS8900、DM9000、AX88796、 LAN91C111。
多数以太网芯片都可以通过一片串行的EEPROM进行配置,主要包括:网卡的工走模式、总线的地址、中断和以太网的MAC地址信息。可以结节省这个存储器,通过以太网驱动程序来配置以太网芯片。
Linux网络设备驱动程序结构
移植编写网络硬件的驱动程序最主要的工作就是完成设备驱动功能层,主要包括数据的接收、发送等控制。
net_device结构的定义在include/linux/netdevice.h,重要的域有:name接口名称; dev_addr链路层地址,也是MAC地址;priv私有数据指针, init()初始化函数; open();stop();hard_start_xmit ()发送数据函数。
p { margin-bottom: 0.21cm; }
模块初始化函数。注册(registerne_netdev)网络设备的net_device变量。register_netdev(struct net_device *dev)把dev加入到dev_base链表中,dev_base为链表的头指针,管理所有的网络设备,链表中的每个元素代表一个网络设备接口。
模块撤销函数。注销(unregister_netdev)网络设备的net_device变量。把dev从dev_base链表中移除。
声明net_device变量,并实现如下函数:
实现init函数,完成设备的初始化和net_device变量自身的初始化。
实现打开(open)设备和关闭(close)设备。
实现发送函数(hard_start_xmit)。
实现中断处理函数,处理中断。
实现数据接收函数。
实现其他函数get_status, do_ioctl等。
(1)网络设备的内核加载
可以通过内核加载和模块加载。系统内核有专门的加载网络设备,不依靠module_init。 driver/net/dev.c中的static int __init net_dev_init(void)初始化网络设备。
(2)网络设备的初始化
内核启动者加载网络驱动模块的时候完成注册(register_netdev)网络设备的工作
net_device的init()函数完成初始化工作:
检测网络物理设备是否存在 ,检测物理设备的硬件特性来完成,然后对设备进行资源配置。
初始化net_device数据结构,如MAC地址。
配置完硬件占用的资源以后,向系统申请这些资源,如中断、I/O空间、DMA等。
open()函数初始化:
初始化硬设备,准备发送数据。
注册中断处理函数(可以在net_device的init函数中注册)。
启动接口的传输队列。netif_start_queue(ndev)启动该队列。
(3)网络数据包的发送和接收
调用 hard_start_xmit方法将数据放入外发队列。内核处理后的每个数据包位于一个套接字缓冲区结构(struct sk_buff)里。这个缓冲区包含物理数据包,并拥有完整的传输层数据包头。接口无须修改传输的数据。hard_start_xmit函数的层离过程:
得到要发送的数据的起始地址和长度。skb->data指向要传输的数据包,而skb->len是以字节为单位的长度。
把数据发送到网卡的物理缓冲区中。可以直接写把数据写入缓冲区寄存器中;或者通过DMA的方式发送数据。
网卡把得到的数据发送到物理媒介中去,这是由网卡自动完成的。
设备接收到数据产生一个中断,在中断处理程序中驱动程序申请一块sk_buff,从硬件里把数据读出放到缓冲区中,调用netif_rx函数把缓冲区的数据交到上一层。