Chinaunix首页 | 论坛 | 博客

分类: LINUX

2014-03-29 21:57:47

/*
 *         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) |
给主人留下些什么吧!~~