注册 登录
编程论坛 Linux系统管理

网络 接受 数据包 (packet)

madfrogme 发布于 2012-08-02 00:34, 4483 次点击
ip_rcv()函数是通向network layer的入口。

当一个包被送到了ip_rcv()之后,收到的信息必须被检查,

以确保包的正确性。最主要的检查就是checksum的计算,

看它是否和header中的值相匹配。

其他检查包括packet大小是否有IP header的最小值;

这个包是不是IP version 4。

当检查做完之后,内核不会立刻处理这个包,而是允许一个 netfilter hook被唤醒,

那样packet就可以在userspace被处理了。

netfilter hook 被安插在内核代码的一些固定地方,来使得packet可以被动态的操作。

这些Hooks在网络这个子系统的不同处,并且每个都有一个label,比如

NF_IP_POST_ROUTING.

当kernel来到了hook处,一些为了这个label而被注册的程序(routine)则在 userspace被唤醒。

下一步,这些被收到的IP packet 就来到了十字路口,是被送往本地机器更高层还是被送往远程机器(remote computer)。

函数ip_route_input()负责作出选择,到底是选ip_local_deliver()函数还是ip_forward()函数


ip_rcv()函数定已在linux/net/ipv4/in_input.c中
程序代码:
370/*
 371 *      Main IP Receive routine.
 372 */
 373int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 374{
 375        struct iphdr *iph;
 376        u32 len;
 377
 378        /* When the interface is in promisc. mode, drop all the crap
 379         * that it receives, do not try to analyse it.
 380         */
 381        if (skb->pkt_type == PACKET_OTHERHOST)
 382                goto drop;
 383
 384        IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
 385
 386        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
 387                IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
 388                goto out;
 389        }
 390
 391        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 392                goto inhdr_error;
 393
 394        iph = skb->nh.iph;
 395
 396        /*
 397         *      RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
 398         *
 399         *      Is the datagram acceptable?
 400         *
 401         *      1.      Length at least the size of an ip header
 402         *      2.      Version of 4
 403         *      3.      Checksums correctly. [Speed optimisation for later, skip loopback checksums]
 404         *      4.      Doesn't have a bogus length
 405         */
 406
 407        if (iph->ihl < 5 || iph->version != 4)
 408                goto inhdr_error;
 409
 410        if (!pskb_may_pull(skb, iph->ihl*4))
 411                goto inhdr_error;
 412
 413        iph = skb->nh.iph;
 414
 415        if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
 416                goto inhdr_error;
 417
 418        len = ntohs(iph->tot_len);
 419        if (skb->len < len || len < (iph->ihl*4))
 420                goto inhdr_error;
 421
 422        /* Our transport medium may have padded the buffer out. Now we know it
 423         * is IP we can trim to the true length of the frame.
 424         * Note this now means skb->len holds ntohs(iph->tot_len).
 425         */
 426        if (pskb_trim_rcsum(skb, len)) {
 427                IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
 428                goto drop;
 429        }
 430
 431        /* Remove any debris in the socket control block */
 432        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
 433
 434        return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
 435                       ip_rcv_finish);
 436
 437inhdr_error:
 438        IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
 439drop:
 440        kfree_skb(skb);
 441out:
 442        return NET_RX_DROP;
 443}


[ 本帖最后由 madfrogme 于 2012-8-2 01:48 编辑 ]
2 回复
#2
hellovfp2012-08-02 12:53
那IP V6放在哪个目录下的呢?
#3
madfrogme2012-08-02 16:12
以下是引用hellovfp在2012-8-2 13:53:12的发言:

那IP V6放在哪个目录下的呢?

net 下面的ip6文件夹吧,是不是该直接看ipv6了?
1