1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
| /* 主要功能:对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;
}
|