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

📄 ip.c

📁 基于linux1.0内核的linux源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 *		operating system.  INET is implemented using the  BSD Socket
 *		interface as the means of communication with the user level.
 *
 *		The Internet Protocol (IP) module.
 *
 * Version:	@(#)ip.c	1.0.16b	9/1/93
 *
 * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
 *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *		Donald Becker, <becker@super.org>
 *
 * Fixes:
 *		Alan Cox	:	Commented a couple of minor bits of surplus code
 *		Alan Cox	:	Undefining IP_FORWARD doesn't include the code
 *					(just stops a compiler warning).
 *		Alan Cox	:	Frames with >=MAX_ROUTE record routes, strict routes or loose routes
 *					are junked rather than corrupting things.
 *		Alan Cox	:	Frames to bad broadcast subnets are dumped
 *					We used to process them non broadcast and
 *					boy could that cause havoc.
 *		Alan Cox	:	ip_forward sets the free flag on the 
 *					new frame it queues. Still crap because
 *					it copies the frame but at least it 
 *					doesn't eat memory too.
 *		Alan Cox	:	Generic queue code and memory fixes.
 *		Fred Van Kempen :	IP fragment support (borrowed from NET2E)
 *		Gerhard Koerting:	Forward fragmented frames correctly.
 *		Gerhard Koerting: 	Fixes to my fix of the above 8-).
 *		Gerhard Koerting:	IP interface addressing fix.
 *		Linus Torvalds	:	More robustness checks
 *		Alan Cox	:	Even more checks: Still not as robust as it ought to be
 *		Alan Cox	:	Save IP header pointer for later
 *		Alan Cox	:	ip option setting
 *		Alan Cox	:	Use ip_tos/ip_ttl settings
 *		Alan Cox	:	Fragmentation bogosity removed
 *					(Thanks to Mark.Bush@prg.ox.ac.uk)
 *		Dmitry Gorodchanin :	Send of a raw packet crash fix.
 *		Alan Cox	:	Silly ip bug when an overlength
 *					fragment turns up. Now frees the
 *					queue.
 *
 * To Fix:
 *		IP option processing is mostly not needed. ip_forward needs to know about routing rules
 *		and time stamp but that's about all.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 */
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include "inet.h"
#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "route.h"
#include "tcp.h"
#include "skbuff.h"
#include "sock.h"
#include "arp.h"
#include "icmp.h"

#define CONFIG_IP_FORWARD
#define CONFIG_IP_DEFRAG

extern int last_retran;
extern void sort_send(struct sock *sk);

#define min(a,b)	((a)<(b)?(a):(b))

void
ip_print(struct iphdr *ip)
{
  unsigned char buff[32];
  unsigned char *ptr;
  int addr, len, i;

  if (inet_debug != DBG_IP) return;

  /* Dump the IP header. */
  printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
	   ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len));
  printk("    id=%X, ttl=%d, prot=%d, check=%X\n",
	   ip->id, ip->ttl, ip->protocol, ip->check);
  printk("    frag_off=%d\n", ip->frag_off);
  printk("    soucre=%s ", in_ntoa(ip->saddr));
  printk("dest=%s\n", in_ntoa(ip->daddr));
  printk("    ----\n");

  /* Dump the data. */
  ptr = (unsigned char *)(ip + 1);
  addr = 0;
  len = ntohs(ip->tot_len) - (4 * ip->ihl);
  while (len > 0) {
	printk("    %04X: ", addr);
	for(i = 0; i < 16; i++) {
		if (len > 0) {
			printk("%02X ", (*ptr & 0xFF));
			buff[i] = *ptr++;
			if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
		} else {
			printk("   ");
			buff[i] = ' ';
		}
		addr++;
		len--;
	};
	buff[i] = '\0';
	printk("  \"%s\"\n", buff);
  }
  printk("    ----\n\n");
}


int
ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
  switch(cmd) {
	case DDIOCSDBG:
		return(dbg_ioctl((void *) arg, DBG_IP));
	default:
		return(-EINVAL);
  }
}


/* these two routines will do routining. */
static void
strict_route(struct iphdr *iph, struct options *opt)
{
}


static void
loose_route(struct iphdr *iph, struct options *opt)
{
}


static void
print_ipprot(struct inet_protocol *ipprot)
{
  DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
	   ipprot->handler, ipprot->protocol, ipprot->copy));
}


/* This routine will check to see if we have lost a gateway. */
void
ip_route_check(unsigned long daddr)
{
}


#if 0
/* this routine puts the options at the end of an ip header. */
static int
build_options(struct iphdr *iph, struct options *opt)
{
  unsigned char *ptr;
  /* currently we don't support any options. */
  ptr = (unsigned char *)(iph+1);
  *ptr = 0;
  return (4);
}
#endif


/* Take an skb, and fill in the MAC header. */
static int
ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
	unsigned long saddr)
{
  unsigned char *ptr;
  int mac;

  ptr = skb->data;
  mac = 0;
  skb->arp = 1;
  if (dev->hard_header) {
	mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
  }
  if (mac < 0) {
	mac = -mac;
	skb->arp = 0;
  }
  skb->dev = dev;
  return(mac);
}


