接下来看一下sk_buff是如何被递交到上层协议进行处理的,只是通过调用netif_receive_skb(在net/core/dev.c中定义)函数实现的:
int netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
int ret = NET_RX_DROP;
unsigned short type = skb->protocol;
/*
给每个网络数据包打上时间戳。
*/
if (skb->stamp.tv_sec == 0)
do_gettimeofday(&skb->stamp);
skb_bond(skb);
pt_prev = NULL;
/*
上层的每个协议在其初始化的过程中会调用dev_add_pack函数将自己的packet_type结构加入到ptye_all列表当中,其中 packet_type结构中定义了该协议的处理方法,对于ip协议来说,func方法就注册为ip_rcv。另外,一般协议packet_type结构 的dev字段设为NULL,所以下面的ptype->dev就为NULL。
另外,如果我们需要增加自己的协议,则需要创建一个packet_type结构,用我们自己的协议处理函数填充该结构的func方法,并且调用dev_add_pack函数将我们自己的协议加入ptype_all数组当中。
*/
for (ptype = ptype_all; ptype; ptype = ptype->next) {
/*
这里每一种协议在定义其packet_type结构时都设置接收这种
数据包协议类型的设备指针,如果设置为NULL,则可以从
任何设备接收数据包。
这里针对协议类型为ETH_P_ALL的情况进行处理,对于IP
协议来说,类型定义为ETH_P_IP,因此不在这里处理。
*/
if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev) {
if (!pt_prev->data) {
ret = deliver_to_old_ones(pt_prev, skb, 0);
} else {
atomic_inc(&skb->users);
ret = pt_prev->func(skb, skb->dev, pt_prev);
}
}
pt_prev = ptype;
}
}
/*
这里针对各种协议进行处理,IP包的类型为ETH_P_IP,因此在这里处理。
*/
for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
if (ptype->type == type &&
(!ptype->dev || ptype->dev == skb->dev)) {
if (pt_prev) {
if (!pt_prev->data) {
ret = deliver_to_old_ones(pt_prev, skb, 0);
} else {
atomic_inc(&skb->users);
ret = pt_prev->func(skb, skb->dev, pt_prev);
}
}
pt_prev = ptype;
}
}
if (pt_prev) {
if (!pt_prev->data) {
ret = deliver_to_old_ones(pt_prev, skb, 1);
} else {
ret = pt_prev->func(skb, skb->dev, pt_prev);
}
} else {
kfree_skb(skb);
/* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-)
*/
ret = NET_RX_DROP;
}