首页 > 代码库 > 《TCP/IP详解卷2:实现》笔记--接口层:以太网和环回
《TCP/IP详解卷2:实现》笔记--接口层:以太网和环回
1.以太网接口
Net/3以太网设备驱动程序都遵循同样的设计。对于大多数Unix设备驱动程序来说,都是这样,因为写一个新接口卡的驱动
程序总是在一个已有的驱动程序的基础上修改而来的。下面我们简要地概述一下以太网的标准和一个以太网驱动程序的设
计。下图是一个IP分组的以太网封装。
我们所讨论的最初的以太网组帧的标准在1982年由Digital设备公司,intel公司以及施乐公司发布,并作为今天在TCP/IP网络
中最常使用的格式,另一个可选的格式是IEEE规定的802.2和802.3标准。
下图列举了以太网接口的数据结构和函数。
上图中,椭圆标识一个函数,方框标识数据结构,圆角方框标识一组函数。
1.1.leintr函数
我们从以太网帧的接收开始。现在,假设硬件已初始化并且系统已完成配置,当接口产生一个中断时,leintr被调用。在正常
操作中,一个以太网接口接收发送到它的单播地址和以太网广播地址的帧。当一个完整的帧可用时,接口就产生一个中断,
并且内核调用leintr。
leintr检测硬件,并且如果有一个帧到达,就调用leread把这个帧从接口转移到一个mbuf中(用m_devget),如果硬件报告
一个帧已传输完成或发现一个差错,则leintr跟新相应的接口统计。复位这个硬件,并调用lestart来传输另一个帧。
所有以太网设备驱动程序将他们接受到的帧传给ether_input做进一步处理。设备驱动程序构造的mbuf不包括以太网首部,
以太网首部作为一个独立的参数传递给ether_input。
以太网CRC并不总是可用。它由接口硬件来计算和检验,接口硬件丢弃到达的CRC差错帧。
1.2.leread函数
leread函数的开始是由leintr传给它的一个连续的内存缓冲区,并且构造了一个ether_header结构和一个mbuf链。这个链表
存储来自以太网帧的数据。leread还将输入帧传给BPF(Berkeley Packet Filter)。
leread有三个参数:unit,标识接收到此帧的特定接口;buf,它指向接口接收到的帧;len,它是帧的字节数。
主要处理如下:
构造ether_header
↓
判断目的地址是多播地址还是广播地址,如果是广播地址,设置M_BCAST,如果是多播地址,设置M_MCAST。这些标志位以后
会在mbuf中体现。
↓
如果接口有BPF,则将帧直接传给BPF。
↓
调用m_devget构造mbuf,并将数据帧内容复制给mbuf。
↓
调用ether_input处理这个分组。
1.3.ether_input函数
函数ether_input检查结构ether_header来判断接收到的数据类型,并将接收到的分组加入到队列中等待处理。
传给ehter_input的参数有:ifp,指向接收分组接口的ifnet结构的指针;eh,指向接收分组的以太网首部的指针;m,一个
指向接收分组的指针(不包含以太网首部)。
函数处理如下:
根据以太网类型字段跳转。对于一个IP分组,schednetisr调度一个IP软件中断,并选择输入队列,ipintrq。对于一个ARP分组,
调度ARP软件中断,并选择arpintrq。
↓
将分组放置到选择的队列中,若队列为空,则丢弃分组。
当ether_input返回时,设备驱动程序通知硬件它准备接收下一分组。
1.4.ether_output函数
下面查看以太网帧的输出。当一个网络层协议,如IP,调用此接口ifnet结构中指定的函数if_output时,开始处理输出。所有
以太网设备的if_output是ether_output,ether_output用14字节以太网首部封装一个以太网帧的数据部分,并将它放置到接口
的发送队列中。
ether_output的参数有:ifp,它指向输出接口的ifnet结构;m0,要发送的分组,dst,分组的目的地址;rt0,路由信息。
函数主要分为四个部分:
验证
特定协议处理
构造帧
接口排队
1.5. lestart函数
函数lestart从接口输出队列中取出排队的帧,并交给以太网卡发送。如果设备空闲,调用此函数开始发送帧。ether_output函数
中调用接口if_start函数调用lestart。
函数的接口如下:
将帧从输出队列中退队
↓
传输帧并传递给BPF
↓
如果设备准备好,重复发送多帧
↓
将设备标记为忙
2.ioctl系统调用
ioctl系统调用提供一个通用的命令接口,一个进程用来访问一个设备的标准系统调用所不支持的特性。ioctl原型为:
int ioctl(int fd, unsigned long com, ...);本书中所有的ioctl命令如下:
第一列显示的是符号常量标识ioctl命令(第二个参数,com)。第二列显示传递给第一列所显示的命令的系统调用的第三个
参数的类型。第三个列是实现这个命令的函数的名称。
下图显示处理ioctl命令的各种函数的组织。
2.1.ifioctl函数
函数处理如下:
对于SIOCGIFCONF,ifioctl调用ifconf来构造一个可变的ifreq结构的表。ifreq的结构如下:
↓
对于其他的ioctl命令,数据参数是指向一个ifreq结构的指针,ifunit函数在ifnet列表中查找名称为进程在ifr->ifr_name中提供的
文本名称的接口,如果没有匹配的接口,ifioctl返回ENXIO。
↓
剩下的处理依赖cmd,在下面的通用接口ioctl命令中会进行说明。
↓
如果接口ioctl命令不能被识别,ifioctl把命令发送给与所请求插口关联的协议的用户要求函数。对于IP,这些命令以一个UDP插
口发送并调用udp_usrreq。
2.2.ifconf函数
ifconf为进程提供了一个标准的方法来发现一个系统中的接口和配置的地址。
2.3.通用接口ioctl命令
剩下的四个接口命令有函数ifioctl处理。
1.SIOCGIFLAGS和SIOCGIFMETRIC
ifioctl将每个接口的if_flags(ifr_flags)或者if_metric(ifr_metric)值复制到ifreq接口。
2.SIOCSIFFLAGS
为了改变接口的标志,调用进程必须有超级用户权限。如果进程正在关闭一个运行的接口或启动一个未运行的接口,分别调用
if_down和if_up。
3.SIOCSIFMETRIC
进程需要超级用户权限,ifioctl将接口新的度量复制到if_metric中。
3.环回接口
任何发送给环回接口的分组立即排入输入队列。接口完全用软件实现。
换回接口的if_output指向的函数looutput,将输出分组放置到分组的目的地址指明协议的输入队列中。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。