/* This function receives all incoming IP datagrams. */ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct iphdr *iph = skb->h.iph;//这里在传入是已经设置好了,指向IP报文头 unsigned char hash; unsigned char flag = 0; unsigned char opts_p = 0; /* Set iff the packet has options. */ struct inet_protocol *ipprot; static struct options opt; /* since we don't use these yet, and they take up stack space. */ int brd; int is_frag=0;
DPRINTF((DBG_IP, "<<\n"));
skb->ip_hdr = iph; /* Fragments can cause ICMP errors too! */ /* Is the datagram acceptable? */ if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) { DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n")); DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); skb->sk = NULL; kfree_skb(skb, FREE_WRITE); return(0); } if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */ ip_print(iph); /* Bogus, only for debugging. */ memset((char *) &opt, 0, sizeof(opt)); if (do_options(iph, &opt) != 0) return 0; opts_p = 1; }
if (iph->frag_off & 0x0020) is_frag|=1; if (ntohs(iph->frag_off) & 0x1fff) is_frag|=2; /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */ if ((brd = chk_addr(iph->daddr)) == 0) {//如果不是本地IP,需要转发,转发在上一个小文里已经说过了,调用rt_route查询路由表,获取下一跳的物理接口,并发送出去 #ifdef CONFIG_IP_FORWARD ip_forward(skb, dev, is_frag); #else printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n", iph->saddr,iph->daddr); #endif skb->sk = NULL; kfree_skb(skb, FREE_WRITE); return(0); }
/* * Reassemble IP fragments. */
if(is_frag)//如果是分片报文,需要重组。这个后续单说一下ip_defrag和ip_fragment这两个函数 { #ifdef CONFIG_IP_DEFRAG skb=ip_defrag(iph,skb,dev);//在没有接收完一个完整的报文之前,这里返回null if(skb==NULL) { return 0; } iph=skb->h.iph; #else printk("\nIP: *** datagram fragmentation not yet implemented ***\n"); printk(" SRC = %s ", in_ntoa(iph->saddr)); printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr)); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); skb->sk = NULL; kfree_skb(skb, FREE_WRITE); return(0); #endif }
if(brd==IS_INVBCAST) { /* printk("Invalid broadcast address from %x [target %x] (Probably they have a wrong netmask)\n", iph->saddr,iph->daddr);*/ skb->sk=NULL; kfree_skb(skb,FREE_WRITE); return(0); } /* Point into the IP datagram, just past the header. */
skb->ip_hdr = iph; skb->h.raw += iph->ihl*4; hash = iph->protocol & (MAX_INET_PROTOS -1); for (ipprot = (struct inet_protocol *)inet_protos[hash]; ipprot != NULL; ipprot=(struct inet_protocol *)ipprot->next) { struct sk_buff *skb2;
if (ipprot->protocol != iph->protocol) continue; DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot)); print_ipprot(ipprot);
/* * See if we need to make a copy of it. This will * only be set if more than one protocol wants it. * and then not for the last one. */ if (ipprot->copy) { skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); if (skb2 == NULL) continue; memcpy(skb2, skb, skb->mem_len); skb2->mem_addr = skb2; skb2->ip_hdr = (struct iphdr *)( (unsigned long)skb2 + (unsigned long) skb->ip_hdr - (unsigned long)skb); skb2->h.raw = (unsigned char *)( (unsigned long)skb2 + (unsigned long) skb->h.raw - (unsigned long)skb); skb2->free=1; } else { skb2 = skb; } flag = 1;
/* * Pass on the datagram to each protocol that wants it, * based on the datagram protocol. We should really * check the protocol handler's return values here... */
//这里调用四层报文接收处理函数处理,如果是tcp报文,调用我们之前说过的tcp_rcv ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr, (ntohs(iph->tot_len) - (iph->ihl * 4)), iph->saddr, 0, ipprot);
}
/* * All protocols checked. * If this packet was a broadcast, we may *not* reply to it, since that * causes (proven, grin) ARP storms and a leakage of memory (i.e. all * ICMP reply messages get queued up for transmission...) */ if (!flag) { if (brd != IS_BROADCAST) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); skb->sk = NULL; kfree_skb(skb, FREE_WRITE); }
return(0); }
|