网络 接受 数据包 (packet)
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 编辑 ]