/*
* Deliver IP Packets to the higher protocol layers.
*/
int ip_local_deliver(struct sk_buff *skb)
{
/*
* Reassemble IP fragments.
* IP报头:flag字段占3bit,片偏移占13bit. 其中flag最低位是MF.
* 考虑三种情况:1、未分段,2、第一个分段,3、中间的分段,4、最后一个分段.
*/
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { //判断是否是IP报文的分段.
/*http://cxw06023273.iteye.com/blog/866892 介绍了具体的重组过程.*/
if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)) //当所有分片到达,并重组以后. 该函数应该是返回0.这样才能执行下面的HOOK函数.
return 0; //该返回值最终会作为ip_rcv的返回值,所以返回0以后.代表处理该SKB结束.
}
return NF_HOOK(PF_INET, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
ip_local_deliver_finish);
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
调用此函数之前,包已经重组OK了.
http://blog.chinaunix.net/uid-22577711-id-3218536.html
*/
static int ip_local_deliver_finish(struct sk_buff *skb)
{
struct net *net = dev_net(skb->dev);
__skb_pull(skb, ip_hdrlen(skb)); //跳过IP报头.
/* Point into the IP datagram, just past the header. */
skb_reset_transport_header(skb); //设置sk_buff结构中transport_header字段,设置传输层头部位置.
rcu_read_lock();
{
int protocol = ip_hdr(skb)->protocol; //L4层的协议类型.
int hash, raw;
struct net_protocol *ipprot;
resubmit:
raw = raw_local_deliver(skb, protocol); /*该函数会将所有protocol类型的数据包上报给原始套接字*/
hash = protocol & (MAX_INET_PROTOS - 1);
ipprot = rcu_dereference(inet_protos[hash]); /*L4层入口函数都注册在inet_protos结构数组中,就像ip_rcv是IP层的入口函数一样,也是注册过的*/
if (ipprot != NULL) {
int ret;
if (!net_eq(net, &init_net) && !ipprot->netns_ok) { /*是一个大体系*/
if (net_ratelimit())
printk("%s: proto %d isn't netns-ready\n",
__func__, protocol);
kfree_skb(skb);
goto out;
}
if (!ipprot->no_policy) { /*启用了安全策略,则交给IPSec*/
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
kfree_skb(skb);
goto out;
}
nf_reset(skb);
}
ret = ipprot->handler(skb); /*调用L4层的协议处理函数.通常会是tcp_v4_rcv, udp_rcv, icmp_rcv和igmp_rcv*/
if (ret < 0) {
protocol = -ret;
goto resubmit; /* 看来L4层协议之间还可以做接力啊!*/
}
IP_INC_STATS_BH(net, IPSTATS_MIB_INDELIVERS);
} else {
if (!raw) { /* 无原始套接字,提交给IPSec */
if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
IP_INC_STATS_BH(net, IPSTATS_MIB_INUNKNOWNPROTOS);
icmp_send(skb, ICMP_DEST_UNREACH,
ICMP_PROT_UNREACH, 0);
}
} else
IP_INC_STATS_BH(net, IPSTATS_MIB_INDELIVERS);
kfree_skb(skb);
}
}
out:
rcu_read_unlock();
return 0;
}
阅读(2519) | 评论(0) | 转发(0) |