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

📄 slip.c

📁 完整的1.0代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * slip.c	This module implements the SLIP protocol for kernel-based *		devices like TTY.  It interfaces between a raw TTY, and the *		kernel's INET protocol layers (via DDI). * * Version:	@(#)slip.c	0.7.6	05/25/93 * * Authors:	Laurence Culhane, <loz@holmes.demon.co.uk> *		Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> * * Fixes: *		Alan Cox	: 	Sanity checks and avoid tx overruns. *					Has a new sl->mtu field. *		Alan Cox	: 	Found cause of overrun. ifconfig sl0 mtu upwards. *					Driver now spots this and grows/shrinks its buffers(hack!). *					Memory leak if you run out of memory setting up a slip driver fixed. *		Matt Dillon	:	Printable slip (borrowed from NET2E) *	Pauline Middelink	:	Slip driver fixes. *		Alan Cox	:	Honours the old SL_COMPRESSED flag *		Alan Cox	:	KISS AX.25 and AXUI IP support *		Michael Riepe	:	Automatic CSLIP recognition added *		Charles Hedrick :	CSLIP header length problem fix. *		Alan Cox	:	Corrected non-IP cases of the above. */ #include <asm/segment.h>#include <asm/system.h>#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/in.h>#include "inet.h"#include "dev.h"#ifdef CONFIG_AX25#include "ax25.h"#endif#include "eth.h"#include "ip.h"#include "route.h"#include "protocol.h"#include "tcp.h"#include "skbuff.h"#include "sock.h"#include "arp.h"#include "slip.h"#include "slhc.h"#define	SLIP_VERSION	"0.7.5"/* Define some IP layer stuff.  Not all systems have it. */#ifdef SL_DUMP#   define	IP_VERSION	4	/* version# of our IP software	*/#   define	IPF_F_OFFSET	0x1fff	/* Offset field			*/#   define	IPF_DF		0x4000	/* Don't fragment flag		*/#   define	IPF_MF		0x2000	/* More Fragments flag		*/#   define	IP_OF_COPIED	0x80	/* Copied-on-fragmentation flag	*/#   define	IP_OF_CLASS	0x60	/* Option class			*/#   define	IP_OF_NUMBER	0x1f	/* Option number		*/#endifstatic struct slip	sl_ctrl[SL_NRUNIT];static struct tty_ldisc	sl_ldisc;static int		already = 0;/* Dump the contents of an IP datagram. */static voidip_dump(unsigned char *ptr, int len){#ifdef SL_DUMP  struct iphdr *ip;  struct tcphdr *th;  int dlen, doff;  if (inet_debug != DBG_SLIP) return;  ip = (struct iphdr *) ptr;  th = (struct tcphdr *) (ptr + ip->ihl * 4);  printk("\r%s -> %s seq %lx ack %lx len %d\n",	 in_ntoa(ip->saddr), in_ntoa(ip->daddr), 	 ntohl(th->seq), ntohl(th->ack_seq), ntohs(ip->tot_len));  return;  printk("\r*****\n");  printk("%p %d\n", ptr, len);  ip = (struct iphdr *) ptr;  dlen = ntohs(ip->tot_len);  doff = ((ntohs(ip->frag_off) & IPF_F_OFFSET) << 3);  printk("SLIP: %s->", in_ntoa(ip->saddr));  printk("%s\n", in_ntoa(ip->daddr));  printk(" len %u ihl %u ver %u ttl %u prot %u",	dlen, ip->ihl, ip->version, ip->ttl, ip->protocol);  if (ip->tos != 0) printk(" tos %u", ip->tos);  if (doff != 0 || (ntohs(ip->frag_off) & IPF_MF))	printk(" id %u offs %u", ntohs(ip->id), doff);  if (ntohs(ip->frag_off) & IPF_DF) printk(" DF");  if (ntohs(ip->frag_off) & IPF_MF) printk(" MF");  printk("\n*****\n");#endif}#if 0void clh_dump(unsigned char *cp, int len){  if (len > 60)    len = 60;  printk("%d:", len);  while (len > 0) {    printk(" %x", *cp++);    len--;  }  printk("\n\n");}#endif/* Initialize a SLIP control block for use. */static voidsl_initialize(struct slip *sl, struct device *dev){  sl->inuse		= 0;  sl->sending		= 0;  sl->escape		= 0;  sl->flags		= 0;#ifdef SL_ADAPTIVE  sl->mode		= SL_MODE_ADAPTIVE;	/* automatic CSLIP recognition */#else#ifdef SL_COMPRESSED  sl->mode		= SL_MODE_CSLIP | SL_MODE_ADAPTIVE;	/* Default */#else  sl->mode		= SL_MODE_SLIP;		/* Default for non compressors */#endif#endif    sl->line		= dev->base_addr;  sl->tty		= NULL;  sl->dev		= dev;  sl->slcomp		= NULL;  /* Clear all pointers. */  sl->rbuff		= NULL;  sl->xbuff		= NULL;  sl->cbuff		= NULL;  sl->rhead		= NULL;  sl->rend		= NULL;  dev->rmem_end		= (unsigned long) NULL;  dev->rmem_start	= (unsigned long) NULL;  dev->mem_end		= (unsigned long) NULL;  dev->mem_start	= (unsigned long) NULL;}/* Find a SLIP channel from its `tty' link. */static struct slip *sl_find(struct tty_struct *tty){  struct slip *sl;  int i;  if (tty == NULL) return(NULL);  for (i = 0; i < SL_NRUNIT; i++) {	sl = &sl_ctrl[i];	if (sl->tty == tty) return(sl);  }  return(NULL);}/* Find a free SLIP channel, and link in this `tty' line. */static inline struct slip *sl_alloc(void){  unsigned long flags;  struct slip *sl;  int i;  save_flags (flags);  cli();  for (i = 0; i < SL_NRUNIT; i++) {	sl = &sl_ctrl[i];	if (sl->inuse == 0) {		sl->inuse = 1;		sl->tty = NULL;		restore_flags(flags);		return(sl);	}  }  restore_flags(flags);  return(NULL);}/* Free a SLIP channel. */static inline voidsl_free(struct slip *sl){  unsigned long flags;  if (sl->inuse) {  	save_flags(flags);  	cli();	sl->inuse = 0;	sl->tty = NULL;	restore_flags(flags);  }}/* MTU has been changed by the IP layer. Unfortunately we are not told about this, but   we spot it ourselves and fix things up. We could be in an upcall from the tty   driver, or in an ip packet queue. */   static void sl_changedmtu(struct slip *sl){	struct device *dev=sl->dev;	unsigned char *tb,*rb,*cb,*tf,*rf,*cf;	int l;	int omtu=sl->mtu;		sl->mtu=dev->mtu;	l=(dev->mtu *2);/* * allow for arrival of larger UDP packets, even if we say not to * also fixes a bug in which SunOS sends 512-byte packets even with * an MSS of 128 */	if (l < (576 * 2))	  l = 576 * 2;		DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n"));		tb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);	rb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);	cb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);		if(tb==NULL || rb==NULL || cb==NULL)	{		printk("Unable to grow slip buffers. MTU change cancelled.\n");		sl->mtu=omtu;		dev->mtu=omtu;		if(tb!=NULL)			kfree(tb);		if(rb!=NULL)			kfree(rb);		if(cb!=NULL)			kfree(cb);		return;	}		cli();		tf=(unsigned char *)sl->dev->mem_start;	sl->dev->mem_start=(unsigned long)tb;	sl->dev->mem_end=(unsigned long) (sl->dev->mem_start + l);	rf=(unsigned char *)sl->dev->rmem_start;	sl->dev->rmem_start=(unsigned long)rb;	sl->dev->rmem_end=(unsigned long) (sl->dev->rmem_start + l);		sl->xbuff = (unsigned char *) sl->dev->mem_start;	sl->rbuff = (unsigned char *) sl->dev->rmem_start;	sl->rend  = (unsigned char *) sl->dev->rmem_end;	sl->rhead = sl->rbuff;		cf=sl->cbuff;	sl->cbuff=cb;		sl->escape=0;	sl->sending=0;	sl->rcount=0;	sti();			if(rf!=NULL)		kfree(rf);	if(tf!=NULL)		kfree(tf);	if(cf!=NULL)		kfree(cf);}/* Stuff one byte into a SLIP receiver buffer. */static inline voidsl_enqueue(struct slip *sl, unsigned char c){  unsigned long flags;  save_flags(flags);  cli();  if (sl->rhead < sl->rend) {	*sl->rhead = c;	sl->rhead++;	sl->rcount++;  } else sl->roverrun++;  restore_flags(flags);}/* Release 'i' bytes from a SLIP receiver buffer. */static inline voidsl_dequeue(struct slip *sl, int i){  unsigned long flags;  save_flags(flags);  cli();  if (sl->rhead > sl->rbuff) {	sl->rhead -= i;	sl->rcount -= i;  }  restore_flags(flags);}/* Set the "sending" flag.  This must be atomic, hence the ASM. */static inline voidsl_lock(struct slip *sl){  unsigned long flags;  save_flags(flags);  cli();  sl->sending = 1;  sl->dev->tbusy = 1;  restore_flags(flags);}/* Clear the "sending" flag.  This must be atomic, hence the ASM. */static inline voidsl_unlock(struct slip *sl){  unsigned long flags;  save_flags(flags);  cli();  sl->sending = 0;  sl->dev->tbusy = 0;  restore_flags(flags);}/* Send one completely decapsulated IP datagram to the IP layer. */static voidsl_bump(struct slip *sl){  int done;  unsigned char c;  unsigned long flags;  int count;  count = sl->rcount;  if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {    if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {#if 1      /* ignore compressed packets when CSLIP is off */      if (!(sl->mode & SL_MODE_CSLIP)) {	printk("SLIP: compressed packet ignored\n");	return;      }#endif      /* make sure we've reserved enough space for uncompress to use */      save_flags(flags);      cli();      if ((sl->rhead + 80) < sl->rend) {	sl->rhead += 80;	sl->rcount += 80;	done = 1;      } else {	sl->roverrun++;	done = 0;      }      restore_flags(flags);      if (! done)  /* not enough space available */	return;      count = slhc_uncompress(sl->slcomp, sl->rbuff, count);      if (count <= 0) {	sl->errors++;	return;      }    } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {      if (!(sl->mode & SL_MODE_CSLIP)) {	/* turn on header compression */	sl->mode |= SL_MODE_CSLIP;	printk("SLIP: header compression turned on\n");      }      sl->rbuff[0] &= 0x4f;      if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {	sl->errors++;	return;      }    }  }  DPRINTF((DBG_SLIP, "<< \"%s\" recv:\r\n", sl->dev->name));  ip_dump(sl->rbuff, sl->rcount);  /* Bump the datagram to the upper layers... */  do {	DPRINTF((DBG_SLIP, "SLIP: packet is %d at 0x%X\n",					sl->rcount, sl->rbuff));	/* clh_dump(sl->rbuff, count); */	done = dev_rint(sl->rbuff, count, 0, sl->dev);	if (done == 0 || done == 1) break;  } while(1);  sl->rpacket++;}/* TTY finished sending a datagram, so clean up. */static voidsl_next(struct slip *sl){  DPRINTF((DBG_SLIP, "SLIP: sl_next(0x%X) called!\n", sl));  sl_unlock(sl);  dev_tint(sl->dev);}/* Encapsulate one IP datagram and stuff into a TTY queue. */static voidsl_encaps(struct slip *sl, unsigned char *icp, int len){  unsigned char *bp, *p;  int count;  DPRINTF((DBG_SLIP, "SLIP: sl_encaps(0x%X, %d) called\n", icp, len));  DPRINTF((DBG_SLIP, ">> \"%s\" sent:\r\n", sl->dev->name));    ip_dump(icp, len);    if(sl->mtu != sl->dev->mtu)	/* Someone has been ifconfigging */  	sl_changedmtu(sl);    if(len>sl->mtu)		/* Sigh, shouldn't occur BUT ... */  {  	len=sl->mtu;  	printk("slip: truncating oversized transmit packet!\n");  }  p = icp;  if(sl->mode & SL_MODE_CSLIP)	  len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);#ifdef OLD    /*   * Send an initial END character to flush out any   * data that may have accumulated in the receiver   * due to line noise.   */  bp = sl->xbuff;  *bp++ = END;  count = 1;  /*   * For each byte in the packet, send the appropriate   * character sequence, according to the SLIP protocol.   */  while(len-- > 0) {	c = *p++;	switch(c) {		case END:			*bp++ = ESC;			*bp++ = ESC_END;			count += 2;                       	break;		case ESC:			*bp++ = ESC;			*bp++ = ESC_ESC;			count += 2;                       	break;		default:			*bp++ = c;			count++;	}  }  *bp++ = END;    count++;#else  if(sl->mode & SL_MODE_SLIP6)  	count=slip_esc6(p, (unsigned char *)sl->xbuff,len);  else  	count=slip_esc(p, (unsigned char *)sl->xbuff,len);#endif  	    sl->spacket++;  bp = sl->xbuff;  /* Tell TTY to send it on its way. */  DPRINTF((DBG_SLIP, "SLIP: kicking TTY for %d bytes at 0x%X\n", count, bp));  if (tty_write_data(sl->tty, (char *) bp, count,	     (void (*)(void *))sl_next, (void *) sl) == 0) {	DPRINTF((DBG_SLIP, "SLIP: TTY already done with %d bytes!\n", count));	sl_next(sl);  }}/*static void sl_hex_dump(unsigned char *x,int l){	int n=0;	printk("sl_xmit: (%d bytes)\n",l);	while(l)	{		printk("%2X ",(int)*x++);		l--;		n++;		if(n%32==0)			printk("\n");	}	if(n%32)		printk("\n");}*//* Encapsulate an IP datagram and kick it into a TTY queue. */static intsl_xmit(struct sk_buff *skb, struct device *dev){  struct tty_struct *tty;  struct slip *sl;  int size;  /* Find the correct SLIP channel to use. */  sl = &sl_ctrl[dev->base_addr];  tty = sl->tty;  DPRINTF((DBG_SLIP, "SLIP: sl_xmit(\"%s\") skb=0x%X busy=%d\n",				dev->name, skb, sl->sending));  /*   * If we are busy already- too bad.  We ought to be able   * to queue things at this point, to allow for a little   * frame buffer.  Oh well...   */  if (sl->sending) {	DPRINTF((DBG_SLIP, "SLIP: sl_xmit: BUSY\r\n"));	sl->sbusy++;	return(1);  }  /* We were not, so we are now... :-) */  if (skb != NULL) {#ifdef CONFIG_AX25  	if(sl->mode & SL_MODE_AX25)	{		if(!skb->arp && dev->rebuild_header(skb->data,dev))		{			skb->dev=dev;			arp_queue(skb);			return 0;		}		skb->arp=1;	}#endif  		sl_lock(sl);	size = skb->len;	if (!(sl->mode & SL_MODE_AX25)) {		if (size < sizeof(struct iphdr)) {			printk("Runt IP frame fed to slip!\n");		} else {			size = ((struct iphdr *)(skb->data))->tot_len;			size = ntohs(size);		}	}	/*	sl_hex_dump(skb->data,skb->len);*/	sl_encaps(sl, skb->data, size);	if (skb->free)		kfree_skb(skb, FREE_WRITE);  }  return(0);}/* Return the frame type ID.  This is normally IP but maybe be AX.25. */static unsigned shortsl_type_trans (struct sk_buff *skb, struct device *dev){#ifdef CONFIG_AX25	struct slip *sl=&sl_ctrl[dev->base_addr];	if(sl->mode&SL_MODE_AX25)		return(NET16(ETH_P_AX25));#endif  return(NET16(ETH_P_IP));}/* Fill in the MAC-level header. Not used by SLIP. */static intsl_header(unsigned char *buff, struct device *dev, unsigned short type,	  unsigned long daddr, unsigned long saddr, unsigned len){#ifdef CONFIG_AX25  struct slip *sl=&sl_ctrl[dev->base_addr];  if((sl->mode&SL_MODE_AX25) && type!=NET16(ETH_P_AX25))  	return ax25_encapsulate_ip(buff,dev,type,daddr,saddr,len);#endif    return(0);}

⌨️ 快捷键说明

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