⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 3 页
字号:
 		offset += len;/* 		printk("Queue frag\n");*/  		/* Put this fragment into the sending queue. */ 		ip_queue_xmit(sk, dev, skb2, 1);/* 		printk("Queued\n");*/   	} } #ifdef CONFIG_IP_FORWARD/* Forward an IP datagram to its next destination. */static voidip_forward(struct sk_buff *skb, struct device *dev, int is_frag){  struct device *dev2;  struct iphdr *iph;  struct sk_buff *skb2;  struct rtable *rt;  unsigned char *ptr;  unsigned long raddr;  /*   * Only forward packets that were fired at us when we are in promiscuous   * mode. In standard mode we rely on the driver to filter for us.   */     if(dev->flags&IFF_PROMISC)  {  	if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len))  		return;  }    /*   * According to the RFC, we must first decrease the TTL field. If   * that reaches zero, we must reply an ICMP control message telling   * that the packet's lifetime expired.   */  iph = skb->h.iph;  iph->ttl--;  if (iph->ttl <= 0) {	DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));	DPRINTF((DBG_IP, "    SRC = %s   ", in_ntoa(iph->saddr)));	DPRINTF((DBG_IP, "    DST = %s (ignored)\n", in_ntoa(iph->daddr)));	/* Tell the sender its packet died... */	icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev);	return;  }  /* Re-compute the IP header checksum. */  ip_send_check(iph);  /*   * OK, the packet is still valid.  Fetch its destination address,   * and give it to the IP sender for further processing.   */  rt = rt_route(iph->daddr, NULL);  if (rt == NULL) {	DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));	/* Tell the sender its packet cannot be delivered... */	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev);	return;  }  /*   * Gosh.  Not only is the packet valid; we even know how to   * forward it onto its final destination.  Can we say this   * is being plain lucky?   * If the router told us that there is no GW, use the dest.   * IP address itself- we seem to be connected directly...   */  raddr = rt->rt_gateway;  if (raddr != 0) {	rt = rt_route(raddr, NULL);	if (rt == NULL) {		DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));		/* Tell the sender its packet cannot be delivered... */		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);		return;	}	if (rt->rt_gateway != 0) raddr = rt->rt_gateway;  } else raddr = iph->daddr;  dev2 = rt->rt_dev;  if (dev == dev2)	return;  /*   * We now allocate a new buffer, and copy the datagram into it.   * If the indicated interface is up and running, kick it.   */  DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr)));  DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n",			in_ntoa(raddr), dev2->name, skb->len));  if (dev2->flags & IFF_UP) {	skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +		       dev2->hard_header_len + skb->len, GFP_ATOMIC);	if (skb2 == NULL) {		printk("\nIP: No memory available for IP forward\n");		return;	}	ptr = skb2->data;	skb2->sk = NULL;	skb2->free = 1;	skb2->len = skb->len + dev2->hard_header_len;	skb2->mem_addr = skb2;	skb2->mem_len = sizeof(struct sk_buff) + skb2->len;	skb2->next = NULL;	skb2->h.raw = ptr;	/* Copy the packet data into the new buffer. */	memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len);			/* Now build the MAC header. */	(void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);	if(skb2->len > dev2->mtu)	{		ip_fragment(NULL,skb2,dev2, is_frag);		kfree_skb(skb2,FREE_WRITE);	}	else		dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL);  }}#endif/* This function receives all incoming IP datagrams. */intip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt){  struct iphdr *iph = skb->h.iph;  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) {#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)  {#ifdef CONFIG_IP_DEFRAG        skb=ip_defrag(iph,skb,dev);        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...	*/	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);}/* * Queues a packet to be sent, and starts the transmitter * if necessary.  if free = 1 then we free the block after * transmit, otherwise we don't. * This routine also needs to put in the total length, and * compute the checksum. */voidip_queue_xmit(struct sock *sk, struct device *dev, 	      struct sk_buff *skb, int free){  struct iphdr *iph;  unsigned char *ptr;  if (sk == NULL) free = 1;  if (dev == NULL) {	printk("IP: ip_queue_xmit dev = NULL\n");	return;  }  IS_SKB(skb);  skb->free = free;  skb->dev = dev;  skb->when = jiffies;    DPRINTF((DBG_IP, ">>\n"));  ptr = skb->data;  ptr += dev->hard_header_len;  iph = (struct iphdr *)ptr;  skb->ip_hdr = iph;  iph->tot_len = ntohs(skb->len-dev->hard_header_len);  if(skb->len > dev->mtu)  {/*  	printk("Fragment!\n");*/  	ip_fragment(sk,skb,dev,0);  	IS_SKB(skb);  	kfree_skb(skb,FREE_WRITE);  	return;  }    ip_send_check(iph);  ip_print(iph);  skb->next = NULL;  /* See if this is the one trashing our queue. Ross? */  skb->magic = 1;  if (!free) {	skb->link3 = NULL;	sk->packets_out++;	cli();	if (sk->send_head == NULL) {		sk->send_tail = skb;		sk->send_head = skb;	} else {		/* See if we've got a problem. */		if (sk->send_tail == NULL) {			printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");			sort_send(sk);		} else {			sk->send_tail->link3 = skb;			sk->send_tail = skb;		}	}	sti();	reset_timer(sk, TIME_WRITE, sk->rto);  } else {	skb->sk = sk;  }  /* If the indicated interface is up and running, kick it. */  if (dev->flags & IFF_UP) {	if (sk != NULL) {		dev->queue_xmit(skb, dev, sk->priority);	} 	else {		dev->queue_xmit(skb, dev, SOPRI_NORMAL);	}  } else {	if (free) kfree_skb(skb, FREE_WRITE);  }}voidip_do_retransmit(struct sock *sk, int all){  struct sk_buff * skb;  struct proto *prot;  struct device *dev;  int retransmits;  prot = sk->prot;  skb = sk->send_head;  retransmits = sk->retransmits;  while (skb != NULL) {	dev = skb->dev;	/* I know this can't happen but as it does.. */	if(dev==NULL)	{		printk("ip_retransmit: NULL device bug!\n");		goto oops;	}	IS_SKB(skb);		/*	 * The rebuild_header function sees if the ARP is done.	 * If not it sends a new ARP request, and if so it builds	 * the header.	 */        cli();	/* We might get interrupted by an arp reply here and fill		   the frame in twice. Because of the technique used this		   would be a little sad */	if (!skb->arp) {		if (dev->rebuild_header(skb->data, dev)) {			sti();	/* Failed to rebuild - next */			if (!all) break;			skb = (struct sk_buff *)skb->link3;			continue;		}	}	skb->arp = 1;	sti();	skb->when = jiffies;	/* If the interface is (still) up and running, kick it. */	if (dev->flags & IFF_UP) {		if (sk && !skb_device_locked(skb))			dev->queue_xmit(skb, dev, sk->priority);	/*	  else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */	}oops:	retransmits++;	sk->prot->retransmits ++;	if (!all) break;	/* This should cut it off before we send too many packets. */	if (sk->retransmits > sk->cong_window) break;	skb = (struct sk_buff *)skb->link3;  }}/* * This is the normal code called for timeouts.  It does the retransmission * and then does backoff.  ip_do_retransmit is separated out because * tcp_ack needs to send stuff from the retransmit queue without * initiating a backoff. */voidip_retransmit(struct sock *sk, int all){  ip_do_retransmit(sk, all);  /*   * Increase the timeout each time we retransmit.  Note that   * we do not increase the rtt estimate.  rto is initialized   * from rtt, but increases here.  Jacobson (SIGCOMM 88) suggests   * that doubling rto each time is the least we can get away with.   * In KA9Q, Karns uses this for the first few times, and then   * goes to quadratic.  netBSD doubles, but only goes up to *64,   * and clamps at 1 to 64 sec afterwards.  Note that 120 sec is   * defined in the protocol as the maximum possible RTT.  I guess   * we'll have to use something other than TCP to talk to the   * University of Mars.   */  sk->retransmits++;  sk->backoff++;  sk->rto = min(sk->rto << 1, 120*HZ);  reset_timer(sk, TIME_WRITE, sk->rto);}/* *	Socket option code for IP. This is the end of the line after any TCP,UDP etc options on *	an IP socket. */ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen){	int val,err;	  	if (optval == NULL)   		return(-EINVAL);  	err=verify_area(VERIFY_READ, optval, sizeof(int));  	if(err)  		return err;  	  	val = get_fs_long((unsigned long *)optval);	if(level!=SOL_IP)		return -EOPNOTSUPP;	switch(optname)	{		case IP_TOS:			if(val<0||val>255)				return -EINVAL;			sk->ip_tos=val;			return 0;		case IP_TTL:			if(val<1||val>255)				return -EINVAL;			sk->ip_ttl=val;			return 0;		/* IP_OPTIONS and friends go here eventually */		default:			return(-ENOPROTOOPT);	}}int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen){	int val,err;		if(level!=SOL_IP)		return -EOPNOTSUPP;			switch(optname)	{		case IP_TOS:			val=sk->ip_tos;			break;		case IP_TTL:			val=sk->ip_ttl;			break;		default:			return(-ENOPROTOOPT);	}	err=verify_area(VERIFY_WRITE, optlen, sizeof(int));	if(err)  		return err;  	put_fs_long(sizeof(int),(unsigned long *) optlen);  	err=verify_area(VERIFY_WRITE, optval, sizeof(int));  	if(err)  		return err;  	put_fs_long(val,(unsigned long *)optval);  	return(0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -