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

📄 ppp_async.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PPP async serial channel driver for Linux. * * Copyright 1999 Paul Mackerras. * *  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. * * This driver provides the encapsulation and framing for sending * and receiving PPP frames over async serial lines.  It relies on * the generic PPP layer to give it frames to send and to process * received frames.  It implements the PPP line discipline. * * Part of the code in this driver was inspired by the old async-only * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * * ==FILEVERSION 20000227== */#include <linux/module.h>#include <linux/kernel.h>#include <linux/skbuff.h>#include <linux/tty.h>#include <linux/netdevice.h>#include <linux/poll.h>#include <linux/ppp_defs.h>#include <linux/if_ppp.h>#include <linux/ppp_channel.h>#include <linux/spinlock.h>#include <linux/init.h>#include <asm/uaccess.h>#ifndef spin_trylock_bh#define spin_trylock_bh(lock)	({ int __r; local_bh_disable();	\				   __r = spin_trylock(lock);	\				   if (!__r) local_bh_enable();	\				   __r; })#endif#define PPP_VERSION	"2.4.1"#define OBUFSIZE	256/* Structure for storing local state. */struct asyncppp {	struct tty_struct *tty;	unsigned int	flags;	unsigned int	state;	unsigned int	rbits;	int		mru;	spinlock_t	xmit_lock;	spinlock_t	recv_lock;	unsigned long	xmit_flags;	u32		xaccm[8];	u32		raccm;	unsigned int	bytes_sent;	unsigned int	bytes_rcvd;	struct sk_buff	*tpkt;	int		tpkt_pos;	u16		tfcs;	unsigned char	*optr;	unsigned char	*olim;	unsigned long	last_xmit;	struct sk_buff	*rpkt;	int		lcp_fcs;	struct ppp_channel chan;	/* interface to generic ppp layer */	unsigned char	obuf[OBUFSIZE];};/* Bit numbers in xmit_flags */#define XMIT_WAKEUP	0#define XMIT_FULL	1/* State bits */#define SC_TOSS		0x20000000#define SC_ESCAPE	0x40000000/* Bits in rbits */#define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)static int flag_time = HZ;MODULE_PARM(flag_time, "i");/* * Prototypes. */static int ppp_async_encode(struct asyncppp *ap);static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb);static int ppp_async_push(struct asyncppp *ap);static void ppp_async_flush_output(struct asyncppp *ap);static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,			    char *flags, int count);static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd,			   unsigned long arg);static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,			   int len, int inbound);struct ppp_channel_ops async_ops = {	ppp_async_send,	ppp_async_ioctl};/* * Routines implementing the PPP line discipline. *//* * Called when a tty is put into PPP line discipline. */static intppp_asynctty_open(struct tty_struct *tty){	struct asyncppp *ap;	int err;	MOD_INC_USE_COUNT;	err = -ENOMEM;	ap = kmalloc(sizeof(*ap), GFP_KERNEL);	if (ap == 0)		goto out;	/* initialize the asyncppp structure */	memset(ap, 0, sizeof(*ap));	ap->tty = tty;	ap->mru = PPP_MRU;	spin_lock_init(&ap->xmit_lock);	spin_lock_init(&ap->recv_lock);	ap->xaccm[0] = ~0U;	ap->xaccm[3] = 0x60000000U;	ap->raccm = ~0U;	ap->optr = ap->obuf;	ap->olim = ap->obuf;	ap->lcp_fcs = -1;	ap->chan.private = ap;	ap->chan.ops = &async_ops;	ap->chan.mtu = PPP_MRU;	err = ppp_register_channel(&ap->chan);	if (err)		goto out_free;	tty->disc_data = ap;	return 0; out_free:	kfree(ap); out:	MOD_DEC_USE_COUNT;	return err;}/* * Called when the tty is put into another line discipline * or it hangs up. * We assume that while we are in this routine, the tty layer * won't call any of the other line discipline entries for the * same tty. */static voidppp_asynctty_close(struct tty_struct *tty){	struct asyncppp *ap = tty->disc_data;	if (ap == 0)		return;	tty->disc_data = 0;	ppp_unregister_channel(&ap->chan);	if (ap->rpkt != 0)		kfree_skb(ap->rpkt);	if (ap->tpkt != 0)		kfree_skb(ap->tpkt);	kfree(ap);	MOD_DEC_USE_COUNT;}/* * Read does nothing. */static ssize_tppp_asynctty_read(struct tty_struct *tty, struct file *file,		  unsigned char *buf, size_t count){	/* For now, do the same as the old 2.3.x code useta */	struct asyncppp *ap = tty->disc_data;	if (ap == 0)		return -ENXIO;	return ppp_channel_read(&ap->chan, file, buf, count);}/* * Write on the tty does nothing, the packets all come in * from the ppp generic stuff. */static ssize_tppp_asynctty_write(struct tty_struct *tty, struct file *file,		   const unsigned char *buf, size_t count){	/* For now, do the same as the old 2.3.x code useta */	struct asyncppp *ap = tty->disc_data;	if (ap == 0)		return -ENXIO;	return ppp_channel_write(&ap->chan, buf, count);}static intppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,		   unsigned int cmd, unsigned long arg){	struct asyncppp *ap = tty->disc_data;	int err, val;	err = -EFAULT;	switch (cmd) {	case PPPIOCGCHAN:		err = -ENXIO;		if (ap == 0)			break;		err = -EFAULT;		if (put_user(ppp_channel_index(&ap->chan), (int *) arg))			break;		err = 0;		break;	case PPPIOCGUNIT:		err = -ENXIO;		if (ap == 0)			break;		err = -EFAULT;		if (put_user(ppp_unit_number(&ap->chan), (int *) arg))			break;		err = 0;		break;	case TCGETS:	case TCGETA:		err = n_tty_ioctl(tty, file, cmd, arg);		break;	case TCFLSH:		/* flush our buffers and the serial port's buffer */		if (arg == TCIOFLUSH || arg == TCOFLUSH)			ppp_async_flush_output(ap);		err = n_tty_ioctl(tty, file, cmd, arg);		break;	case FIONREAD:		val = 0;		if (put_user(val, (int *) arg))			break;		err = 0;		break;/* * For now, do the same as the old 2.3 driver useta */	case PPPIOCGFLAGS:	case PPPIOCSFLAGS:	case PPPIOCGASYNCMAP:	case PPPIOCSASYNCMAP:	case PPPIOCGRASYNCMAP:	case PPPIOCSRASYNCMAP:	case PPPIOCGXASYNCMAP:	case PPPIOCSXASYNCMAP:	case PPPIOCGMRU:	case PPPIOCSMRU:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		err = ppp_async_ioctl(&ap->chan, cmd, arg);		break;	case PPPIOCATTACH:	case PPPIOCDETACH:		err = ppp_channel_ioctl(&ap->chan, cmd, arg);		break;	default:		err = -ENOIOCTLCMD;	}	return err;}/* No kernel lock - fine */static unsigned intppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait){	unsigned int mask;	struct asyncppp *ap = tty->disc_data;	mask = POLLOUT | POLLWRNORM;/* * For now, do the same as the old 2.3 driver useta */	if (ap != 0)		mask |= ppp_channel_poll(&ap->chan, file, wait);	if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file))		mask |= POLLHUP;	return mask;}static intppp_asynctty_room(struct tty_struct *tty){	return 65535;}static voidppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,		  char *flags, int count){	struct asyncppp *ap = tty->disc_data;	if (ap == 0)		return;	spin_lock_bh(&ap->recv_lock);	ppp_async_input(ap, buf, flags, count);	spin_unlock_bh(&ap->recv_lock);	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)	    && tty->driver.unthrottle)		tty->driver.unthrottle(tty);}static voidppp_asynctty_wakeup(struct tty_struct *tty){	struct asyncppp *ap = tty->disc_data;	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);	if (ap == 0)		return;	if (ppp_async_push(ap))		ppp_output_wakeup(&ap->chan);}static struct tty_ldisc ppp_ldisc = {	magic:	TTY_LDISC_MAGIC,	name:	"ppp",	open:	ppp_asynctty_open,	close:	ppp_asynctty_close,	read:	ppp_asynctty_read,	write:	ppp_asynctty_write,	ioctl:	ppp_asynctty_ioctl,	poll:	ppp_asynctty_poll,	receive_room: ppp_asynctty_room,	receive_buf: ppp_asynctty_receive,	write_wakeup: ppp_asynctty_wakeup,};intppp_async_init(void){	int err;	err = tty_register_ldisc(N_PPP, &ppp_ldisc);	if (err != 0)		printk(KERN_ERR "PPP_async: error %d registering line disc.\n",		       err);	return err;}/* * The following routines provide the PPP channel interface. */static intppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg){	struct asyncppp *ap = chan->private;	int err, val;	u32 accm[8];	err = -EFAULT;	switch (cmd) {	case PPPIOCGFLAGS:		val = ap->flags | ap->rbits;		if (put_user(val, (int *) arg))			break;		err = 0;		break;	case PPPIOCSFLAGS:		if (get_user(val, (int *) arg))			break;		ap->flags = val & ~SC_RCV_BITS;		spin_lock_bh(&ap->recv_lock);		ap->rbits = val & SC_RCV_BITS;		spin_unlock_bh(&ap->recv_lock);		err = 0;		break;	case PPPIOCGASYNCMAP:		if (put_user(ap->xaccm[0], (u32 *) arg))			break;		err = 0;		break;	case PPPIOCSASYNCMAP:		if (get_user(ap->xaccm[0], (u32 *) arg))			break;		err = 0;		break;	case PPPIOCGRASYNCMAP:		if (put_user(ap->raccm, (u32 *) arg))			break;		err = 0;		break;	case PPPIOCSRASYNCMAP:		if (get_user(ap->raccm, (u32 *) arg))			break;		err = 0;		break;	case PPPIOCGXASYNCMAP:		if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))			break;		err = 0;		break;	case PPPIOCSXASYNCMAP:		if (copy_from_user(accm, (void *) arg, sizeof(accm)))			break;		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */		accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */		memcpy(ap->xaccm, accm, sizeof(ap->xaccm));		err = 0;		break;	case PPPIOCGMRU:		if (put_user(ap->mru, (int *) arg))			break;		err = 0;		break;	case PPPIOCSMRU:		if (get_user(val, (int *) arg))			break;		if (val < PPP_MRU)			val = PPP_MRU;		ap->mru = val;		err = 0;		break;	default:		err = -ENOTTY;	}	return err;}/* * Procedures for encapsulation and framing. */u16 ppp_crc16_table[256] = {	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,

⌨️ 快捷键说明

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