一般的,驱动程序将其设备的一个内存区域(例如,其配置寄存器)映射到系统内存,使得驱动程序的读写操作可以通过系统内存地址直接进行,这样可以简化代码。I/O端口和内存分别使用request_region和release_region注册机释放。
查询:
最常见的查询都是通过设备名称或设备ID进行,在net_device结构的组织中的全局列表和hash表中进行查找。这两种查询的实现是由dev_get_by_name和dev_get_by_index负责。也有可能根据设备类型和MAC地址搜寻net_device实力。这种查询用的是dev_base列表。至于传输数据时采用哪个网卡设备(net_device)是由用户层设置的
设备注册:
设备注册不是简单的把net_device结构插入到”net_device结构的组织“一节所介绍的全局列表和hash表就行了,设备注册还涉及net_device结构中一些参数的初始化、产生广播通知信息以通知其他内核组件有关此次注册,以及其他任务。
开启和关闭网络设备:
设备一旦注册就可用了,但是,除非由用户(或用户应用程序)明确的开启,否则还是无法传输和接受数据流。开启设备的请求由定义在net/core/dev.c中的dev_open负责。
开启设备之时,由下列任务要做:
(1、如果有定义的话,调用dev->open。并非所有设备去弄程序都初始化此函数。
(2、设置dev->state中的__LINK_STATE_START标识,把设备表示未开启和运行中。
(3、设置dev->flags中的IFF_UP标识,把设备标志位开启
(4、调用dev_activate
(5、传送NETDEV_UP通知信息给netdev_chain
负责接收帧的代码分成两部分:首先驱动程序把该帧拷贝到内核可访问的输入队列,然后内核再予以处理,通常是把那个帧传给一个相关协议(如IP)专用的处理函数。第一部分会在中断环境中执行。
处理Ethernet层的帧的函数是由中断事件驱动的,中断处理函数会执行一些立即性的任务,然后把其他任务安排到下半部函数中以便在稍后执行。明确的讲,中断处理函数会:
1、把帧拷贝到sk_buff数据结构体,并调用netif_rx(skb)通知内核帧已经接受。
skb = dev_alloc_skb(pkt_len+5);//分配sk_buff结构体
。。。 。。。 。。。
if (skb != NULL){
skb ->dev = dev;
skb_reaserve(skb,2);
。。。 。。。 。。。
/*把DATA拷贝到sk_buff结构中*/
。。。 。。。 。。。
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb); //通知内核已经接受帧
。。。 。。。 。。。
}
netif_rx后面解释
2、对一些sk_buff参数做初始化,以便在稍后由上面的网络层使用
3、更新其他一些该设备私用的参数
netif_rx的主要任务如下:
1、对sk_buff数据结构的一些字段做初始化
2、把已经接受的帧存储到存储到CPU的私有输入队列,然后触发相关联的软IRQ NET_RX_SOFTIRQ以通知内核
3、更新有关拥塞等级的统计数据
处理软中断NET_RX_SOFTIRQ的函数是net_rx_action
该函数的工作是浏览poll_list(存储net_device的设备列表)设备列表,而这些设备的入口队列中都有数据,然后为每个设备启用相关联的poll虚拟函数。
所有的poll虚拟函数都会用到netif_receive_skb(skb)这个函数,该函数是处理帧的函数。该函数的三个主要任务是:
1、把帧的副本传给每个协议分流器,如果正在运行的话。
2、把帧的副本传给skb->protocol所关联的L3(IP层)协议处理函数。(会检查skb->protocol字段的值,根据该值调用相对应的函数。例如:如果该字段是ETH_P_802_3,则指定ipx_rcv来处理这个帧)
3、负责此层必须处理的一些功能,例如桥接
下一步帧就交给与skb->protocol协议关联的处理函数了,通常每种协议只有一个处理函数,但是也可以注册多个。
此时,接收部分已经完成,下一步就是L3协议处理函数决定要对封包如何处理:
1、传给接收工作站中正在执行的接受者(应用程序)
2、丢弃
3、转发
内核可从L3的目的地地址确定该封包是否是传给其本地系统。如果封包要给本地系统,封包就会传递到上层去(即TCP,UDP,ICMP等)
以上就结束了帧接受过程
协议函数的注册:
为每个协议注册时,内核会对packet_type结构做初始化,然后调用dev_add_pack。下面是取自net/ipv4.ip_out/put.c的范例,显示出IPv4关键代码如何注册IPv4协议处理函数。
当IPv4协议在引导其间初始化时,ip_init函数会被执行。其中一种结果是packet_type结构中的函数ip_rcv会注册成此协议的函数处理函数,。所有Ethernet帧接收时,若ETH_P_IP的值为Protocol Above,就会由函数ip_rcv处理。
static struct packet_type ip_packet_type =
{
.type = constant_htons(ETH_P_IP);
.func = ip_rcv;
}
void __init ip_init(void)
{
dev_add_pack(&ip_packet_type);
......
}