Chinaunix首页 | 论坛 | 博客
  • 博客访问: 378696
  • 博文数量: 56
  • 博客积分: 1449
  • 博客等级: 中尉
  • 技术积分: 822
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-08 10:24
文章分类

全部博文(56)

文章存档

2014年(7)

2012年(13)

2011年(10)

2010年(26)

分类: LINUX

2012-05-21 20:00:13


点击(此处)折叠或打开

  1. /* 主要功能:对IP头部合法性进行严格检查,然后把具体功能交给ip_rcv_finish。*/
  2. int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
  3. {
  4.     struct iphdr *iph;
  5.     u32 len;
  6.     /* 网络名字空间,忽略 */
  7.     if (dev->nd_net != &init_net)
  8.         goto drop;
  9.     /*
  10.      *当网卡处于混杂模式时,收到不是发往该主机的数据包,由net_rx_action()设置。
  11.      *在调用ip_rcv之前,内核会将该数据包交给嗅探器,所以该函数仅丢弃该包。
  12.      */
  13.     if (skb->pkt_type == PACKET_OTHERHOST)
  14.         goto drop;
  15.     /* SNMP所需要的统计数据,忽略 */
  16.     IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);

  17.     /*
  18.      *ip_rcv是由netif_receive_skb函数调用,如果嗅探器或者其他的用户对数据包需要进
  19.      *进行处理,则在调用ip_rcv之前,netif_receive_skb会增加skb的引用计数,既该引
  20.      *用计数会大于1。若如此次,则skb_share_check会创建sk_buff的一份拷贝。
  21.      */
  22.     if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
  23.         IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
  24.         goto out;
  25.     }
  26.     /*
  27.      *pskb_may_pull确保skb->data指向的内存包含的数据至少为IP头部大小,由于每个
  28.      *IP数据包包括IP分片必须包含一个完整的IP头部。如果小于IP头部大小,则缺失
  29.      *的部分将从数据分片中拷贝。这些分片保存在skb_shinfo(skb)->frags[]中。
  30.      */
  31.     if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  32.         goto inhdr_error;
  33.     /* pskb_may_pull可能会调整skb中的指针,所以需要重新定义IP头部*/
  34.     iph = ip_hdr(skb);

  35.     /*
  36.      *    RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
  37.      *
  38.      *    Is the datagram acceptable?
  39.      *
  40.      *    1.    Length at least the size of an ip header
  41.      *    2.    Version of 4
  42.      *    3.    Checksums correctly. [Speed optimisation for later, skip loopback checksums]
  43.      *    4.    Doesn't have a bogus length
  44.      */
  45.     /* 上面说的很清楚了 */
  46.     if (iph->ihl < 5 || iph->version != 4)
  47.         goto inhdr_error;
  48.     /* 确保IP完整的头部包括选项在内存中 */
  49.     if (!pskb_may_pull(skb, iph->ihl*4))
  50.         goto inhdr_error;
  51.     
  52.     iph = ip_hdr(skb);
  53.     /* 验证IP头部的校验和 */
  54.     if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
  55.         goto inhdr_error;
  56.     /* IP头部中指示的IP数据包总长度 */
  57.     len = ntohs(iph->tot_len);
  58.     /*
  59.      *确保skb的数据长度大于等于IP头部中指示的IP数据包总长度及数据包总长度必须
  60.      *大于等于IP头部长度。
  61.      */
  62.     if (skb->len < len) {
  63.         IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
  64.         goto drop;
  65.     } else if (len < (iph->ihl*4))
  66.         goto inhdr_error;

  67.     /* Our transport medium may have padded the buffer out. Now we know it
  68.      * is IP we can trim to the true length of the frame.
  69.      * Note this now means skb->len holds ntohs(iph->tot_len).
  70.      */
  71.     /* 注释说明的很清楚,该函数成功执行完之后,skb->len = ntohs(iph->tot_len). */
  72.     if (pskb_trim_rcsum(skb, len)) {
  73.         IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
  74.         goto drop;
  75.     }

  76.     /* Remove any debris in the socket control block */
  77.     memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
  78.     /* 忽略与netfilter子系统的交互,调用为ip_rcv_finish(skb) */
  79.     return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
  80.          ip_rcv_finish);

  81. inhdr_error:
  82.     IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
  83. drop:
  84.     kfree_skb(skb);
  85. out:
  86.     return NET_RX_DROP;
  87. }

阅读(7300) | 评论(0) | 转发(6) |
给主人留下些什么吧!~~