/*
 * This routine builds the appropriate hardware/IP headers for
 * the routine.  It assumes that if *dev != NULL then the
 * protocol knows what it's doing, otherwise it uses the
 * routing/ARP tables to select a device struct.
 */
int
ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
		struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
{
  static struct options optmem;
  struct iphdr *iph;
  struct rtable *rt;
  unsigned char *buff;
  unsigned long raddr;
  static int count = 0;
  int tmp;

  if (saddr == 0) 
  	saddr = my_addr();
  	
  DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n"
	   "                 type=%d, opt=%X, len = %d)\n",
	   skb, saddr, daddr, *dev, type, opt, len));
	   
  buff = skb->data;

  /* See if we need to look up the device. */
  if (*dev == NULL) {
	rt = rt_route(daddr, &optmem);
	if (rt == NULL) 
		return(-ENETUNREACH);

	*dev = rt->rt_dev;
	if (saddr == 0x0100007FL && daddr != 0x0100007FL) 
		saddr = rt->rt_dev->pa_addr;
	raddr = rt->rt_gateway;

	DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
	opt = &optmem;
  } else {
	/* We still need the address of the first hop. */
	rt = rt_route(daddr, &optmem);
	raddr = (rt == NULL) ? 0 : rt->rt_gateway;
  }
  if (raddr == 0)
  	raddr = daddr;

  /* Now build the MAC header. */
  tmp = ip_send(skb, raddr, len, *dev, saddr);
  buff += tmp;
  len -= tmp;

  skb->dev = *dev;
  skb->saddr = saddr;
  if (skb->sk) skb->sk->saddr = saddr;

  /* Now build the IP header. */

  /* If we are using IPPROTO_RAW, then we don't need an IP header, since
     one is being supplied to us by the user */

  if(type == IPPROTO_RAW) return (tmp);

  iph = (struct iphdr *)buff;
  iph->version  = 4;
  iph->tos      = tos;
  iph->frag_off = 0;
  iph->ttl      = ttl;
  iph->daddr    = daddr;
  iph->saddr    = saddr;
  iph->protocol = type;
  iph->ihl      = 5;
  iph->id       = htons(count++);

  /* Setup the IP options. */
#ifdef Not_Yet_Avail
  build_options(iph, opt);
#endif

  return(20 + tmp);	/* IP header plus MAC header size */
}


static int
do_options(struct iphdr *iph, struct options *opt)
{
  unsigned char *buff;
  int done = 0;
  int i, len = sizeof(struct iphdr);

  /* Zero out the options. */
  opt->record_route.route_size = 0;
  opt->loose_route.route_size  = 0;
  opt->strict_route.route_size = 0;
  opt->tstamp.ptr              = 0;
  opt->security                = 0;
  opt->compartment             = 0;
  opt->handling                = 0;
  opt->stream                  = 0;
  opt->tcc                     = 0;
  return(0);

  /* Advance the pointer to start at the options. */
  buff = (unsigned char *)(iph + 1);

  /* Now start the processing. */
  while (!done && len < iph->ihl*4) switch(*buff) {
	case IPOPT_END:
		done = 1;
		break;
	case IPOPT_NOOP:
		buff++;
		len++;
		break;
	case IPOPT_SEC:
		buff++;
		if (*buff != 11) return(1);
		buff++;
		opt->security = ntohs(*(unsigned short *)buff);
		buff += 2;
		opt->compartment = ntohs(*(unsigned short *)buff);
		buff += 2;
		opt->handling = ntohs(*(unsigned short *)buff);
		buff += 2;
	  	opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1));
	  	buff += 3;
	  	len += 11;
	  	break;
	case IPOPT_LSRR:
		buff++;
		if ((*buff - 3)% 4 != 0) return(1);
		len += *buff;
		opt->loose_route.route_size = (*buff -3)/4;
		buff++;
		if (*buff % 4 != 0) return(1);
		opt->loose_route.pointer = *buff/4 - 1;
		buff++;
		buff++;
		for (i = 0; i < opt->loose_route.route_size; i++) {
			if(i>=MAX_ROUTE)
				return(1);
			opt->loose_route.route[i] = *(unsigned long *)buff;
			buff += 4;
		}
		break;
	case IPOPT_SSRR:
		buff++;
		if ((*buff - 3)% 4 != 0) return(1);
		len += *buff;
		opt->strict_route.route_size = (*buff -3)/4;
		buff++;
		if (*buff % 4 != 0) return(1);
		opt->strict_route.pointer = *buff/4 - 1;
		buff++;
		buff++;
		for (i = 0; i < opt->strict_route.route_size; i++) {
			if(i>=MAX_ROUTE)
				return(1);
			opt->strict_route.route[i] = *(unsigned long *)buff;
			buff += 4;
		}
		break;
	case IPOPT_RR:
		buff++;
		if ((*buff - 3)% 4 != 0) return(1);
		len += *buff;
		opt->record_route.route_size = (*buff -3)/4;
		buff++;
		if (*buff % 4 != 0) return(1);
		opt->record_route.pointer = *buff/4 - 1;
		buff++;
		buff++;
		for (i = 0; i < opt->record_route.route_size; i++) {
			if(i>=MAX_ROUTE)
				return 1;
			opt->record_route.route[i] = *(unsigned long *)buff;
			buff += 4;
		}
		break;
	case IPOPT_SID:
		len += 4;
		buff +=2;
		opt->stream = *(unsigned short *)buff;
		buff += 2;
		break;
	case IPOPT_TIMESTAMP:
		buff++;
		len += *buff;
		if (*buff % 4 != 0) return(1);
		opt->tstamp.len = *buff / 4 - 1;
		buff++;
		if ((*buff - 1) % 4 != 0) return(1);
		opt->tstamp.ptr = (*buff-1)/4;
		buff++;
		opt->tstamp.x.full_char = *buff;
		buff++;
		for (i = 0; i < opt->tstamp.len; i++) {
			opt->tstamp.data[i] = *(unsigned long *)buff;
			buff += 4;
		}
		break;
	default:
		return(1);
  }

  if (opt->record_route.route_size == 0) {
	if (opt->strict_route.route_size != 0) {
		memcpy(&(opt->record_route), &(opt->strict_route),
					     sizeof(opt->record_route));
	} else if (opt->loose_route.route_size != 0) {
		memcpy(&(opt->record_route), &(opt->loose_route),
					     sizeof(opt->record_route));
	}
  }

  if (opt->strict_route.route_size != 0 &&
      opt->strict_route.route_size != opt->strict_route.pointer) {
	strict_route(iph, opt);
	return(0);
  }

  if (opt->loose_route.route_size != 0 &&
      opt->loose_route.route_size != opt->loose_route.pointer) {
	loose_route(iph, opt);
	return(0);
  }

  return(0);
}

