- /* 主要功能:对IP头部合法性进行严格检查,然后把具体功能交给ip_rcv_finish。*/
- int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
- {
- struct iphdr *iph;
- u32 len;
- /* 网络名字空间,忽略 */
- if (dev->nd_net != &init_net)
- goto drop;
- /*
- *当网卡处于混杂模式时,收到不是发往该主机的数据包,由net_rx_action()设置。
- *在调用ip_rcv之前,内核会将该数据包交给嗅探器,所以该函数仅丢弃该包。
- */
- if (skb->pkt_type == PACKET_OTHERHOST)
- goto drop;
- /* SNMP所需要的统计数据,忽略 */
- IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
- /*
- *ip_rcv是由netif_receive_skb函数调用,如果嗅探器或者其他的用户对数据包需要进
- *进行处理,则在调用ip_rcv之前,netif_receive_skb会增加skb的引用计数,既该引
- *用计数会大于1。若如此次,则skb_share_check会创建sk_buff的一份拷贝。
- */
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
- goto out;
- }
- /*
- *pskb_may_pull确保skb->data指向的内存包含的数据至少为IP头部大小,由于每个
- *IP数据包包括IP分片必须包含一个完整的IP头部。如果小于IP头部大小,则缺失
- *的部分将从数据分片中拷贝。这些分片保存在skb_shinfo(skb)->frags[]中。
- */
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto inhdr_error;
- /* pskb_may_pull可能会调整skb中的指针,所以需要重新定义IP头部*/
- iph = ip_hdr(skb);
- /*
- * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
- *
- * Is the datagram acceptable?
- *
- * 1. Length at least the size of an ip header
- * 2. Version of 4
- * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
- * 4. Doesn't have a bogus length
- */
- /* 上面说的很清楚了 */
- if (iph->ihl < 5 || iph->version != 4)
- goto inhdr_error;
- /* 确保IP完整的头部包括选项在内存中 */
- if (!pskb_may_pull(skb, iph->ihl*4))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
- /* 验证IP头部的校验和 */
- if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
- goto inhdr_error;
- /* IP头部中指示的IP数据包总长度 */
- len = ntohs(iph->tot_len);
- /*
- *确保skb的数据长度大于等于IP头部中指示的IP数据包总长度及数据包总长度必须
- *大于等于IP头部长度。
- */
- if (skb->len < len) {
- IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
- goto drop;
- } else if (len < (iph->ihl*4))
- goto inhdr_error;
- /* Our transport medium may have padded the buffer out. Now we know it
- * is IP we can trim to the true length of the frame.
- * Note this now means skb->len holds ntohs(iph->tot_len).
- */
- /* 注释说明的很清楚,该函数成功执行完之后,skb->len = ntohs(iph->tot_len). */
- if (pskb_trim_rcsum(skb, len)) {
- IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
- goto drop;
- }
- /* Remove any debris in the socket control block */
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- /* 忽略与netfilter子系统的交互,调用为ip_rcv_finish(skb) */
- return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
- ip_rcv_finish);
- inhdr_error:
- IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
- drop:
- kfree_skb(skb);
- out:
- return NET_RX_DROP;
- }
阅读(2749) | 评论(0) | 转发(0) |