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

📄 slip.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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. * * Version:	@(#)slip.c	0.8.3	12/24/94 * * 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. *		Alan Cox	:	Now uses hardware type as per FvK. *		Alan Cox	:	Default to 192.168.0.0 (RFC 1597) *		A.N.Kuznetsov	:	dev_tint() recursion fix. *	Dmitry Gorodchanin	:	SLIP memory leaks *      Dmitry Gorodchanin      :       Code cleanup. Reduce tty driver *                                      buffering from 4096 to 256 bytes. *                                      Improving SLIP response time. *                                      CONFIG_SLIP_MODE_SLIP6. *                                      ifconfig sl? up & down now works correctly. *					Modularization. *              Alan Cox        :       Oops - fix AX.25 buffer lengths *      Dmitry Gorodchanin      :       Even more cleanups. Preserve CSLIP *                                      statistics. Include CSLIP code only *                                      if it really needed. *		Alan Cox	:	Free slhc buffers in the right place. *		Alan Cox	:	Allow for digipeated IP over AX.25 *		Matti Aarnio	:	Dynamic SLIP devices, with ideas taken *					from Jim Freeman's <jfree@caldera.com> *					dynamic PPP devices.  We do NOT kfree() *					device entries, just reg./unreg. them *					as they are needed.  We kfree() them *					at module cleanup. *					With MODULE-loading ``insmod'', user can *					issue parameter:   slip_maxdev=1024 *					(Or how much he/she wants.. Default is 256) * *	Stanislav Voronyi	:	Slip line checking, with ideas taken *					from multislip BSDI driver which was written *					by Igor Chechik, RELCOM Corp. Only algorithms * 					have been ported to Linux SLIP driver. *	Vitaly E. Lavrov	:	Sane behaviour on tty hangup. *	Alexey Kuznetsov	:	Cleanup interfaces to tty&netdevice modules. */#define SL_CHECK_TRANSMIT#include <linux/config.h>#include <linux/module.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/tty.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/if_arp.h>#include <linux/if_slip.h>#include <linux/init.h>#include "slip.h"#ifdef CONFIG_INET#include <linux/ip.h>#include <linux/tcp.h>#include <net/slhc_vj.h>#endif#ifdef MODULE#define SLIP_VERSION    "0.8.4-NET3.019-NEWTTY-MODULAR"#else#define	SLIP_VERSION	"0.8.4-NET3.019-NEWTTY"#endiftypedef struct slip_ctrl {	struct slip	ctrl;		/* SLIP things			*/	struct net_device	dev;		/* the device			*/} slip_ctrl_t;static slip_ctrl_t	**slip_ctrls = NULL;int slip_maxdev = SL_NRUNIT;		/* Can be overridden with insmod! */MODULE_PARM(slip_maxdev, "i");static struct tty_ldisc	sl_ldisc;static int slip_esc(unsigned char *p, unsigned char *d, int len);static void slip_unesc(struct slip *sl, unsigned char c);#ifdef CONFIG_SLIP_MODE_SLIP6static int slip_esc6(unsigned char *p, unsigned char *d, int len);static void slip_unesc6(struct slip *sl, unsigned char c);#endif#ifdef CONFIG_SLIP_SMARTstatic void sl_keepalive(unsigned long sls);static void sl_outfill(unsigned long sls);static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd);#endif/*********************************  Buffer administration routines:*	sl_alloc_bufs()*	sl_free_bufs()*	sl_realloc_bufs()** NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because*	sl_realloc_bufs provides strong atomicity and reallocation*	on actively running device.*********************************//*    Allocate channel buffers. */static intsl_alloc_bufs(struct slip *sl, int mtu){	int err = -ENOBUFS;	unsigned long len;	char * rbuff = NULL;	char * xbuff = NULL;#ifdef SL_INCLUDE_CSLIP	char * cbuff = NULL;	struct slcompress *slcomp = NULL;#endif	/*	 * Allocate the SLIP frame buffers:	 *	 * rbuff	Receive buffer.	 * xbuff	Transmit buffer.	 * cbuff        Temporary compression buffer.	 */	len = 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 (len < 576 * 2)		len = 576 * 2;	rbuff = kmalloc(len + 4, GFP_KERNEL);	if (rbuff == NULL)		goto err_exit;	xbuff = kmalloc(len + 4, GFP_KERNEL);	if (xbuff == NULL)		goto err_exit;#ifdef SL_INCLUDE_CSLIP	cbuff = kmalloc(len + 4, GFP_KERNEL);	if (cbuff == NULL)		goto err_exit;	slcomp = slhc_init(16, 16);	if (slcomp == NULL)		goto err_exit;#endif	spin_lock_bh(&sl->lock);	if (sl->tty == NULL) {		spin_unlock_bh(&sl->lock);		err = -ENODEV;		goto err_exit;	}	sl->mtu	     = mtu;	sl->buffsize = len;	sl->rcount   = 0;	sl->xleft    = 0;	rbuff = xchg(&sl->rbuff, rbuff);	xbuff = xchg(&sl->xbuff, xbuff);#ifdef SL_INCLUDE_CSLIP	cbuff = xchg(&sl->cbuff, cbuff);	slcomp = xchg(&sl->slcomp, slcomp);#ifdef CONFIG_SLIP_MODE_SLIP6	sl->xdata    = 0;	sl->xbits    = 0;#endif#endif	spin_unlock_bh(&sl->lock);	err = 0;	/* Cleanup */err_exit:#ifdef SL_INCLUDE_CSLIP	if (cbuff)		kfree(cbuff);	if (slcomp)		slhc_free(slcomp);#endif	if (xbuff)		kfree(xbuff);	if (rbuff)		kfree(rbuff);	return err;}/* Free a SLIP channel buffers. */static voidsl_free_bufs(struct slip *sl){	void * tmp;	/* Free all SLIP frame buffers. */	if ((tmp = xchg(&sl->rbuff, NULL)) != NULL)		kfree(tmp);	if ((tmp = xchg(&sl->xbuff, NULL)) != NULL)		kfree(tmp);#ifdef SL_INCLUDE_CSLIP	if ((tmp = xchg(&sl->cbuff, NULL)) != NULL)		kfree(tmp);	if ((tmp = xchg(&sl->slcomp, NULL)) != NULL)		slhc_free(tmp);#endif}/*    Reallocate slip channel buffers. */static int sl_realloc_bufs(struct slip *sl, int mtu){	int err = 0;	struct net_device *dev = sl->dev;	unsigned char *xbuff, *rbuff;#ifdef SL_INCLUDE_CSLIP	unsigned char *cbuff;#endif	int len = 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 (len < 576 * 2)		len = 576 * 2;	xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);	rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);#ifdef SL_INCLUDE_CSLIP	cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);#endif#ifdef SL_INCLUDE_CSLIP	if (xbuff == NULL || rbuff == NULL || cbuff == NULL)  {#else	if (xbuff == NULL || rbuff == NULL)  {#endif		if (mtu >= sl->mtu) {			printk("%s: unable to grow slip buffers, MTU change cancelled.\n",			       dev->name);			err = -ENOBUFS;		}		goto done;	}	spin_lock_bh(&sl->lock);	err = -ENODEV;	if (sl->tty == NULL)		goto done_on_bh;	xbuff    = xchg(&sl->xbuff, xbuff);	rbuff    = xchg(&sl->rbuff, rbuff);#ifdef SL_INCLUDE_CSLIP	cbuff    = xchg(&sl->cbuff, cbuff);#endif	if (sl->xleft)  {		if (sl->xleft <= len)  {			memcpy(sl->xbuff, sl->xhead, sl->xleft);		} else  {			sl->xleft = 0;			sl->tx_dropped++;		}	}	sl->xhead = sl->xbuff;	if (sl->rcount)  {		if (sl->rcount <= len) {			memcpy(sl->rbuff, rbuff, sl->rcount);		} else  {			sl->rcount = 0;			sl->rx_over_errors++;			set_bit(SLF_ERROR, &sl->flags);		}	}	sl->mtu      = mtu;	dev->mtu      = mtu;	sl->buffsize = len;	err = 0;done_on_bh:	spin_unlock_bh(&sl->lock);done:	if (xbuff)		kfree(xbuff);	if (rbuff)		kfree(rbuff);#ifdef SL_INCLUDE_CSLIP	if (cbuff)		kfree(cbuff);#endif	return err;}/* Set the "sending" flag.  This must be atomic hence the set_bit. */static inline voidsl_lock(struct slip *sl){	netif_stop_queue(sl->dev);}/* Clear the "sending" flag.  This must be atomic, hence the ASM. */static inline voidsl_unlock(struct slip *sl){	netif_wake_queue(sl->dev);}/* Send one completely decapsulated IP datagram to the IP layer. */static voidsl_bump(struct slip *sl){	struct sk_buff *skb;	int count;	count = sl->rcount;#ifdef SL_INCLUDE_CSLIP	if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {		unsigned char c;		if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {			/* ignore compressed packets when CSLIP is off */			if (!(sl->mode & SL_MODE_CSLIP)) {				printk("%s: compressed packet ignored\n", sl->dev->name);				return;			}			/* make sure we've reserved enough space for uncompress to use */			if (count + 80 > sl->buffsize) {				sl->rx_over_errors++;				return;			}			count = slhc_uncompress(sl->slcomp, sl->rbuff, count);			if (count <= 0) {				return;			}		} else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {			if (!(sl->mode & SL_MODE_CSLIP)) {				/* turn on header compression */				sl->mode |= SL_MODE_CSLIP;				sl->mode &= ~SL_MODE_ADAPTIVE;				printk("%s: header compression turned on\n", sl->dev->name);			}			sl->rbuff[0] &= 0x4f;			if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {				return;			}		}	}#endif  /* SL_INCLUDE_CSLIP */	sl->rx_bytes+=count;		skb = dev_alloc_skb(count);	if (skb == NULL)  {		printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);		sl->rx_dropped++;		return;	}	skb->dev = sl->dev;	memcpy(skb_put(skb,count), sl->rbuff, count);	skb->mac.raw=skb->data;	skb->protocol=htons(ETH_P_IP);	netif_rx(skb);	sl->rx_packets++;}/* Encapsulate one IP datagram and stuff into a TTY queue. */static voidsl_encaps(struct slip *sl, unsigned char *icp, int len){	unsigned char *p;	int actual, count;	if (len > sl->mtu) {		/* Sigh, shouldn't occur BUT ... */		printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);		sl->tx_dropped++;		sl_unlock(sl);		return;	}	p = icp;#ifdef SL_INCLUDE_CSLIP	if (sl->mode & SL_MODE_CSLIP)  {		len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);	}#endif#ifdef CONFIG_SLIP_MODE_SLIP6	if(sl->mode & SL_MODE_SLIP6)		count = slip_esc6(p, (unsigned char *) sl->xbuff, len);	else#endif		count = slip_esc(p, (unsigned char *) sl->xbuff, len);	/* Order of next two lines is *very* important.	 * When we are sending a little amount of data,	 * the transfer may be completed inside driver.write()	 * routine, because it's running with interrupts enabled.	 * In this case we *never* got WRITE_WAKEUP event,	 * if we did not request it before write operation.	 *       14 Oct 1994  Dmitry Gorodchanin.	 */	sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);	actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);#ifdef SL_CHECK_TRANSMIT	sl->dev->trans_start = jiffies;#endif	sl->xleft = count - actual;	sl->xhead = sl->xbuff + actual;#ifdef CONFIG_SLIP_SMART	/* VSV */	clear_bit(SLF_OUTWAIT, &sl->flags);	/* reset outfill flag */#endif}/* * Called by the driver when there's room for more data.  If we have * more packets to send, we send them here. */static void slip_write_wakeup(struct tty_struct *tty){	int actual;	struct slip *sl = (struct slip *) tty->disc_data;	/* First make sure we're connected. */	if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) {		return;	}	if (sl->xleft <= 0)  {		/* Now serial buffer is almost free & we can start		 * transmission of another packet */		sl->tx_packets++;		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);		sl_unlock(sl);		return;	}	actual = tty->driver.write(tty, 0, sl->xhead, sl->xleft);	sl->xleft -= actual;	sl->xhead += actual;}static void sl_tx_timeout(struct net_device *dev){	struct slip *sl = (struct slip*)(dev->priv);	spin_lock(&sl->lock);	if (netif_queue_stopped(dev)) {		struct slip *sl = (struct slip*)(dev->priv);		if (!netif_running(dev))			goto out;		/* May be we must check transmitter timeout here ?		 *      14 Oct 1994 Dmitry Gorodchanin.		 */#ifdef SL_CHECK_TRANSMIT		if (jiffies - dev->trans_start  < 20 * HZ)  {			/* 20 sec timeout not reached */			goto out;		}		printk("%s: transmit timed out, %s?\n", dev->name,		       (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?		       "bad line quality" : "driver error");		sl->xleft = 0;		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);		sl_unlock(sl);#endif	}out:	spin_unlock(&sl->lock);}/* Encapsulate an IP datagram and kick it into a TTY queue. */static intsl_xmit(struct sk_buff *skb, struct net_device *dev){	struct slip *sl = (struct slip*)(dev->priv);

⌨️ 快捷键说明

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