/* When the interface is in promisc. mode, drop all the crap * that it receives, do not try to analyse it. */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop;
// 确保 skb->data 所指区域包含的数据区块至少和 IP 报头一样大 if (!pskb_may_pull(skb, sizeof(struct iphdr))) goto inhdr_error;
iph = skb->nh.iph;
/* * 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 */
// 基本 IP 报头的尺寸是 20 字节 if (iph->ihl < 5 || iph->version != 4) goto inhdr_error;
if (!pskb_may_pull(skb, iph->ihl*4)) goto inhdr_error;
iph = skb->nh.iph;
// 校验和 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) goto inhdr_error;
len = ntohs(iph->tot_len); // 1. 确保已接收的封包长度大于或等于 IP 报头中记录的长度 // 2. 确保封包的尺寸至少和 IP 报头的尺寸一样大 if (skb->len < len || 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). */ // 检查 L2 协议是否补满封包以达到特定最小长度 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));
/* * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ if (skb->dst == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { if (err == -EHOSTUNREACH) IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); goto drop; } }