Kernel version: 2.6.34
This is about the IP layer protocol to receive the message processing, highlighting the routing table lookup, and IP fragmentation reorganization.
IP_RCV into IP Shong receive function
Discard the message is not sent to this machine, skb->pkt_type in the network card receiving packet processing Ethernet head will be based on DST Mac settings, the protocol stack book will not be sent to the local broadcast message would be discarded in the two layer, actually discarded is occurring in the beginning of the upper level.
if (skb-
>pkt_type = = packet_otherhost)
goto drop;
Note that you may have options when you take the IP header, so the message length should be IPH->IHL * 4. Here you need to try two times, the first attempt to sizeof (struct IPHDR), just to make sure that the SKB can accommodate the standard header (20 bytes), and then Ip_hdr (SKB) to get the header, and the second attempt IHL * 4, which is the true length of the message, Then call IP_HDR (SKB) again to get the header. The reason to recall Ip_hdr () after two attempts pull is that pskb_may_pull () may invoke __pskb_pull_tail () to alter the existing SKB structure.
if (!pskb_may_pull (SKB, sizeof (struct
iphdr))
goto Inhdr_error;
IPH = IP_HDR (SKB);
..... if (!pskb_may_pull (SKB, iph->ihl*4))
goto Inhdr_error;
IPH = IP_HDR (SKB);
After obtaining the IP header after some checks, get to the total length of the message Len = Iph->tot_len, at this time call Pskb_trim_rcsum () to remove the extra bytes, that is, greater than Len.
if (Pskb_trim_rcsum (SKB, Len)) {
ip_inc_stats_bh (dev_net (Dev), ipstats_mib_indiscards);
goto drop;
}
Then call Ip_rcv_finish () to continue the processing of the IP layer, IP_RCV () can be seen as the IP layer processing before the route is found, and the next Ip_rcv_finish () will look for the routing table, which calls the inserted netfilter (about NetFilter, Refer to the previous article http://blog.csdn.net/qy532846454/article/details/6605592).
Return Nf_hook (Pf_inet, nf_inet_pre_routing, SKB, Dev, NULL, ip_rcv_finish);
Enter Ip_rcv_finish function
Ip_rcv_finish () The main task is to complete the routing table query, the decision message after the IP layer processing, is to continue to pass up, or forwarding, or discard.
No routing Table query was started, so there is no corresponding routing table entry: SKB_DST (SKB) = NULL. Ip_route_input () is found in the routing table, and the routing table for the kernel can be seen in the preceding article http://blog.csdn.net/qy532846454/article/details/6726171:
if (SKB_DST (SKB) = = 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 (Dev_net (Skb->dev),
ipstats_mib_ inaddrerrors);
else if (err = =-enetunreach)
ip_inc_stats_bh (Dev_net (Skb->dev),
ipstats_mib_innoroutes);
goto drop;
}
}
By routing table lookup, we know:
-If the message is discarded, direct drop;
-If the message is not received or forwarded, then input = Ip_error
-If it is sent to the native message, input = Ip_local_deliver;
-If the broadcast message, then input = Ip_local_deliver;
-If it is a group broadcast text, input = Ip_local_deliver;
-If the message is forwarded, then input = Ip_forward;
At the end of Ip_rcv_finish (), the found Route entry _skb_dst->input () is called to continue to pass up:
Return Dst_input (SKB);
Specific look at the message delivery under various circumstances, if it is discarded messages, the message is released, and from the IP protocol layer back to complete the message delivery process.
Drop:
kfree_skb (SKB);
return net_rx_drop;
If the message is not processed, execute ip_error and send the corresponding ICMP error message according to the error type.
static int ip_error (struct sk_buff *skb) {struct rtable *rt = skb_rtable (SKB);
unsigned long now;
int code;
Switch (rt->u.dst.error) {case EINVAL:default:goto out;
Case ehostunreach:code = Icmp_host_unreach;
Break
Case enetunreach:code = Icmp_net_unreach;
IP_INC_STATS_BH (Dev_net (Rt->u.dst.dev), ipstats_mib_innoroutes);
Break
Case eacces:code = icmp_pkt_filtered;
Break
now = jiffies;
Rt->u.dst.rate_tokens + + now-rt->u.dst.rate_last;
if (Rt->u.dst.rate_tokens > Ip_rt_error_burst) rt->u.dst.rate_tokens = Ip_rt_error_burst;
Rt->u.dst.rate_last = Now;
if (Rt->u.dst.rate_tokens >= ip_rt_error_cost) {rt->u.dst.rate_tokens-= Ip_rt_error_cost;
Icmp_send (SKB, Icmp_dest_unreach, code, 0); } out:kfree_skb (SKB);
return 0; }