/* This is a version of ip_compute_csum() optimized for IP headers, which
   always checksum on 4 octet boundaries. */
static inline unsigned short
ip_fast_csum(unsigned char * buff, int wlen)
{
    unsigned long sum = 0;

    if (wlen) {
    	unsigned long bogus;
	 __asm__("clc\n"
		"1:\t"
		"lodsl\n\t"
		"adcl %3, %0\n\t"
		"decl %2\n\t"
		"jne 1b\n\t"
		"adcl $0, %0\n\t"
		"movl %0, %3\n\t"
		"shrl $16, %3\n\t"
		"addw %w3, %w0\n\t"
		"adcw $0, %w0"
	    : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
	    : "0"  (sum),  "1" (buff),  "2" (wlen));
    }
    return (~sum) & 0xffff;
}

/*
 * This routine does all the checksum computations that don't
 * require anything special (like copying or special headers).
 */
unsigned short
ip_compute_csum(unsigned char * buff, int len)
{
  unsigned long sum = 0;

  /* Do the first multiple of 4 bytes and convert to 16 bits. */
  if (len > 3) {
	__asm__("clc\n"
	        "1:\t"
	    	"lodsl\n\t"
	    	"adcl %%eax, %%ebx\n\t"
	    	"loop 1b\n\t"
	    	"adcl $0, %%ebx\n\t"
	    	"movl %%ebx, %%eax\n\t"
	    	"shrl $16, %%eax\n\t"
	    	"addw %%ax, %%bx\n\t"
	    	"adcw $0, %%bx"
	        : "=b" (sum) , "=S" (buff)
	        : "0" (sum), "c" (len >> 2) ,"1" (buff)
	        : "ax", "cx", "si", "bx" );
  }
  if (len & 2) {
	__asm__("lodsw\n\t"
	    	"addw %%ax, %%bx\n\t"
	    	"adcw $0, %%bx"
	        : "=b" (sum), "=S" (buff)
	        : "0" (sum), "1" (buff)
	        : "bx", "ax", "si");
  }
  if (len & 1) {
	__asm__("lodsb\n\t"
	    	"movb $0, %%ah\n\t"
	    	"addw %%ax, %%bx\n\t"
	    	"adcw $0, %%bx"
	        : "=b" (sum), "=S" (buff)
	        : "0" (sum), "1" (buff)
	        : "bx", "ax", "si");
  }
  sum =~sum;
  return(sum & 0xffff);
}

/* Check the header of an incoming IP datagram.  This version is still used in slhc.c. */
int
ip_csum(struct iphdr *iph)
{
  return ip_fast_csum((unsigned char *)iph, iph->ihl);
}

/* Generate a checksym for an outgoing IP datagram. */
static void
ip_send_check(struct iphdr *iph)
{
   iph->check = 0;
   iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}

/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/

static struct ipq *ipqueue = NULL;		/* IP fragment queue	*/
 /* Create a new fragment entry. */
static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
{
   	struct ipfrag *fp;
 
   	fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
   	if (fp == NULL) 
   	{
	 	printk("IP: frag_create: no memory left !\n");
	 	return(NULL);
   	}
  	memset(fp, 0, sizeof(struct ipfrag));

⌨️ 快捷键说明

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