X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=linux%2Fppp.c;h=06f39c642149f5411883685c92fb0bdb5f4d0178;hp=71b6b4c716bd57cde138e7bafe84306292770ef7;hb=0631a591f5290ceb3a0eb3004d890f5273f13b42;hpb=0f61ac5460e89dd768f1fb56fbdd8fa6f8af79f1 diff --git a/linux/ppp.c b/linux/ppp.c index 71b6b4c..06f39c6 100644 --- a/linux/ppp.c +++ b/linux/ppp.c @@ -2,14 +2,16 @@ * * Michael Callahan * Al Longyear + * Paul Mackerras * * Dynamic PPP devices by Jim Freeman . * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid * - * ==FILEVERSION 8== + * ==FILEVERSION 971016== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the number above. + * If you modify this file at all, please set the number above to the + * date of the modification as YYMMDD (year month day). * ppp.c is shipped with a PPP distribution as well as with the kernel; * if everyone increases the FILEVERSION number above, then scripts * can do the right thing when deciding whether to install a new ppp.c @@ -39,64 +41,36 @@ CHECK_CHARACTERS - Enable the checking on all received characters for 8 data bits, no parity. This adds a small amount of processing for each received character. - - NEW_SKBUFF - Use NET3.020 sk_buff's - - IPX_CHANGE - Force the use of IPX support into the driver. - THIS IS **VERY** ALPHA LEVEL CODE!!!! */ -/* #define NEW_SKBUFF 1 */ #define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) #define CHECK_CHARACTERS 1 #define PPP_COMPRESS 1 -#define USE_SKB_PROTOCOL 1 /* Set by the installation program! */ - -#ifdef NEW_SKBUFF -#undef USE_SKB_PROTOCOL -#define USE_SKB_PROTOCOL 2 -#endif - -#ifndef PPP_MAX_DEV -#define PPP_MAX_DEV 256 -#endif - -#undef IPX_CHANGE - -#if defined(IPX_CHANGE) || defined(NEW_SKBUFF) -#define PPP_REQUESTED_HDR_LEN PPP_HARD_HDR_LEN -#else -#define PPP_REQUESTED_HDR_LEN 0 -#endif -/* $Id: ppp.c,v 1.6 1995/12/18 03:38:12 paulus Exp $ - * Added dynamic allocation of channels to eliminate - * compiled-in limits on the number of channels. - * - * Dynamic channel allocation code Copyright 1995 Caldera, Inc., - * released under the GNU General Public License Version 2. - */ +/* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */ -#if USE_SKB_PROTOCOL == 0 -#include /* still needed for 1.2 */ -#endif +#include #include - -#ifndef MOD_INC_USE_COUNT /* for those 1.2 kernels still out there */ -#undef MOD_DEC_USE_COUNT -#define MOD_DEC_USE_COUNT do {} while (0) -#define MOD_INC_USE_COUNT do {} while (0) -#endif - -#include #include #include #include #include #include #include + +#undef VERSION +/* a nice define to generate linux version numbers */ +#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch)) + +#if LINUX_VERSION_CODE < VERSION(2,1,14) #include +#endif + +#if LINUX_VERSION_CODE >= VERSION(2,1,23) +#include +#endif + #include #include #include @@ -106,44 +80,82 @@ #include /* used in new tty drivers */ #include #include -#include -#include +#include #include #include #include #include #include -#ifdef NEW_SKBUFF -#include -#else typedef struct sk_buff sk_buff; -#define skb_data(skb) ((unsigned char *) (skb)->data) -#endif +#define skb_data(skb) ((__u8 *) (skb)->data) -#include -#include +#include +#include #include -#include "slhc.h" +#include + +#define fcstab ppp_crc16_table /* Name of the table in the kernel */ #include + #include #include #include - -#undef PACKETPTR -#define PACKETPTR 1 #include -#undef PACKETPTR - -#define bsd_decompress (*ppp->sc_rcomp->decompress) -#define bsd_compress (*ppp->sc_xcomp->compress) #ifndef PPP_IPX #define PPP_IPX 0x2b /* IPX protocol over PPP */ #endif #ifndef PPP_LQR -#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */ +#endif + +#if LINUX_VERSION_CODE >= VERSION(2,1,4) +#include +#define GET_USER(error,value,addr) error = get_user(value,addr) +#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 +#define PUT_USER(error,value,addr) error = put_user(value,addr) +#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 + +#if LINUX_VERSION_CODE >= VERSION(2,1,5) +#include +#endif + +#else /* 2.0.x and 2.1.x before 2.1.4 */ + +#define GET_USER(error,value,addr) \ +do { \ + error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \ + if (error == 0) \ + value = get_user(addr); \ +} while (0) + +#define COPY_FROM_USER(error,dest,src,size) \ +do { \ + error = verify_area (VERIFY_READ, (void *) src, size); \ + if (error == 0) \ + memcpy_fromfs (dest, src, size); \ +} while (0) + +#define PUT_USER(error,value,addr) \ +do { \ + error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \ + if (error == 0) \ + put_user (value, addr); \ +} while (0) + +#define COPY_TO_USER(error,dest,src,size) \ +do { \ + error = verify_area (VERIFY_WRITE, (void *) dest, size); \ + if (error == 0) \ + memcpy_tofs (dest, src, size); \ +} while (0) + +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,37) +#define test_and_set_bit(nr, addr) set_bit(nr, addr) #endif static int ppp_register_compressor (struct compressor *cp); @@ -156,43 +168,43 @@ static void ppp_unregister_compressor (struct compressor *cp); static struct compressor *find_compressor (int type); static void ppp_init_ctrl_blk (register struct ppp *); static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr); -static int ppp_doframe (struct ppp *); static struct ppp *ppp_alloc (void); -static void ppp_print_buffer (const u_char *, const u_char *, int); +static struct ppp *ppp_find (int pid_value); +static void ppp_print_buffer (const __u8 *, const __u8 *, int); extern inline void ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, - register u_char chr); + register __u8 chr); extern inline int lock_buffer (register struct ppp_buffer *buf); +static int ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf, + __u8 *data, int len, enum NPmode npmode); -static int rcv_proto_ip (struct ppp *, u_short, u_char *, int); -static int rcv_proto_ipx (struct ppp *, u_short, u_char *, int); -static int rcv_proto_vjc_comp (struct ppp *, u_short, u_char *, int); -static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int); -static int rcv_proto_unknown (struct ppp *, u_short, u_char *, int); -static int rcv_proto_lqr (struct ppp *, u_short, u_char *, int); -static void ppp_doframe_lower (struct ppp *, u_char *, int); -static int ppp_doframe (struct ppp *); +static int rcv_proto_ip (struct ppp *, __u16, __u8 *, int); +static int rcv_proto_ipx (struct ppp *, __u16, __u8 *, int); +static int rcv_proto_vjc_comp (struct ppp *, __u16, __u8 *, int); +static int rcv_proto_vjc_uncomp (struct ppp *, __u16, __u8 *, int); +static int rcv_proto_unknown (struct ppp *, __u16, __u8 *, int); +static int rcv_proto_lqr (struct ppp *, __u16, __u8 *, int); +static void ppp_doframe_lower (struct ppp *, __u8 *, int); +static int ppp_doframe (struct ppp *); -extern int ppp_bsd_compressor_init(void); -static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd); -static int rcv_proto_ccp (struct ppp *, u_short, u_char *, int); +static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd); +static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int); -#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c)) +#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (__u8)(c)) #ifndef OPTIMIZE_FLAG_TIME #define OPTIMIZE_FLAG_TIME 0 #endif -#ifndef PPP_MAX_DEV -#define PPP_MAX_DEV 256 -#endif - /* * Parameters which may be changed via insmod. */ static int flag_time = OPTIMIZE_FLAG_TIME; -static int max_dev = PPP_MAX_DEV; + +#if LINUX_VERSION_CODE >= VERSION(2,1,19) +MODULE_PARM(flag_time, "i"); +#endif /* * The "main" procedure to the ppp device @@ -210,115 +222,87 @@ static int ppp_dev_close (struct device *); static int ppp_dev_xmit (sk_buff *, struct device *); static struct enet_statistics *ppp_dev_stats (struct device *); -#if USE_SKB_PROTOCOL == 0 /* The 1.2.x kernel is here */ -#define dev_alloc_skb(count) alloc_skb(count, GFP_ATOMIC) -#define skb_put(skb,count) skb_data(skb) -#define get_long_user(addr) get_user_long((void *) addr) -#define get_int_user(addr) ((int) get_user_long((void *) addr)) -#define put_byte_user(val,addr) put_fs_byte(val,((u_char *) (addr))) -#define put_long_user(val,addr) put_fs_long((val),((void *) (addr))) - -static unsigned short ppp_dev_type (sk_buff *, struct device *); -static int ppp_dev_header (unsigned char *buff, struct device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len, struct sk_buff *skb); - -#else /* The 1.3.x kernel is here */ -#define get_long_user(addr) get_user(((int *) addr)) -#define get_int_user(addr) ((int) get_user(((int *) addr))) -#define put_byte_user(val,addr) put_user((val),((u_char *) (addr))) -#define put_long_user(val,addr) put_user((val),((int *) (addr))) - -static int ppp_dev_header (sk_buff *, struct device *, unsigned short, - void *, void *, unsigned); -#endif - -#ifdef NEW_SKBUFF -static int ppp_dev_input (struct protocol *self, struct protocol *lower, - sk_buff *skb, void *saddr, void *daddr); -static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type, - int subid, void *saddr, void *daddr, void *opt); -static int ppp_dev_getkey(int protocol, int subid, unsigned char *key); -#else -static int ppp_dev_rebuild (void *, struct device *, unsigned long, - sk_buff *); +#if LINUX_VERSION_CODE < VERSION(2,1,15) +static int ppp_dev_header (sk_buff *, struct device *, __u16, + void *, void *, unsigned int); +static int ppp_dev_rebuild (void *eth, struct device *dev, + unsigned long raddr, struct sk_buff *skb); #endif /* * TTY callbacks */ -static int ppp_tty_read (struct tty_struct *, struct file *, u_char *, +static int ppp_tty_read (struct tty_struct *, struct file *, __u8 *, unsigned int); -static int ppp_tty_write (struct tty_struct *, struct file *, const u_char *, +static int ppp_tty_write (struct tty_struct *, struct file *, const __u8 *, unsigned int); static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long); +#if LINUX_VERSION_CODE < VERSION(2,1,23) static int ppp_tty_select (struct tty_struct *tty, struct inode *inode, struct file *filp, int sel_type, select_table * wait); +#else +static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait); +#endif static int ppp_tty_open (struct tty_struct *); static void ppp_tty_close (struct tty_struct *); static int ppp_tty_room (struct tty_struct *tty); -static void ppp_tty_receive (struct tty_struct *tty, const u_char * cp, +static void ppp_tty_receive (struct tty_struct *tty, const __u8 * cp, char *fp, int count); static void ppp_tty_wakeup (struct tty_struct *tty); -#define CHECK_PPP(a) if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;} -#define CHECK_PPP_VOID() if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;} +#define CHECK_PPP_MAGIC(ppp) do { \ + if (ppp->magic != PPP_MAGIC) { \ + printk(KERN_WARNING "bad magic for ppp %p at %s:%d\n", \ + ppp, __FILE__, __LINE__); \ + } \ +} while (0) +#define CHECK_PPP(a) do { \ + CHECK_PPP_MAGIC(ppp); \ + if (!ppp->inuse) { \ + printk (ppp_warning, __LINE__); \ + return a; \ + } \ +} while (0) +#define CHECK_PPP_VOID() do { \ + CHECK_PPP_MAGIC(ppp); \ + if (!ppp->inuse) { \ + printk (ppp_warning, __LINE__); \ + } \ +} while (0) #define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f))) -#define in_rmap(ppp,c) ((((unsigned int) (u_char) (c)) < 0x20) && \ +#define in_rmap(ppp,c) ((((unsigned int) (__u8) (c)) < 0x20) && \ ppp->recv_async_map & (1 << (c))) #define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) -#define tty2ppp(tty) ((struct ppp *) (tty->disc_data)) -#define dev2ppp(dev) ((struct ppp *) (dev->priv)) -#define ppp2tty(ppp) ((struct tty_struct *) ppp->tty) -#define ppp2dev(ppp) ((struct device *) ppp->dev) - -struct ppp_hdr { - unsigned char address; - unsigned char control; - unsigned char protocol[2]; -}; - -#define PPP_HARD_HDR_LEN (sizeof (struct ppp_hdr)) - -typedef struct ppp_ctrl { - struct ppp_ctrl *next; /* Next structure in the list */ - char name [8]; /* Name of the device */ - struct ppp ppp; /* PPP control table */ - struct device dev; /* Device information table */ -} ppp_ctrl_t; +#define tty2ppp(tty) ((struct ppp *) ((tty)->disc_data)) +#define dev2ppp(dev) ((struct ppp *) ((dev)->priv)) +#define ppp2tty(ppp) ((ppp)->tty) +#define ppp2dev(ppp) (&(ppp)->dev) -static ppp_ctrl_t *ppp_list = NULL; - -#define ctl2ppp(ctl) (struct ppp *) &ctl->ppp -#define ctl2dev(ctl) (struct device *) &ctl->dev -#undef PPP_NRUNIT +static struct ppp *ppp_list = NULL; +static struct ppp *ppp_last = NULL; /* Buffer types */ -#define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */ -#define BUFFER_TYPE_TTY_WR 1 /* tty write buffer */ -#define BUFFER_TYPE_DEV_WR 2 /* ppp write buffer */ -#define BUFFER_TYPE_TTY_RD 3 /* tty read buffer */ +#define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */ +#define BUFFER_TYPE_TTY_WR 1 /* tty write buffer */ +#define BUFFER_TYPE_DEV_WR 2 /* ppp write buffer */ +#define BUFFER_TYPE_TTY_RD 3 /* tty read buffer */ #define BUFFER_TYPE_VJ 4 /* vj compression buffer */ -/* Define this string only once for all macro envocations */ +/* Define this string only once for all macro invocations */ static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n"; -static char szVersion[] = PPP_VERSION; - -#ifdef NEW_SKBUFF -static struct protocol proto_ppp; -#endif +static char szVersion[] = PPP_VERSION; /* * Information for the protocol decoder */ -typedef int (*pfn_proto) (struct ppp *, u_short, u_char *, int); +typedef int (*pfn_proto) (struct ppp *, __u16, __u8 *, int); typedef struct ppp_proto_struct { int proto; @@ -327,24 +311,16 @@ typedef struct ppp_proto_struct { static ppp_proto_type proto_list[] = { - { PPP_IP, rcv_proto_ip }, - { PPP_IPX, rcv_proto_ipx }, - { PPP_VJC_COMP, rcv_proto_vjc_comp }, + { PPP_IP, rcv_proto_ip }, + { PPP_IPX, rcv_proto_ipx }, + { PPP_VJC_COMP, rcv_proto_vjc_comp }, { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp }, - { PPP_LQR, rcv_proto_lqr }, - { PPP_CCP, rcv_proto_ccp }, - { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */ + { PPP_LQR, rcv_proto_lqr }, + { PPP_CCP, rcv_proto_ccp }, + { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */ }; -/* - * Values for FCS calculations. - */ - -#define PPP_INITFCS 0xffff /* Initial FCS value */ -#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ -#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_crc16_table[((fcs) ^ (c)) & 0xff]) - -unsigned short ppp_crc16_table[256] = +__u16 ppp_crc16_table[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, @@ -381,7 +357,7 @@ unsigned short ppp_crc16_table[256] = }; #ifdef CHECK_CHARACTERS -static unsigned paritytab[8] = +static __u32 paritytab[8] = { 0x96696996, 0x69969669, 0x69969669, 0x96696996, 0x69969669, 0x96696996, 0x96696996, 0x69969669 @@ -389,11 +365,11 @@ static unsigned paritytab[8] = #endif /* local function to store a value into the LQR frame */ -extern inline u_char * store_long (register u_char *p, register int value) { - *p++ = (u_char) (value >> 24); - *p++ = (u_char) (value >> 16); - *p++ = (u_char) (value >> 8); - *p++ = (u_char) value; +extern inline __u8 * store_long (register __u8 *p, register int value) { + *p++ = (__u8) (value >> 24); + *p++ = (__u8) (value >> 16); + *p++ = (__u8) (value >> 8); + *p++ = (__u8) value; return p; } @@ -413,42 +389,18 @@ ppp_first_time (void) int status; printk (KERN_INFO - "PPP: version %s (dynamic channel allocation)" -#ifdef NEW_SKBUFF - " NEW_SKBUFF" -#endif + "PPP: version %s (demand dialling)" "\n", szVersion); -#ifndef MODULE /* slhc module logic has its own copyright announcment */ +#ifndef MODULE /* slhc module logic has its own copyright announcement */ printk (KERN_INFO "TCP compression code copyright 1989 Regents of the " "University of California\n"); #endif - - printk (KERN_INFO - "PPP Dynamic channel allocation code copyright 1995 " - "Caldera, Inc.\n"); -/* - * Register the protocol for the device - */ - -#ifdef NEW_SKBUFF - memset (&proto_ppp, 0, sizeof (proto_ppp)); - - proto_ppp.name = "PPP"; - proto_ppp.output = ppp_dev_output; - proto_ppp.input = ppp_dev_input; - proto_ppp.bh_input = ppp_dev_input; - proto_ppp.control_event = default_protocol_control; - proto_ppp.get_binding = ppp_dev_getkey; - proto_ppp.header_space = PPP_REQUESTED_HDR_LEN; - - protocol_register(&proto_ppp); -#endif /* - * Register the tty dicipline - */ + * Register the tty discipline + */ (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc)); ppp_ldisc.magic = TTY_LDISC_MAGIC; ppp_ldisc.open = ppp_tty_open; @@ -456,11 +408,15 @@ ppp_first_time (void) ppp_ldisc.read = ppp_tty_read; ppp_ldisc.write = ppp_tty_write; ppp_ldisc.ioctl = ppp_tty_ioctl; +#if LINUX_VERSION_CODE < VERSION(2,1,23) ppp_ldisc.select = ppp_tty_select; +#else + ppp_ldisc.poll = ppp_tty_poll; +#endif ppp_ldisc.receive_room = ppp_tty_room; ppp_ldisc.receive_buf = ppp_tty_receive; ppp_ldisc.write_wakeup = ppp_tty_wakeup; - + status = tty_register_ldisc (N_PPP, &ppp_ldisc); if (status == 0) printk (KERN_INFO "PPP line discipline registered.\n"); @@ -479,38 +435,42 @@ ppp_first_time (void) static int ppp_init_dev (struct device *dev) { - int indx; -#ifdef NEW_SKBUFF - dev->default_protocol = &proto_ppp; /* Our protocol layer is PPP */ -#else +#if LINUX_VERSION_CODE < VERSION(2,1,15) dev->hard_header = ppp_dev_header; -#if USE_SKB_PROTOCOL == 0 - dev->type_trans = ppp_dev_type; -#endif dev->rebuild_header = ppp_dev_rebuild; - dev->hard_header_len = PPP_REQUESTED_HDR_LEN; #endif + dev->hard_header_len = PPP_HDRLEN; + /* device INFO */ - dev->mtu = PPP_MTU; + dev->mtu = PPP_MTU; dev->hard_start_xmit = ppp_dev_xmit; - dev->open = ppp_dev_open; - dev->stop = ppp_dev_close; - dev->get_stats = ppp_dev_stats; - dev->do_ioctl = ppp_dev_ioctl; - dev->addr_len = 0; - dev->type = ARPHRD_PPP; + dev->open = ppp_dev_open; + dev->stop = ppp_dev_close; + dev->get_stats = ppp_dev_stats; + dev->do_ioctl = ppp_dev_ioctl; + dev->addr_len = 0; + dev->tx_queue_len = 10; + dev->type = ARPHRD_PPP; + +#if LINUX_VERSION_CODE < VERSION(2,1,20) + { + int indx; - for (indx = 0; indx < DEV_NUMBUFFS; indx++) - skb_queue_head_init (&dev->buffs[indx]); + for (indx = 0; indx < DEV_NUMBUFFS; indx++) + skb_queue_head_init (&dev->buffs[indx]); + } +#else + dev_init_buffers(dev); +#endif /* New-style flags */ - dev->flags = IFF_POINTOPOINT; - dev->family = AF_INET; - dev->pa_addr = 0; + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->family = AF_INET; + dev->pa_addr = 0; dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; /* sizeof (unsigned long) */ + dev->pa_mask = 0; + dev->pa_alen = 4; /* sizeof (__u32) */ return 0; } @@ -535,27 +495,26 @@ ppp_init_ctrl_blk (register struct ppp *ppp) ppp->xmit_async_map[3] = 0x60000000; ppp->recv_async_map = 0x00000000; - ppp->rbuf = NULL; - ppp->wbuf = NULL; - ppp->ubuf = NULL; - ppp->cbuf = NULL; - ppp->slcomp = NULL; - ppp->read_wait = NULL; + ppp->rbuf = NULL; + ppp->wbuf = NULL; + ppp->ubuf = NULL; + ppp->cbuf = NULL; + ppp->slcomp = NULL; + ppp->read_wait = NULL; ppp->write_wait = NULL; - ppp->last_xmit = jiffies - flag_time; + ppp->last_xmit = jiffies - flag_time; + ppp->last_recv = jiffies; /* clear statistics */ - memset (&ppp->stats, '\0', sizeof (struct pppstat)); - - /* Reset the demand dial information */ - ppp->ddinfo.xmit_idle= /* time since last NP packet sent */ - ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */ + memset(&ppp->stats, 0, sizeof (struct pppstat)); + memset(&ppp->estats, 0, sizeof(ppp->estats)); /* PPP compression data */ ppp->sc_xc_state = ppp->sc_rc_state = NULL; } +#if LINUX_VERSION_CODE < VERSION(2,1,18) static struct symbol_table ppp_syms = { #include X(ppp_register_compressor), @@ -563,6 +522,11 @@ static struct symbol_table ppp_syms = { X(ppp_crc16_table), #include }; +#else +EXPORT_SYMBOL(ppp_register_compressor); +EXPORT_SYMBOL(ppp_unregister_compressor); +EXPORT_SYMBOL(ppp_crc16_table); +#endif /* called at boot/load time for each ppp device defined in the kernel */ @@ -575,16 +539,26 @@ ppp_init (struct device *dev) if (first_time) { first_time = 0; - answer = ppp_first_time(); + answer = ppp_first_time(); +#if LINUX_VERSION_CODE < VERSION(2,1,18) if (answer == 0) (void) register_symtab (&ppp_syms); +#endif } if (answer == 0) - answer = -ENODEV; + answer = -ENODEV; return answer; } #endif +#define BUFFER_MAGIC 0x1d10 +#define CHECK_BUF_MAGIC(buf) do { \ + if (buf->magic != BUFFER_MAGIC) { \ + printk(KERN_WARNING "bad magic for ppp buffer %p at %s:%d\n", \ + buf, __FILE__, __LINE__); \ + } \ +} while (0) + /* * Routine to allocate a buffer for later use by the driver. */ @@ -605,6 +579,7 @@ ppp_alloc_buf (int size, int type) buf->head = 0; buf->tail = 0; buf->fcs = PPP_INITFCS; + buf->magic = BUFFER_MAGIC; } return (buf); } @@ -616,8 +591,10 @@ ppp_alloc_buf (int size, int type) static void ppp_free_buf (struct ppp_buffer *ptr) { - if (ptr != NULL) + if (ptr != NULL) { + CHECK_BUF_MAGIC(ptr); kfree (ptr); + } } /* @@ -627,19 +604,18 @@ ppp_free_buf (struct ppp_buffer *ptr) extern inline int lock_buffer (register struct ppp_buffer *buf) { - register int state; - int flags; + unsigned long state; + unsigned long flags; /* * Save the current state and if free then set it to the "busy" state */ + CHECK_BUF_MAGIC(buf); save_flags (flags); cli (); state = buf->locked; if (state == 0) buf->locked = 2; -/* - * Restore the flags and return the previous state. 0 implies success. - */ + restore_flags (flags); return (state); } @@ -654,6 +630,7 @@ static int ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) { struct device *dev; + unsigned long flags; struct ppp_buffer *new_rbuf; struct ppp_buffer *new_wbuf; @@ -669,9 +646,13 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) /* * Allocate the buffer from the kernel for the data */ + CHECK_PPP(0); dev = ppp2dev (ppp); + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: changedmtu %d %d\n", ppp->name, + new_mtu, new_mru); mru = new_mru; - /* allow for possible escapement of every character */ + /* allow for possible escaping of every character */ mtu = (new_mtu * 2) + 20; /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */ @@ -679,15 +660,11 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) mru = PPP_MRU; mru += 10; - - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n", - dev->name, new_mtu, new_mru); - new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR); + new_wbuf = ppp_alloc_buf (mtu+PPP_HDRLEN, BUFFER_TYPE_DEV_WR); new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR); new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD); - new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN, BUFFER_TYPE_VJ); + new_cbuf = ppp_alloc_buf (mru+PPP_HDRLEN, BUFFER_TYPE_VJ); /* * If the buffers failed to allocate then complain and release the partial * allocations. @@ -707,6 +684,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) /* * Update the pointers to the new buffer structures. */ + save_flags(flags); cli (); old_wbuf = ppp->wbuf; old_rbuf = ppp->rbuf; @@ -718,12 +696,15 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) ppp->cbuf = new_cbuf; ppp->tbuf = new_tbuf; - ppp->rbuf->size -= 80; /* reserve space for vj header expansion */ + if (old_wbuf) + new_wbuf->locked = old_wbuf->locked; + + ppp->rbuf->size -= 80; /* reserve space for vj header expansion */ - dev->mem_start = (unsigned long) buf_base (new_wbuf); - dev->mem_end = (unsigned long) (dev->mem_start + mtu); + dev->mem_start = (unsigned long) buf_base (new_wbuf); + dev->mem_end = (unsigned long) (dev->mem_start + mtu); dev->rmem_start = (unsigned long) buf_base (new_rbuf); - dev->rmem_end = (unsigned long) (dev->rmem_start + mru); + dev->rmem_end = (unsigned long) (dev->rmem_start + mru); /* * Update the parameters for the new buffer sizes */ @@ -739,9 +720,9 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) ppp->xbuf = NULL; ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - ppp->flags &= ~SC_XMIT_BUSY; + ppp->flags &= ~SC_XMIT_BUSY; - sti (); + restore_flags(flags); /* * Release old buffer pointers */ @@ -759,6 +740,14 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) static void ppp_ccp_closed (struct ppp *ppp) { + unsigned long flags; + + save_flags(flags); + cli(); + ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); + restore_flags(flags); + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: ccp closed\n", ppp->name); if (ppp->sc_xc_state) { (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state); ppp->sc_xc_state = NULL; @@ -783,17 +772,25 @@ ppp_release (struct ppp *ppp) struct tty_struct *tty; struct device *dev; + CHECK_PPP_MAGIC(ppp); tty = ppp2tty (ppp); dev = ppp2dev (ppp); + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s released\n", ppp->name); + ppp_ccp_closed (ppp); + /* Ensure that the pppd process is not hanging on select()/poll() */ + wake_up_interruptible (&ppp->read_wait); + wake_up_interruptible (&ppp->write_wait); + if (tty != NULL && tty->disc_data == ppp) tty->disc_data = NULL; /* Break the tty->ppp link */ if (dev && dev->flags & IFF_UP) { + dev->flags &= ~IFF_UP; /* prevent recursion */ dev_close (dev); /* close the device properly */ - dev->flags = 0; /* prevent recursion */ } ppp_free_buf (ppp->rbuf); @@ -818,12 +815,14 @@ ppp_release (struct ppp *ppp) ppp->inuse = 0; ppp->tty = NULL; + ppp->backup_tty = NULL; } /* - * Device callback. + * TTY callback. * - * Called when the PPP device goes down in response to an ifconfig request. + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. */ static void @@ -836,11 +835,21 @@ ppp_tty_close (struct tty_struct *tty) if (ppp->flags & SC_DEBUG) printk (KERN_WARNING "ppp: trying to close unopened tty!\n"); + return; + } + CHECK_PPP_VOID(); + tty->disc_data = NULL; + if (tty == ppp->backup_tty) + ppp->backup_tty = 0; + if (tty != ppp->tty) + return; + if (ppp->backup_tty) { + ppp->tty = ppp->backup_tty; } else { - CHECK_PPP_VOID(); + ppp->sc_xfer = 0; if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp: channel %s closing.\n", - ppp2dev(ppp) -> name); + ppp2dev(ppp)->name); ppp_release (ppp); MOD_DEC_USE_COUNT; } @@ -857,6 +866,7 @@ static int ppp_tty_open (struct tty_struct *tty) { struct ppp *ppp = tty2ppp (tty); + int indx; /* * There should not be an existing table for this slot. */ @@ -871,62 +881,76 @@ ppp_tty_open (struct tty_struct *tty) /* * Allocate the structure from the system */ - ppp = ppp_alloc(); - if (ppp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_open: couldn't allocate ppp channel\n"); - return -ENFILE; - } + ppp = ppp_find(current->pid); + if (ppp != NULL) { + /* + * If we are taking over a ppp unit which is currently + * connected to a loopback pty, there's not much to do. + */ + CHECK_PPP(-EINVAL); + tty->disc_data = ppp; + ppp->tty = tty; + + } else { + ppp = ppp_alloc(); + if (ppp == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR "ppp_alloc failed\n"); + return -ENFILE; + } /* * Initialize the control block */ - ppp_init_ctrl_blk (ppp); - ppp->tty = tty; - tty->disc_data = ppp; -/* - * Flush any pending characters in the driver and discipline. - */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer (tty); + ppp_init_ctrl_blk (ppp); + tty->disc_data = ppp; + ppp->tty = tty; /* * Allocate space for the default VJ header compression slots */ - ppp->slcomp = slhc_init (16, 16); - if (ppp->slcomp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_open: no space for compression buffers!\n"); - ppp_release (ppp); - return -ENOMEM; - } + ppp->slcomp = slhc_init (16, 16); + if (ppp->slcomp == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR "ppp_tty_open: " + "no space for compression buffers!\n"); + ppp_release (ppp); + return -ENOMEM; + } /* * Allocate space for the MTU and MRU buffers */ - if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) { - ppp_release (ppp); - return -ENOMEM; - } + if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) { + ppp_release (ppp); + return -ENOMEM; + } /* * Allocate space for a user level buffer */ - ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD); - if (ppp->ubuf == NULL) { + ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD); + if (ppp->ubuf == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR "ppp_tty_open: " + "no space for user receive buffer\n"); + ppp_release (ppp); + return -ENOMEM; + } + if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_open: no space for user receive buffer\n"); - ppp_release (ppp); - return -ENOMEM; - } + printk (KERN_INFO "ppp: channel %s open\n", + ppp2dev(ppp)->name); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO "ppp: channel %s open\n", - ppp2dev(ppp)->name); + for (indx = 0; indx < NUM_NP; ++indx) + ppp->sc_npmode[indx] = NPMODE_PASS; + + MOD_INC_USE_COUNT; + } +/* + * Flush any pending characters in the driver and discipline. + */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer (tty); - MOD_INC_USE_COUNT; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer (tty); return (ppp->line); } @@ -946,16 +970,21 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, struct ppp_buffer *xbuf) { register int count, actual; + unsigned long flags; + + CHECK_PPP_VOID(); + CHECK_BUF_MAGIC(xbuf); /* * Prevent re-entrancy by ensuring that this routine is called only once. */ + save_flags(flags); cli (); if (ppp->flags & SC_XMIT_BUSY) { - sti (); + restore_flags(flags); return; } ppp->flags |= SC_XMIT_BUSY; - sti (); + restore_flags(flags); /* * Send the next block of data to the modem */ @@ -967,7 +996,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, * This could occur should the carrier drop. */ if (actual < 0) { - ppp->stats.ppp_oerrors++; + ppp->stats.ppp_oerrors++; actual = count; } else ppp->bytes_sent += actual; @@ -990,11 +1019,8 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, * If the completed buffer came from the device write, then complete the * transmission block. */ - if (ppp2dev (ppp) -> flags & IFF_UP) { - if (xbuf->type == BUFFER_TYPE_DEV_WR) - ppp2dev (ppp)->tbusy = 0; - mark_bh (NET_BH); - } + ppp2dev (ppp)->tbusy = 0; + mark_bh (NET_BH); /* * Wake up the transmission queue for all completion events. */ @@ -1002,6 +1028,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, /* * Look at the priorities. Choose a daemon write over the device driver. */ + save_flags(flags); cli(); xbuf = ppp->s1buf; ppp->s1buf = NULL; @@ -1009,21 +1036,25 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, xbuf = ppp->s2buf; ppp->s2buf = NULL; } - sti(); /* * If there is a pending buffer then transmit it now. */ if (xbuf != NULL) { ppp->flags &= ~SC_XMIT_BUSY; ppp_kick_tty (ppp, xbuf); + restore_flags(flags); return; } + restore_flags(flags); } } /* * Clear the re-entry flag */ + save_flags(flags); /* &=~ may not be atomic */ + cli (); ppp->flags &= ~SC_XMIT_BUSY; + restore_flags(flags); } /* @@ -1043,9 +1074,12 @@ ppp_tty_wakeup (struct tty_struct *tty) if (!ppp) return; + CHECK_PPP_VOID(); - if (ppp->magic != PPP_MAGIC) + if (tty != ppp->tty) { + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); return; + } /* * Ensure that there is a transmission pending. Clear the re-entry flag if * there is no pending buffer. Otherwise, send the buffer. @@ -1066,7 +1100,10 @@ ppp_tty_wakeup (struct tty_struct *tty) static void ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf) { - register int flags; + unsigned long flags; + + CHECK_PPP_VOID(); + CHECK_BUF_MAGIC(xbuf); /* * Hold interrupts. */ @@ -1075,8 +1112,8 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf) /* * Control the flags which are best performed with the interrupts masked. */ - xbuf->locked = 1; - xbuf->tail = 0; + xbuf->locked = 1; + xbuf->tail = 0; /* * If the transmitter is busy then place the buffer on the appropriate * priority queue. @@ -1092,9 +1129,9 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf) /* * If the transmitter is not busy then this is the highest priority frame */ - ppp->flags &= ~SC_XMIT_BUSY; + ppp->flags &= ~SC_XMIT_BUSY; ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - ppp->xbuf = xbuf; + ppp->xbuf = xbuf; restore_flags (flags); /* * Do the "tty wakeup_code" to actually send this buffer. @@ -1125,20 +1162,25 @@ ppp_tty_room (struct tty_struct *tty) /* * Callback function when data is available at the tty driver. */ - static void -ppp_tty_receive (struct tty_struct *tty, const u_char * data, +ppp_tty_receive (struct tty_struct *tty, const __u8 * data, char *flags, int count) { register struct ppp *ppp = tty2ppp (tty); register struct ppp_buffer *buf = NULL; - u_char chr; + __u8 chr; + + if (ppp != 0) + CHECK_PPP_VOID(); + /* + * This can happen if stuff comes in on the backup tty. + */ + if (ppp == 0 || tty != ppp->tty) + return; /* * Fetch the pointer to the buffer. Be careful about race conditions. */ - if (ppp != NULL) - buf = ppp->rbuf; - + buf = ppp->rbuf; if (buf == NULL) return; /* @@ -1148,7 +1190,7 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, if (ppp->magic != PPP_MAGIC) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG - "PPP: handler called but couldn't find " + "PPP: tty_receive called but couldn't find " "PPP struct.\n"); return; } @@ -1158,6 +1200,7 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, */ if (ppp->flags & SC_LOG_RAWIN) ppp_print_buffer ("receive buffer", data, count); + /* * Collect the character and error condition for the character. Set the toss * flag for the first character error. @@ -1166,16 +1209,25 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, ppp->bytes_rcvd++; chr = *data++; if (flags) { - if (*flags && ppp->toss == 0) + if (*flags && ppp->toss == 0) { ppp->toss = *flags; + switch (ppp->toss) { + case TTY_OVERRUN: + ++ppp->estats.rx_fifo_errors; + break; + case TTY_FRAME: + case TTY_BREAK: + ++ppp->estats.rx_frame_errors; + break; + } + } ++flags; } + /* - * Set the flags for 8 data bits and no parity. - * - * Actually, it sets the flags for d7 being 0/1 and parity being even/odd - * so that the normal processing would have all flags set at the end of the - * session. A missing flag bit would denote an error condition. + * Set the flags for d7 being 0/1 and parity being even/odd so that + * the normal processing would have all flags set at the end of the + * session. A missing flag bit indicates an error condition. */ #ifdef CHECK_CHARACTERS @@ -1190,13 +1242,9 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, ppp->flags |= SC_RCV_EVNP; #endif /* - * Branch on the character. Process the escape character. The sequence ESC ESC - * is defined to be ESC. + * Branch on the character. */ switch (chr) { - case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */ - ppp->escape = PPP_TRANS; - break; /* * FLAG. This is the end of the block. If the block terminated by ESC FLAG, * then the block is to be ignored. In addition, characters before the very @@ -1210,8 +1258,8 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, * Process frames which are not to be ignored. If the processing failed, * then clean up the VJ tables. */ - if ((ppp->toss & 0x80) != 0 || - ppp_doframe (ppp) == 0) { + if (ppp_doframe (ppp) == 0) { + ++ppp->stats.ppp_ierrors; slhc_toss (ppp->slcomp); } /* @@ -1227,17 +1275,39 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, * receive mask then ignore the character. */ default: + /* If we're tossing, look no further. */ + if (ppp->toss != 0) + break; + + /* If this is a control char to be ignored, do so */ if (in_rmap (ppp, chr)) break; -/* - * Adjust the character and if the frame is to be discarded then simply - * ignore the character until the ending FLAG is received. - */ - chr ^= ppp->escape; - ppp->escape = 0; - if (ppp->toss != 0) + /* + * Modify the next character if preceded by escape. + * The escape character (0x7d) could be an escaped + * 0x5d, if it follows an escape :-) + */ + if (ppp->escape) { + chr ^= PPP_TRANS; + ppp->escape = 0; + } else if (chr == PPP_ESCAPE) { + ppp->escape = PPP_TRANS; break; + } + + /* + * Decompress A/C and protocol compression here. + */ + if (buf->count == 0 && chr != PPP_ALLSTATIONS) { + buf_base(buf)[0] = PPP_ALLSTATIONS; + buf_base(buf)[1] = PPP_UI; + buf->count = 2; + } + if (buf->count == 2 && (chr & 1) != 0) { + buf_base(buf)[2] = 0; + buf->count = 3; + } /* * If the count sent is within reason then store the character, bump the * count, and update the FCS for the character. @@ -1251,85 +1321,242 @@ ppp_tty_receive (struct tty_struct *tty, const u_char * data, * The peer sent too much data. Set the flags to discard the current frame * and wait for the re-synchronization FLAG to be sent. */ - ppp->stats.ppp_ierrors++; + ++ppp->estats.rx_length_errors; ppp->toss |= 0xC0; break; } } } -/* - * Put the input frame into the networking system for the indicated protocol - */ +/* on entry, a received frame is in ppp->rbuf.bufr + check it and dispose as appropriate */ static int -ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count) +ppp_doframe (struct ppp *ppp) { - sk_buff *skb = dev_alloc_skb (count); + __u8 *data = buf_base (ppp->rbuf); + int count = ppp->rbuf->count; + int proto; + int new_count; + __u8 *new_data; + + CHECK_PPP(0); + CHECK_BUF_MAGIC(ppp->rbuf); + /* - * Generate a skb buffer for the new frame. + * If there is a pending error from the receiver then log it and discard + * the damaged frame. */ - if (skb == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_do_ip: packet dropped on %s (no memory)!\n", - ppp2dev (ppp)->name); + if (ppp->toss) { + if ((ppp->flags & SC_DEBUG) && count > 0) + printk (KERN_DEBUG + "ppp_toss: tossing frame, reason = %x\n", + ppp->toss); return 0; } /* - * Move the received data from the input buffer to the skb buffer. + * An empty frame is ignored. This occurs if the FLAG sequence precedes and + * follows each frame. */ - skb->dev = ppp2dev (ppp); /* We are the device */ -#if USE_SKB_PROTOCOL == 0 - skb->len = count; -#else - skb->protocol = proto; - skb->mac.raw = skb_data(skb); -#endif - memcpy (skb_put(skb,count), data, count); /* move data */ + if (count == 0) + return 1; /* - * Tag the frame and kick it to the proper receive routine + * Generate an error if the frame is too small. */ - skb->free = 1; - ppp->ddinfo.recv_idle = jiffies; - netif_rx (skb); - return 1; -} - + if (count < PPP_HDRLEN + 2) { + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp: got runt ppp frame, %d chars\n", count); + ++ppp->estats.rx_length_errors; + return 0; + } /* - * Process the receipt of an IP frame + * Verify the CRC of the frame and discard the CRC characters from the + * end of the buffer. */ - -static int -rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count) -{ - if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0)) - return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count); - return 0; -} - + if (ppp->rbuf->fcs != PPP_GOODFCS) { + if (ppp->flags & SC_DEBUG) { + printk (KERN_DEBUG + "ppp: frame with bad fcs, length = %d\n", + count); + ppp_print_buffer("bad frame", data, count); + } + ++ppp->estats.rx_crc_errors; + return 0; + } + count -= 2; /* ignore the fcs characters */ /* - * Process the receipt of an IPX frame + * Obtain the protocol from the frame */ - -static int -rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count) -{ -#if defined(NEW_SKBUFF) || defined(IPX_CHANGE) - if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0)) - return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count); -#endif - return 0; -} - + proto = PPP_PROTOCOL(data); /* - * Process the receipt of an VJ Compressed frame + * Process the active decompressor. */ - + if ((ppp->sc_rc_state != (void *) 0) && + (ppp->flags & SC_DECOMP_RUN) && + ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) { + if (proto == PPP_COMP) { +/* + * If the frame is compressed then decompress it. + */ + new_data = kmalloc (ppp->mru + PPP_HDRLEN, GFP_ATOMIC); + if (new_data == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_doframe: no memory\n"); + new_count = DECOMP_ERROR; + } else { + new_count = (*ppp->sc_rcomp->decompress) + (ppp->sc_rc_state, data, count, + new_data, ppp->mru + PPP_HDRLEN); + } + switch (new_count) { + default: + ppp_doframe_lower (ppp, new_data, new_count); + kfree (new_data); + return 1; + + case DECOMP_ERROR: + ppp->flags |= SC_DC_ERROR; + break; + + case DECOMP_FATALERROR: + ppp->flags |= SC_DC_FERROR; + if (ppp->flags & SC_DEBUG) + printk(KERN_ERR "ppp: fatal decomp error\n"); + break; + } +/* + * Log the error condition and discard the frame. + */ + if (new_data != 0) + kfree (new_data); + slhc_toss (ppp->slcomp); + ++ppp->stats.ppp_ierrors; + } else { +/* + * The frame is not special. Pass it through the compressor without + * actually compressing the data + */ + (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, + data, count); + } + } +/* + * Process the uncompressed frame. + */ + ppp_doframe_lower (ppp, data, count); + return 1; +} + +static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count) +{ + __u16 proto = PPP_PROTOCOL (data); + ppp_proto_type *proto_ptr; + + CHECK_PPP_VOID(); +/* + * Ignore empty frames + */ + if (count <= PPP_HDRLEN) + return; +/* + * Count the frame and print it + */ + ++ppp->stats.ppp_ipackets; + if (ppp->flags & SC_LOG_INPKT) + ppp_print_buffer ("receive frame", data, count); +/* + * Find the procedure to handle this protocol. The last one is marked + * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon. + */ + proto_ptr = proto_list; + while (proto_ptr->proto != 0 && proto_ptr->proto != proto) + ++proto_ptr; +/* + * Update the appropriate statistic counter. + */ + if ((*proto_ptr->func) (ppp, proto, + &data[PPP_HDRLEN], + count - PPP_HDRLEN)) + ppp->stats.ppp_ioctects += count; + else + ++ppp->stats.ppp_discards; +} + +/* + * Put the input frame into the networking system for the indicated protocol + */ + static int -rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto, - u_char *data, int count) +ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count) { + sk_buff *skb = dev_alloc_skb (count); +/* + * Generate a skb buffer for the new frame. + */ + if (skb == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_do_ip: packet dropped on %s (no memory)!\n", + ppp2dev (ppp)->name); + return 0; + } +/* + * Move the received data from the input buffer to the skb buffer. + */ + skb->dev = ppp2dev (ppp); /* We are the device */ + skb->protocol = proto; + skb->mac.raw = skb_data(skb); + memcpy (skb_put(skb,count), data, count); /* move data */ +/* + * Tag the frame and kick it to the proper receive routine + */ +#if LINUX_VERSION_CODE < VERSION(2,1,15) + skb->free = 1; +#endif + + ppp->last_recv = jiffies; + netif_rx (skb); + return 1; +} + +/* + * Process the receipt of an IP frame + */ + +static int +rcv_proto_ip (struct ppp *ppp, __u16 proto, __u8 * data, int count) +{ + CHECK_PPP(0); + if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0)) + if (ppp->sc_npmode[NP_IP] == NPMODE_PASS) + return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count); + return 0; +} + +/* + * Process the receipt of an IPX frame + */ + +static int +rcv_proto_ipx (struct ppp *ppp, __u16 proto, __u8 * data, int count) +{ + CHECK_PPP(0); + if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0)) + return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count); + return 0; +} + +/* + * Process the receipt of an VJ Compressed frame + */ + +static int +rcv_proto_vjc_comp (struct ppp *ppp, __u16 proto, + __u8 *data, int count) +{ + CHECK_PPP(0); if ((ppp->flags & SC_REJ_COMP_TCP) == 0) { int new_count = slhc_uncompress (ppp->slcomp, data, count); if (new_count >= 0) { @@ -1347,9 +1574,10 @@ rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto, */ static int -rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto, - u_char *data, int count) +rcv_proto_vjc_uncomp (struct ppp *ppp, __u16 proto, + __u8 *data, int count) { + CHECK_PPP(0); if ((ppp->flags & SC_REJ_COMP_TCP) == 0) { if (slhc_remember (ppp->slcomp, data, count) > 0) { return rcv_proto_ip (ppp, PPP_IP, data, count); @@ -1366,29 +1594,31 @@ rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto, */ static int -rcv_proto_unknown (struct ppp *ppp, unsigned short proto, - u_char *data, int len) +rcv_proto_unknown (struct ppp *ppp, __u16 proto, + __u8 *data, int len) { int totlen; register int current_idx; #define PUTC(c) \ { \ - buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \ + buf_base (ppp->ubuf) [current_idx++] = (__u8) (c); \ current_idx &= ppp->ubuf->size; \ if (current_idx == ppp->ubuf->tail) \ goto failure; \ } + CHECK_PPP(0); /* * The total length includes the protocol data. * Lock the user information buffer. */ - if (set_bit (0, &ppp->ubuf->locked)) { + if (test_and_set_bit (0, &ppp->ubuf->locked)) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG - "ppp_us_queue: can't get lock\n"); + "ppp: rcv_proto_unknown: can't get lock\n"); } else { + CHECK_BUF_MAGIC(ppp->ubuf); current_idx = ppp->ubuf->head; /* * Insert the buffer length (not counted), the protocol, and the data @@ -1416,11 +1646,6 @@ rcv_proto_unknown (struct ppp *ppp, unsigned short proto, if (ppp->tty->fasync != NULL) kill_fasync (ppp->tty->fasync, SIGIO); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp: successfully queued %d bytes, flags = %x\n", - len + 2, ppp->flags); - return 1; /* * The buffer is full. Unlock the header @@ -1428,16 +1653,15 @@ rcv_proto_unknown (struct ppp *ppp, unsigned short proto, failure: clear_bit (0, &ppp->ubuf->locked); if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_us_queue: ran out of buffer space.\n"); + printk (KERN_DEBUG + "ppp: rcv_proto_unknown: buffer overflow\n"); } /* * Discard the frame. There are no takers for this protocol. */ if (ppp->flags & SC_DEBUG) - printk (KERN_WARNING - "ppp: dropping packet on the floor.\n"); - slhc_toss (ppp->slcomp); + printk (KERN_DEBUG + "ppp: rcv_proto_unknown: dropping packet\n"); return 0; } @@ -1449,15 +1673,17 @@ failure: * immediate or the compressors will become confused on the peer. */ -static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd) +static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd) { int slen = CCP_LENGTH(dp); - u_char *opt = dp + CCP_HDRLEN; + __u8 *opt = dp + CCP_HDRLEN; int opt_len = slen - CCP_HDRLEN; + unsigned long flags; if (slen > len) return; + save_flags(flags); switch (CCP_CODE(dp)) { case CCP_CONFREQ: case CCP_TERMREQ: @@ -1466,6 +1692,7 @@ static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd) * CCP must be going down - disable compression */ if (ppp->flags & SC_CCP_UP) { + cli(); ppp->flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); @@ -1494,8 +1721,13 @@ static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd) opt_len, ppp2dev (ppp)->base_addr, 0, - ppp->flags)) + ppp->flags & SC_DEBUG)) { + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: comp running\n", + ppp->name); + cli(); ppp->flags |= SC_COMP_RUN; + } break; } /* @@ -1511,262 +1743,62 @@ static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd) ppp2dev (ppp)->base_addr, 0, ppp->mru, - ppp->flags)) { + ppp->flags & SC_DEBUG)) { + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: decomp running\n", + ppp->name); + cli(); ppp->flags |= SC_DECOMP_RUN; ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); } break; /* - * The protocol sequence is complete at this end + * CCP Reset-ack resets compressors and decompressors as it passes through. */ case CCP_RESETACK: if ((ppp->flags & SC_CCP_UP) == 0) break; if (!rcvd) { - if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN)) + if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN)) { (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state); + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: comp reset\n", + ppp->name); + } } else { if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) { (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state); - ppp->flags &= ~SC_DC_ERROR; + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: decomp reset\n", + ppp->name); + cli(); + ppp->flags &= ~SC_DC_ERROR; } } break; } + restore_flags(flags); } static int -rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len) +rcv_proto_ccp (struct ppp *ppp, __u16 proto, __u8 *dp, int len) { + CHECK_PPP(0); ppp_proto_ccp (ppp, dp, len, 1); return rcv_proto_unknown (ppp, proto, dp, len); } /* * Handle a LQR packet. - * - * The LQR packet is passed along to the pppd process just like any - * other PPP frame. The difference is that some processing needs to be - * performed to append the current data to the end of the frame. */ static int -rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len) +rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len) { -#if 0 /* until support is in the pppd process don't corrupt the reject. */ - register u_char *p; - if (len > 8) { - if (len < 48) - memset (&data [len], '\0', 48 - len); -/* - * Fill in the fields from the driver data - */ - p = &data [48]; - p = store_long (p, ++ppp->stats.ppp_ilqrs); - p = store_long (p, ppp->stats.ppp_ipackets); - p = store_long (p, ppp->stats.ppp_discards); - p = store_long (p, ppp->stats.ppp_ierrors); - p = store_long (p, ppp->stats.ppp_ioctects + len); - - len = 68; - } -#endif -/* - * Pass the frame to the pppd daemon. - */ return rcv_proto_unknown (ppp, proto, data, len); } -/* on entry, a received frame is in ppp->rbuf.bufr - check it and dispose as appropriate */ - -static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count) -{ - u_short proto = PPP_PROTOCOL (data); - ppp_proto_type *proto_ptr; -/* - * Ignore empty frames - */ - if (count <= 4) - return; -/* - * Count the frame and print it - */ - ++ppp->stats.ppp_ipackets; - if (ppp->flags & SC_LOG_INPKT) - ppp_print_buffer ("receive frame", data, count); -/* - * Find the procedure to handle this protocol. The last one is marked - * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon. - */ - proto_ptr = proto_list; - while (proto_ptr->proto != 0 && proto_ptr->proto != proto) - ++proto_ptr; -/* - * Update the appropriate statistic counter. - */ - if ((*proto_ptr->func) (ppp, proto, - &data[PPP_HARD_HDR_LEN], - count - PPP_HARD_HDR_LEN)) - ppp->stats.ppp_ioctects += count; - else - ++ppp->stats.ppp_discards; -} - -/* on entry, a received frame is in ppp->rbuf.bufr - check it and dispose as appropriate */ - -static int -ppp_doframe (struct ppp *ppp) -{ - u_char *data = buf_base (ppp->rbuf); - int count = ppp->rbuf->count; - int addr, ctrl, proto; - int new_count; - u_char *new_data; -/* - * If there is a pending error from the receiver then log it and discard - * the damaged frame. - */ - if (ppp->toss) { - if (ppp->flags & SC_DEBUG) - printk (KERN_WARNING - "ppp_toss: tossing frame, reason = %d\n", - ppp->toss); - ppp->stats.ppp_ierrors++; - return 0; - } -/* - * An empty frame is ignored. This occurs if the FLAG sequence precedes and - * follows each frame. - */ - if (count == 0) - return 1; -/* - * Generate an error if the frame is too small. - */ - if (count < PPP_HARD_HDR_LEN) { - if (ppp->flags & SC_DEBUG) - printk (KERN_WARNING - "ppp: got runt ppp frame, %d chars\n", count); - slhc_toss (ppp->slcomp); - ppp->stats.ppp_ierrors++; - return 1; - } -/* - * Verify the CRC of the frame and discard the CRC characters from the - * end of the buffer. - */ - if (ppp->rbuf->fcs != PPP_GOODFCS) { - if (ppp->flags & SC_DEBUG) - printk (KERN_WARNING - "ppp: frame with bad fcs, excess = %x\n", - ppp->rbuf->fcs ^ PPP_GOODFCS); - ppp->stats.ppp_ierrors++; - return 0; - } - count -= 2; /* ignore the fcs characters */ -/* - * Ignore the leading ADDRESS and CONTROL fields in the frame. - */ - addr = PPP_ALLSTATIONS; - ctrl = PPP_UI; - - if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) { - data += 2; - count -= 2; - } -/* - * Obtain the protocol from the frame - */ - proto = (u_short) *data++; - if ((proto & 1) == 0) { - proto = (proto << 8) | (u_short) *data++; - --count; - } -/* - * Rewrite the header with the full information. This may encroach upon - * the 'filler' area in the buffer header. This is the purpose for the - * filler. - */ - *(--data) = proto; - *(--data) = proto >> 8; - *(--data) = ctrl; - *(--data) = addr; - count += 3; -/* - * Process the active decompressor. - */ - if ((ppp->sc_rc_state != (void *) 0) && - (ppp->flags & SC_DECOMP_RUN) && - ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) { - if (proto == PPP_COMP) { -/* - * If the frame is compressed then decompress it. - */ - new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC); - if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_doframe: no memory\n"); - slhc_toss (ppp->slcomp); - (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, - data, - count); - return 1; - } -/* - * Decompress the frame - */ - new_count = bsd_decompress (ppp->sc_rc_state, - data, - count, - new_data, - ppp->mru + 4); - switch (new_count) { - default: - ppp_doframe_lower (ppp, new_data, new_count); - kfree (new_data); - return 1; - - case DECOMP_OK: - break; - - case DECOMP_ERROR: - ppp->flags |= SC_DC_ERROR; - break; - - case DECOMP_FATALERROR: - ppp->flags |= SC_DC_FERROR; - break; - } -/* - * Log the error condition and discard the frame. - */ - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_proto_comp: " - "decompress err %d\n", new_count); - kfree (new_data); - slhc_toss (ppp->slcomp); - return 1; - } -/* - * The frame is not special. Pass it through the compressor without - * actually compressing the data - */ - (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, - data, - count); - } -/* - * Process the uncompressed frame. - */ - ppp_doframe_lower (ppp, data, count); - return 1; -} - /************************************************************* * LINE DISCIPLINE SUPPORT * The following functions form support user programs @@ -1780,12 +1812,13 @@ ppp_doframe (struct ppp *ppp) */ static int -ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, +ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, unsigned int nr) { struct ppp *ppp = tty2ppp (tty); - u_char c; - int len, indx; + __u8 c; + int len, ret; + int error; #define GETC(c) \ { \ @@ -1794,48 +1827,48 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, } /* - * Validate the pointer to the PPP structure + * Validate the pointers */ if (!ppp) return -EIO; - if (ppp->magic != PPP_MAGIC) - return -EIO; + /* if (ppp->magic != PPP_MAGIC) + return -EIO; */ CHECK_PPP (-ENXIO); - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG - "ppp_tty_read: called buf=%p nr=%u\n", - buf, nr); +/* + * Before we attempt to write the frame to the user, ensure that the + * user has access to the pages for the total buffer length. + */ + error = verify_area (VERIFY_WRITE, buf, nr); + if (error != 0) + return (error); + /* * Acquire the read lock. */ for (;;) { ppp = tty2ppp (tty); - if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) + if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse + || tty != ppp->tty) return 0; - if (set_bit (0, &ppp->ubuf->locked) != 0) { + if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) { +#if 0 if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_read: sleeping(ubuf)\n"); - +#endif current->timeout = 0; - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; schedule (); if (current->signal & ~current->blocked) return -EINTR; continue; } -/* - * Before we attempt to write the frame to the user, ensure that the - * user has access to the pages for the total buffer length. - */ - indx = verify_area (VERIFY_WRITE, buf, nr); - if (indx != 0) - return (indx); + /* * Fetch the length of the buffer from the first two bytes. */ @@ -1846,90 +1879,81 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, len = c << 8; GETC (c); len += c; + if (len) + break; } -/* - * If there is no length then wait for the data to arrive. - */ - if (len == 0) { - /* no data */ - clear_bit (0, &ppp->ubuf->locked); - if (file->f_flags & O_NONBLOCK) { - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG - "ppp_tty_read: no data " - "(EWOULDBLOCK)\n"); - return -EWOULDBLOCK; - } - current->timeout = 0; - - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG - "ppp_tty_read: sleeping(read_wait)\n"); - interruptible_sleep_on (&ppp->read_wait); - if (current->signal & ~current->blocked) - return -EINTR; - continue; - } /* - * Reset the time of the last read operation. + * If there is no length then wait for the data to arrive. */ + /* no data */ + clear_bit (0, &ppp->ubuf->locked); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + current->timeout = 0; +#if 0 if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len); + printk (KERN_DEBUG + "ppp_tty_read: sleeping(read_wait)\n"); +#endif + interruptible_sleep_on (&ppp->read_wait); + if (current->signal & ~current->blocked) + return -EINTR; + } + /* * Ensure that the frame will fit within the caller's buffer. If not, then - * discard the frame from the input buffer and return an error to the caller. + * discard the frame from the input buffer. */ - if (len + 2 > nr) { - /* Can't copy it, update us_rbuff_head */ + if (len + 2 > nr) { + /* Can't copy it, update us_rbuff_head */ - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG "ppp: read of %u bytes too small for %d " "frame\n", nr, len + 2); - ppp->ubuf->tail += len; - ppp->ubuf->tail &= ppp->ubuf->size; - clear_bit (0, &ppp->ubuf->locked); - ppp->stats.ppp_ierrors++; - return -EOVERFLOW; - } -/* - * Before we attempt to write the frame to the user, ensure that the - * page tables are proper. - */ - indx = verify_area (VERIFY_WRITE, buf, len + 2); - if (indx != 0) { - ppp->ubuf->tail += len; - ppp->ubuf->tail &= ppp->ubuf->size; - clear_bit (0, &ppp->ubuf->locked); - return (indx); - } + ppp->stats.ppp_ierrors++; + error = -EOVERFLOW; + goto out; + } + /* * Fake the insertion of the ADDRESS and CONTROL information because these * were not saved in the buffer. */ - put_byte_user (PPP_ALLSTATIONS, buf++); - put_byte_user (PPP_UI, buf++); + PUT_USER (error, (u_char) PPP_ALLSTATIONS, buf); + if (error) + goto out; + ++buf; + PUT_USER (error, (u_char) PPP_UI, buf); + if (error) + goto out; + ++buf; - indx = len; /* * Copy the received data from the buffer to the caller's area. */ - while (indx-- > 0) { - GETC (c); - put_byte_user (c, buf); - ++buf; - } -/* - * Release the lock and return the character count in the buffer area. - */ - clear_bit (0, &ppp->ubuf->locked); - len += 2; /* Account for ADDRESS and CONTROL bytes */ - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG - "ppp_tty_read: passing %d bytes up\n", len); - return len; + ret = len + 2; /* Account for ADDRESS and CONTROL bytes */ + while (len-- > 0) { + GETC (c); + PUT_USER (error, c, buf); + if (error) + goto out; + ++buf; } + + clear_bit (0, &ppp->ubuf->locked); +#if 0 + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG "ppp_tty_read: passing %d bytes up\n", ret); +#endif + return ret; + +out: + ppp->ubuf->tail += len; + ppp->ubuf->tail &= ppp->ubuf->size; + clear_bit (0, &ppp->ubuf->locked); + return error; #undef GETC } @@ -1939,14 +1963,14 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, extern inline void ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, - register u_char chr) + register __u8 chr) { /* * The buffer should not be full. */ if (ppp->flags & SC_DEBUG) { if ((buf->count < 0) || (buf->count > 3000)) - printk (KERN_DEBUG "ppp_stuff_char: %x %d\n", + printk (KERN_DEBUG "ppp_stuff_char: %d %x\n", (unsigned int) buf->count, (unsigned int) chr); } @@ -1965,17 +1989,23 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, } /* - * Procedure to encode the data with the proper escapement and send the + * Procedure to encode the data with the proper escaping and send the * data to the remote system. */ static void ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, - u_char *data, int count, int non_ip) + __u8 *data, int count, int non_ip) { - unsigned short int write_fcs; - int address, control; + __u16 write_fcs; + int address, control; int proto; + + CHECK_PPP_VOID(); + CHECK_BUF_MAGIC(buf); + ++ppp->stats.ppp_opackets; + ppp->stats.ppp_ooctects += count; + /* * Insert the leading FLAG character */ @@ -1984,7 +2014,7 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, if (non_ip || flag_time == 0) ins_char (buf, PPP_FLAG); else { - if (jiffies - ppp->last_xmit > flag_time) + if (jiffies - ppp->last_xmit >= flag_time) ins_char (buf, PPP_FLAG); } ppp->last_xmit = jiffies; @@ -1994,7 +2024,7 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, */ address = PPP_ADDRESS (data); control = PPP_CONTROL (data); - proto = PPP_PROTOCOL (data); + proto = PPP_PROTOCOL (data); if (address != PPP_ALLSTATIONS || control != PPP_UI || @@ -2023,26 +2053,10 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, write_fcs = buf->fcs ^ 0xFFFF; ppp_stuff_char (ppp, buf, write_fcs); ppp_stuff_char (ppp, buf, write_fcs >> 8); - - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n", - write_fcs); /* * Add the trailing flag character */ ins_char (buf, PPP_FLAG); -/* - * Print the buffer - */ - if (ppp->flags & SC_LOG_FLUSH) - ppp_print_buffer ("ppp flush", buf_base (buf), - buf->count); - else { - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG - "ppp_dev_xmit: writing %d chars\n", - buf->count); - } /* * Send the block to the tty driver. */ @@ -2051,20 +2065,23 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf, } /* - * Send an frame to the remote with the proper bsd compression. + * Compress and send an frame to the peer. * * Return 0 if frame was queued for transmission. - * 1 if frame must be re-queued for later driver support. + * 1 if frame must be re-queued for later driver support. */ static int ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, - u_char *data, int count) + __u8 *data, int count) { int proto; - int address, control; - u_char *new_data; - int new_count; + int address, control; + __u8 *new_data; + int new_count; + + CHECK_PPP(0); + CHECK_BUF_MAGIC(buf); /* * Print the buffer */ @@ -2074,7 +2091,7 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, * Determine if the frame may be compressed. Attempt to compress the * frame if possible. */ - proto = PPP_PROTOCOL (data); + proto = PPP_PROTOCOL (data); address = PPP_ADDRESS (data); control = PPP_CONTROL (data); @@ -2084,7 +2101,7 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, (control == PPP_UI) && (proto != PPP_LCP) && (proto != PPP_CCP)) { - new_data = kmalloc (count, GFP_ATOMIC); + new_data = kmalloc (ppp->mtu, GFP_ATOMIC); if (new_data == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR @@ -2092,32 +2109,20 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, return 1; } - new_count = bsd_compress (ppp->sc_xc_state, - data, - new_data, - count, - count); - - if (new_count > 0) { - ++ppp->stats.ppp_opackets; - ppp->stats.ppp_ooctects += new_count; + new_count = (*ppp->sc_xcomp->compress) + (ppp->sc_xc_state, data, new_data, count, ppp->mtu); - ppp_dev_xmit_lower (ppp, buf, new_data, - new_count, 0); + if (new_count > 0 && (ppp->flags & SC_CCP_UP)) { + ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0); kfree (new_data); return 0; } /* - * The frame could not be compressed. + * The frame could not be compressed, or it could not be sent in + * compressed form because CCP is not yet up. */ kfree (new_data); } -/* - * The frame may not be compressed. Update the statistics before the - * count field is destroyed. The frame will be transmitted. - */ - ++ppp->stats.ppp_opackets; - ppp->stats.ppp_ooctects += count; /* * Go to the escape encoding */ @@ -2130,9 +2135,9 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, */ static int -send_revise_frame (register struct ppp *ppp, u_char *data, int len) +send_revise_frame (register struct ppp *ppp, __u8 *data, int len) { - u_char *p; + __u8 *p; switch (PPP_PROTOCOL (data)) { /* @@ -2141,7 +2146,7 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len) */ case PPP_LQR: len = 48; /* total size of this frame */ - p = (u_char *) &data [40]; /* Point to last two items. */ + p = (__u8 *) &data [40]; /* Point to last two items. */ p = store_long (p, ppp->stats.ppp_opackets + 1); p = store_long (p, ppp->stats.ppp_ooctects + len); break; @@ -2150,13 +2155,11 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len) */ case PPP_CCP: ppp_proto_ccp (ppp, - data + PPP_HARD_HDR_LEN, - len - PPP_HARD_HDR_LEN, + data + PPP_HDRLEN, + len - PPP_HDRLEN, 0); break; -/* - * All other frame types - */ + default: break; } @@ -2170,14 +2173,15 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len) */ static int -ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data, +ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, unsigned int count) { struct ppp *ppp = tty2ppp (tty); - u_char *new_data; - int status; + __u8 *new_data; + int error; + /* - * Verify the pointer to the PPP data and that the tty is still in PPP mode. + * Verify the pointers. */ if (!ppp) return -EIO; @@ -2189,12 +2193,13 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data, /* * Ensure that the caller does not wish to send too much. */ - if (count > PPP_MTU) { + if (count > PPP_MTU + PPP_HDRLEN) { if (ppp->flags & SC_DEBUG) printk (KERN_WARNING "ppp_tty_write: truncating user packet " - "from %u to mtu %d\n", count, PPP_MTU); - count = PPP_MTU; + "from %u to mtu %d\n", count, + PPP_MTU + PPP_HDRLEN); + count = PPP_MTU + PPP_HDRLEN; } /* * Allocate a buffer for the data and fetch it from the user space. @@ -2206,18 +2211,29 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data, "ppp_tty_write: no memory\n"); return 0; } +/* + * Retrieve the user's buffer + */ + COPY_FROM_USER (error, new_data, data, count); + if (error) { + kfree (new_data); + return error; + } /* * lock this PPP unit so we will be the only writer; * sleep if necessary */ while (lock_buffer (ppp->tbuf) != 0) { current->timeout = 0; +#if 0 if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_write: sleeping\n"); +#endif interruptible_sleep_on (&ppp->write_wait); ppp = tty2ppp (tty); - if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) { + if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse + || tty != ppp->tty) { kfree (new_data); return 0; } @@ -2227,17 +2243,6 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data, return -EINTR; } } -/* - * Ensure that the caller's buffer is valid. - */ - status = verify_area (VERIFY_READ, data, count); - if (status != 0) { - kfree (new_data); - ppp->tbuf->locked = 0; - return status; - } - - memcpy_fromfs (new_data, data, count); /* * Change the LQR frame */ @@ -2245,7 +2250,19 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data, /* * Send the data */ - ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count); + if (PPP_PROTOCOL(new_data) == PPP_IP) { + /* + * IP frames can be sent by pppd when we're doing + * demand-dialling. We send them via ppp_dev_xmit_ip + * to make sure that VJ compression happens properly. + */ + ppp_dev_xmit_ip(ppp, ppp->tbuf, new_data + PPP_HDRLEN, + count - PPP_HDRLEN, NPMODE_PASS); + + } else { + ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count); + } + kfree (new_data); return (int) count; } @@ -2261,31 +2278,43 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) struct ppp_option_data data; int error; int nb; - u_char *ptr; - u_char ccp_option[CCP_MAX_OPTION_LENGTH]; + __u8 *ptr; + __u8 ccp_option[CCP_MAX_OPTION_LENGTH]; + unsigned long flags; + /* * Fetch the compression parameters */ - error = verify_area (VERIFY_READ, odp, sizeof (data)); - if (error == 0) { - memcpy_fromfs (&data, odp, sizeof (data)); - nb = data.length; - ptr = data.ptr; - if ((unsigned long) nb >= (unsigned long)CCP_MAX_OPTION_LENGTH) - nb = CCP_MAX_OPTION_LENGTH; - - error = verify_area (VERIFY_READ, ptr, nb); - } + COPY_FROM_USER (error, + &data, + odp, + sizeof (data)); if (error != 0) return error; - memcpy_fromfs (ccp_option, ptr, nb); + nb = data.length; + ptr = data.ptr; + if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH) + nb = CCP_MAX_OPTION_LENGTH; + + COPY_FROM_USER (error, + ccp_option, + ptr, + nb); + + if (error != 0) + return error; if (ccp_option[1] < 2) /* preliminary check on the length byte */ return (-EINVAL); - cp = find_compressor ((int) (unsigned) (unsigned char) ccp_option[0]); + save_flags(flags); + cli(); + ppp->flags &= ~(SC_COMP_RUN | SC_DECOMP_RUN); + restore_flags(flags); + + cp = find_compressor (ccp_option[0]); if (cp != (struct compressor *) 0) { /* * Found a handler for the protocol - try to allocate @@ -2296,35 +2325,41 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) if (ppp->sc_xc_state != NULL) (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); - ppp->sc_xcomp = cp; + ppp->sc_xcomp = cp; ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); if (ppp->sc_xc_state == NULL) { if (ppp->flags & SC_DEBUG) - printk("ppp%ld: comp_alloc failed\n", - ppp2dev (ppp)->base_addr); + printk(KERN_DEBUG "%s: comp_alloc failed\n", + ppp->name); error = -ENOBUFS; + } else { + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: comp_alloc -> %p\n", + ppp->name, ppp->sc_xc_state); } - ppp->flags &= ~SC_COMP_RUN; } else { if (ppp->sc_rc_state != NULL) (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); - ppp->sc_rcomp = cp; + ppp->sc_rcomp = cp; ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); if (ppp->sc_rc_state == NULL) { if (ppp->flags & SC_DEBUG) - printk("ppp%ld: decomp_alloc failed\n", - ppp2dev (ppp)->base_addr); - error = ENOBUFS; + printk(KERN_DEBUG "%s: decomp_alloc failed\n", + ppp->name); + error = -ENOBUFS; + } else { + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: decomp_alloc -> %p\n", + ppp->name, ppp->sc_rc_state); } - ppp->flags &= ~SC_DECOMP_RUN; } return (error); } if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n", - ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1], + printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n", + ppp->name, ccp_option[0], ccp_option[1], ccp_option[2], nb); return (-EINVAL); /* no handler found */ } @@ -2334,12 +2369,12 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) */ static int -ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, - unsigned long param3) +ppp_tty_ioctl (struct tty_struct *tty, struct file * file, + unsigned int param2, unsigned long param3) { struct ppp *ppp = tty2ppp (tty); register int temp_i = 0; - int error; + int error = 0; /* * Verify the status of the PPP device. */ @@ -2360,56 +2395,45 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, */ switch (param2) { case PPPIOCSMRU: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - temp_i = get_int_user ((int *) param3); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set mru to %x\n", temp_i); + GET_USER (error, temp_i, (int *) param3); + if (error != 0) + break; + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set mru to %x\n", temp_i); - if (ppp->mru != temp_i) - ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i); - } + if (ppp->mru != temp_i) + ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i); break; /* * Fetch the flags */ case PPPIOCGFLAGS: - error = verify_area (VERIFY_WRITE, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - temp_i = (ppp->flags & SC_MASK); + temp_i = (ppp->flags & SC_MASK); #ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */ - temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | - SC_RCV_ODDP | SC_RCV_EVNP; + temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | + SC_RCV_ODDP | SC_RCV_EVNP; #endif - put_long_user ((long) temp_i, param3); - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG - "ppp_tty_ioctl: get flags: addr %lx flags " - "%x\n", param3, temp_i); - } + PUT_USER (error, temp_i, (int *) param3); break; /* * Set the flags for the various options */ case PPPIOCSFLAGS: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - temp_i = get_int_user (param3) & SC_MASK; - temp_i |= (ppp->flags & ~SC_MASK); - - if ((ppp->flags & SC_CCP_OPEN) && - (temp_i & SC_CCP_OPEN) == 0) - ppp_ccp_closed (ppp); - - if ((ppp->flags | temp_i) & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set flags to %x\n", temp_i); - ppp->flags = temp_i; - } + GET_USER (error, temp_i, (int *) param3); + if (error != 0) + break; + temp_i &= SC_MASK; + temp_i |= (ppp->flags & ~SC_MASK); + + if ((ppp->flags & SC_CCP_OPEN) && + (temp_i & SC_CCP_OPEN) == 0) + ppp_ccp_closed (ppp); + + if ((ppp->flags | temp_i) & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set flags to %x\n", temp_i); + ppp->flags = temp_i; break; /* * Set the compression mode @@ -2422,182 +2446,198 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, * Retrieve the transmit async map */ case PPPIOCGASYNCMAP: - error = verify_area (VERIFY_WRITE, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - put_long_user (ppp->xmit_async_map[0], param3); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: get asyncmap: addr " - "%lx asyncmap %lx\n", - param3, - (unsigned long) ppp->xmit_async_map[0]); - } + PUT_USER (error, ppp->xmit_async_map[0], (int *) param3); break; /* * Set the transmit async map */ case PPPIOCSASYNCMAP: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - ppp->xmit_async_map[0] = get_long_user (param3); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set xmit asyncmap %lx\n", - (unsigned long) ppp->xmit_async_map[0]); - } + GET_USER (error, temp_i, (int *) param3); + if (error != 0) + break; + ppp->xmit_async_map[0] = temp_i; + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set xmit asyncmap %x\n", + ppp->xmit_async_map[0]); break; /* * Set the receive async map */ case PPPIOCSRASYNCMAP: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - ppp->recv_async_map = get_long_user (param3); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set rcv asyncmap %lx\n", - (unsigned long) ppp->recv_async_map); - } + GET_USER (error, temp_i, (int *) param3); + if (error != 0) + break; + ppp->recv_async_map = temp_i; + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set rcv asyncmap %x\n", + ppp->recv_async_map); break; /* * Obtain the unit number for this device. */ case PPPIOCGUNIT: - error = verify_area (VERIFY_WRITE, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - put_long_user (ppp2dev (ppp)->base_addr, param3); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: get unit: %ld", - ppp2dev (ppp)->base_addr); - } + PUT_USER (error, ppp2dev (ppp)->base_addr, (int *) param3); + if (error != 0) + break; + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: get unit: %ld\n", + ppp2dev (ppp)->base_addr); break; /* * Set the debug level */ case PPPIOCSDEBUG: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - temp_i = (get_int_user (param3) & 0x1F) << 16; - temp_i |= (ppp->flags & ~0x1F0000); - - if ((ppp->flags | temp_i) & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set flags to %x\n", temp_i); - ppp->flags = temp_i; - } + GET_USER (error, temp_i, (int *) param3); + if (error != 0) + break; + temp_i = (temp_i & 0x1F) << 16; + temp_i |= (ppp->flags & ~0x1F0000); + + if ((ppp->flags | temp_i) & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set flags to %x\n", temp_i); + ppp->flags = temp_i; break; /* * Get the debug level */ case PPPIOCGDEBUG: - error = verify_area (VERIFY_WRITE, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - temp_i = (ppp->flags >> 16) & 0x1F; - put_long_user ((long) temp_i, param3); - - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: get debug level %d\n", - temp_i); - } + temp_i = (ppp->flags >> 16) & 0x1F; + PUT_USER (error, temp_i, (int *) param3); break; /* * Get the times since the last send/receive frame operation */ case PPPIOCGIDLE: - error = verify_area (VERIFY_WRITE, (void *) param3, - sizeof (struct ppp_idle)); - if (error == 0) { + { struct ppp_idle cur_ddinfo; - unsigned long cur_jiffies = jiffies; /* change absolute times to relative times. */ - cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ; - cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ; - memcpy_tofs ((void *) param3, &cur_ddinfo, - sizeof (cur_ddinfo)); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: read demand dial info\n"); + cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ; + cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ; + COPY_TO_USER (error, + (void *) param3, + &cur_ddinfo, + sizeof (cur_ddinfo)); } break; /* * Retrieve the extended async map */ case PPPIOCGXASYNCMAP: - error = verify_area (VERIFY_WRITE, - (void *) param3, - sizeof (ppp->xmit_async_map)); - if (error == 0) { - memcpy_tofs ((void *) param3, - ppp->xmit_async_map, - sizeof (ppp->xmit_async_map)); - - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: get xasyncmap: addr %lx\n", - param3); - } + COPY_TO_USER (error, + (void *) param3, + ppp->xmit_async_map, + sizeof (ppp->xmit_async_map)); break; /* * Set the async extended map */ case PPPIOCSXASYNCMAP: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (ppp->xmit_async_map)); - if (error == 0) { + { __u32 temp_tbl[8]; - memcpy_fromfs (temp_tbl, (void *) param3, - sizeof (ppp->xmit_async_map)); - temp_tbl[1] = 0x00000000; + COPY_FROM_USER (error, + temp_tbl, + (void *) param3, + sizeof (temp_tbl)); + + if (error != 0) + break; + temp_tbl[1] = 0x00000000; temp_tbl[2] &= ~0x40000000; - temp_tbl[3] |= 0x60000000; + temp_tbl[3] |= 0x60000000; if ((temp_tbl[2] & temp_tbl[3]) != 0 || (temp_tbl[4] & temp_tbl[5]) != 0 || (temp_tbl[6] & temp_tbl[7]) != 0) error = -EINVAL; else { - memcpy (ppp->xmit_async_map, temp_tbl, + memcpy (ppp->xmit_async_map, + temp_tbl, sizeof (ppp->xmit_async_map)); - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set xasyncmap\n"); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set xasyncmap\n"); + } + } + break; +/* + * Set the maximum VJ header compression slot number. + */ + case PPPIOCSMAXCID: + GET_USER (error, temp_i, (int *) param3); + if (error != 0) + break; + temp_i = (temp_i & 255) + 1; + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set maxcid to %d\n", + temp_i); + if (ppp->slcomp != NULL) + slhc_free (ppp->slcomp); + ppp->slcomp = slhc_init (16, temp_i); + + if (ppp->slcomp == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp: no space for compression buffers!\n"); + ppp_release (ppp); + error = -ENOMEM; + } + break; + + case PPPIOCXFERUNIT: + ppp->backup_tty = tty; + ppp->sc_xfer = current->pid; + break; + + case PPPIOCGNPMODE: + case PPPIOCSNPMODE: + { + struct npioctl npi; + + COPY_FROM_USER (error, + &npi, + (void *) param3, + sizeof (npi)); + if (error != 0) + break; + + switch (npi.protocol) { + case PPP_IP: + npi.protocol = NP_IP; + break; + default: + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "pppioc[gs]npmode: " + "invalid proto %d\n", npi.protocol); + error = -EINVAL; + } + + if (error != 0) + break; + + if (param2 == PPPIOCGNPMODE) { + npi.mode = ppp->sc_npmode[npi.protocol]; + + COPY_TO_USER (error, + (void *) param3, + &npi, + sizeof (npi)); + break; } - } - break; -/* - * Set the maximum VJ header compression slot number. - */ - case PPPIOCSMAXCID: - error = verify_area (VERIFY_READ, (void *) param3, - sizeof (temp_i)); - if (error == 0) { - temp_i = get_int_user (param3) + 1; + + ppp->sc_npmode[npi.protocol] = npi.mode; if (ppp->flags & SC_DEBUG) - printk (KERN_INFO - "ppp_tty_ioctl: set maxcid to %d\n", - temp_i); - if (ppp->slcomp != NULL) - slhc_free (ppp->slcomp); - ppp->slcomp = slhc_init (16, temp_i); - - if (ppp->slcomp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp: no space for compression buffers!\n"); - ppp_release (ppp); - error = -ENOMEM; - } + printk(KERN_DEBUG "ppp: set np %d to %d\n", + npi.protocol, npi.mode); + ppp2dev(ppp)->tbusy = 0; + mark_bh(NET_BH); } break; /* @@ -2607,6 +2647,15 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, case TCGETA: error = n_tty_ioctl (tty, file, param2, param3); break; + + case FIONREAD: + { + int count = ppp->ubuf->tail - ppp->ubuf->head; + if (count < 0) + count += (ppp->ubuf->size + 1); + PUT_USER (error, count, (int *) param3); + } + break; /* * All other ioctl() events will come here. */ @@ -2626,9 +2675,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, /* * TTY callback. * - * Process the select() statement for the PPP device. + * Process the select() (or poll()) statement for the PPP device. */ +#if LINUX_VERSION_CODE < VERSION(2,1,23) static int ppp_tty_select (struct tty_struct *tty, struct inode *inode, struct file *filp, int sel_type, select_table * wait) @@ -2641,7 +2691,7 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, if (!ppp) return -EBADF; - if (ppp->magic != PPP_MAGIC) + if (ppp->magic != PPP_MAGIC || tty != ppp->tty) return -EBADF; CHECK_PPP (0); @@ -2651,7 +2701,7 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, */ switch (sel_type) { case SEL_IN: - if (set_bit (0, &ppp->ubuf->locked) == 0) { + if (test_and_set_bit (0, &ppp->ubuf->locked) == 0) { /* Test for the presence of data in the queue */ if (ppp->ubuf->head != ppp->ubuf->tail) { clear_bit (0, &ppp->ubuf->locked); @@ -2659,12 +2709,12 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, } clear_bit (0, &ppp->ubuf->locked); } /* fall through */ - /* +/* * Exceptions or read errors. */ case SEL_EX: /* Is this a pty link and the remote disconnected? */ - if (tty->flags & (1 << TTY_SLAVE_CLOSED)) + if (tty->flags & (1 << TTY_OTHER_CLOSED)) break; /* Is this a local link and the modem disconnected? */ @@ -2687,6 +2737,39 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, return result; } +#else /* 2.1.23 or later */ + +static unsigned int +ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait) +{ + struct ppp *ppp = tty2ppp (tty); + unsigned int mask = 0; + + if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) { + CHECK_PPP (0); + + poll_wait(&ppp->read_wait, wait); + poll_wait(&ppp->write_wait, wait); + + /* Must lock the user buffer area while checking. */ + CHECK_BUF_MAGIC(ppp->ubuf); + if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) { + if(ppp->ubuf->head != ppp->ubuf->tail) + mask |= POLLIN | POLLRDNORM; + clear_bit(0, &ppp->ubuf->locked); + } + if(tty->flags & (1 << TTY_OTHER_CLOSED)) + mask |= POLLHUP; + if(tty_hung_up_p(filp)) + mask |= POLLHUP; + if(ppp->tbuf->locked == 0) + mask |= POLLOUT | POLLWRNORM; + } + return mask; +} + +#endif + /************************************************************* * NETWORK OUTPUT * This routine accepts requests from the network layer @@ -2704,8 +2787,10 @@ ppp_dev_open (struct device *dev) { struct ppp *ppp = dev2ppp (dev); +#if 0 /* reset POINTOPOINT every time, since dev_close zaps it! */ - dev->flags |= IFF_POINTOPOINT; + dev->flags |= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; +#endif if (ppp2tty (ppp) == NULL) { if (ppp->flags & SC_DEBUG) @@ -2734,10 +2819,6 @@ ppp_dev_close (struct device *dev) struct ppp *ppp = dev2ppp (dev); if (ppp2tty (ppp) == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp: %s not connected to a TTY! can't go down!\n", - dev->name); return -ENXIO; } /* @@ -2759,20 +2840,16 @@ ppp_dev_close (struct device *dev) static int ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr) { - int error; - int len; - char *result; -/* - * Must have write access to the buffer. - */ - result = (char *) ifr->ifr_ifru.ifru_data; - len = strlen (szVersion) + 1; - error = verify_area (VERIFY_WRITE, result, len); + int error; + char *result = (char *) ifr->ifr_ifru.ifru_data; + int len = strlen (szVersion) + 1; /* * Move the version data */ - if (error == 0) - memcpy_tofs (result, szVersion, len); + COPY_TO_USER (error, + result, + szVersion, + len); return error; } @@ -2786,19 +2863,12 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev) { struct ppp_stats *result, temp; int error; -/* - * Must have write access to the buffer. - */ - result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; - error = verify_area (VERIFY_WRITE, - result, - sizeof (temp)); /* * Supply the information for the caller. First move the version data * then move the ppp stats; and finally the vj stats. */ memset (&temp, 0, sizeof(temp)); - if (error == 0 && dev->flags & IFF_UP) { + if (dev->flags & IFF_UP) { memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat)); if (ppp->slcomp != NULL) { temp.vj.vjs_packets = ppp->slcomp->sls_o_compressed+ @@ -2812,11 +2882,14 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev) temp.vj.vjs_compressedin = ppp->slcomp->sls_i_compressed; } } -/* - * Move the data to the caller's buffer - */ - if (error == 0) - memcpy_tofs (result, &temp, sizeof (temp)); + + result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; + + COPY_TO_USER (error, + result, + &temp, + sizeof (temp)); + return error; } @@ -2829,18 +2902,11 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev { struct ppp_comp_stats *result, temp; int error; -/* - * Must have write access to the buffer. - */ - result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data; - error = verify_area (VERIFY_WRITE, - result, - sizeof (temp)); /* * Supply the information for the caller. */ memset (&temp, 0, sizeof(temp)); - if (error == 0 && dev->flags & IFF_UP) { + if (dev->flags & IFF_UP) { if (ppp->sc_xc_state != NULL) (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state, &temp.c); @@ -2852,8 +2918,13 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev /* * Move the data to the caller's buffer */ - if (error == 0) - memcpy_tofs (result, &temp, sizeof (temp)); + result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data; + + COPY_TO_USER (error, + result, + &temp, + sizeof (temp)); + return error; } @@ -2866,6 +2937,8 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) { struct ppp *ppp = dev2ppp (dev); int error; + + CHECK_PPP_MAGIC(ppp); /* * Process the requests */ @@ -2893,67 +2966,49 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) * Send an IP frame to the remote with vj header compression. * * Return 0 if frame was queued for transmission. - * 1 if frame must be re-queued for later driver support. + * 1 if frame must be re-queued for later driver support. + * -1 if frame should be dropped. */ -#if defined(IPX_CHANGE) -#define ppp_dev_xmit_ip1 ppp_dev_xmit_ip -#endif - static int -ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) +ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf, + __u8 *data, int len, enum NPmode npmode) { - int proto = PPP_IP; - int len; - struct ppp_hdr *hdr; - struct tty_struct *tty = ppp2tty (ppp); -/* - * Obtain the length from the IP header. - */ - len = ((struct iphdr *)data) -> tot_len; - len = ntohs (len); + int proto = PPP_IP; + __u8 *hdr; /* - * Validate the tty interface + * Branch on the type of processing for the IP frame. */ - if (tty == NULL) { + switch (npmode) { + case NPMODE_PASS: + break; + + case NPMODE_QUEUE: + /* + * We may not send the packet now, so drop it. + * XXX It would be nice to be able to return it to the + * network system to be queued and retransmitted later. + */ if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_dev_xmit: %s not connected to a TTY!\n", - dev->name); - return 0; - } -/* - * Ensure that the PPP device is still up - */ - if (!(dev->flags & IFF_UP)) { + printk(KERN_DEBUG "%s: returning frame\n", + ppp->name); + return -1; + + case NPMODE_ERROR: + case NPMODE_DROP: + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_dev_xmit: npmode = %d on %s\n", + ppp->sc_npmode[NP_IP], ppp->name); + return -1; + + default: if (ppp->flags & SC_DEBUG) printk (KERN_WARNING - "ppp_dev_xmit: packet sent on interface %s," - " which is down for IP\n", - dev->name); - return 0; - } -/* - * Detect a change in the transfer size - */ - if (ppp->mtu != ppp2dev (ppp)->mtu) { - ppp_changedmtu (ppp, - ppp2dev (ppp)->mtu, - ppp->mru); - } -/* - * Acquire the lock on the transmission buffer. If the buffer was busy then - * mark the device as busy and return "failure to send, try back later" error. - */ - if (lock_buffer (ppp->wbuf) != 0) { - dev->tbusy = 1; - return 1; + "ppp_dev_xmit: unknown npmode %d on %s\n", + ppp->sc_npmode[NP_IP], ppp->name); + return -1; } -/* - * Print the frame being sent - */ - if (ppp->flags & SC_LOG_OUTPKT) - ppp_print_buffer ("ppp outpkt", data, len); /* * At this point, the buffer will be transmitted. There is no other exit. * @@ -2961,12 +3016,12 @@ ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) */ if (ppp->flags & SC_COMP_TCP) { len = slhc_compress (ppp->slcomp, data, len, - buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN, + buf_base (ppp->cbuf) + PPP_HDRLEN, &data, (ppp->flags & SC_NO_TCP_CCID) == 0); if (data[0] & SL_TYPE_COMPRESSED_TCP) { - proto = PPP_VJC_COMP; + proto = PPP_VJC_COMP; data[0] ^= SL_TYPE_COMPRESSED_TCP; } else { if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) @@ -2977,158 +3032,41 @@ ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) /* * Send the frame */ - len += PPP_HARD_HDR_LEN; - hdr = &((struct ppp_hdr *) data)[-1]; - - hdr->address = PPP_ALLSTATIONS; - hdr->control = PPP_UI; - hdr->protocol[0] = 0; - hdr->protocol[1] = proto; - - return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len); -} - -/* - * This is just an interum solution until the 1.3 kernel's networking is - * available. The 1.2 kernel has problems with device headers before the - * buffers. - * - * This routine should be deleted, and the ppp_dev_xmit_ip1 routine called - * by this name. - */ - -#if !defined(IPX_CHANGE) -static int -ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data) -{ - struct ppp_hdr *hdr; - int len; - int answer; - - len = ((struct iphdr *)data) -> tot_len; - len = ntohs (len); + len += PPP_HDRLEN; + hdr = data - PPP_HDRLEN; - hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr), - GFP_ATOMIC); + hdr[0] = PPP_ALLSTATIONS; + hdr[1] = PPP_UI; + hdr[2] = 0; + hdr[3] = proto; - if (hdr == NULL) - answer = 1; - else { - memcpy (&hdr[1], data, len); - answer = ppp_dev_xmit_ip1 (dev, ppp, (u_char *) &hdr[1]); - kfree (hdr); - } - - return answer; + return ppp_dev_xmit_frame (ppp, buf, hdr, len); } -#endif /* !defined(IPX_CHANGE) */ /* - * Send an IPX (or any other non-IP) frame to the remote. + * Send a non-IP data frame (such as an IPX frame) to the remote. * * Return 0 if frame was queued for transmission. - * 1 if frame must be re-queued for later driver support. + * 1 if frame must be re-queued for later driver support. */ - -#if defined(IPX_CHANGE) -#define ppp_dev_xmit_ipx1 ppp_dev_xmit_ipx -#endif - -#if defined(NEW_SKBUFF) || defined(IPX_CHANGE) static int -ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp, - u_char *data, int len, int proto) +ppp_dev_xmit_other (struct device *dev, struct ppp *ppp, + __u8 *data, int len, int proto) { - struct tty_struct *tty = ppp2tty (ppp); - struct ppp_hdr *hdr; -/* - * Validate the tty interface - */ - if (tty == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_dev_xmit: %s not connected to a TTY!\n", - dev->name); - return 0; - } -/* - * Ensure that the PPP device is still up - */ - if (!(dev->flags & IFF_UP)) { - if (ppp->flags & SC_DEBUG) - printk (KERN_WARNING - "ppp_dev_xmit: packet sent on interface %s," - " which is down\n", - dev->name); - return 0; - } -/* - * Detect a change in the transfer size - */ - if (ppp->mtu != ppp2dev (ppp)->mtu) { - ppp_changedmtu (ppp, - ppp2dev (ppp)->mtu, - ppp->mru); - } -/* - * Acquire the lock on the transmission buffer. If the buffer was busy then - * mark the device as busy and return "failure to send, try back later" error. - */ - if (lock_buffer (ppp->wbuf) != 0) { - dev->tbusy = 1; - return 1; - } -/* - * Print the frame being sent - */ - if (ppp->flags & SC_LOG_OUTPKT) - ppp_print_buffer ("ppp outpkt", data, len); + __u8 *hdr; /* * Send the frame */ - len += PPP_HARD_HDR_LEN; - hdr = &((struct ppp_hdr *) data)[-1]; - - hdr->address = PPP_ALLSTATIONS; - hdr->control = PPP_UI; - hdr->protocol[0] = proto >> 8; - hdr->protocol[1] = proto; - - return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len); -} - -/* - * This is just an interum solution until the 1.3 kernel's networking is - * available. The 1.2 kernel has problems with device headers before the - * buffers. - * - * This routine should be deleted, and the ppp_dev_xmit_ipx1 routine called - * by this name. - */ - -#if !defined(IPX_CHANGE) -static int -ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp, - u_char *data, int len, int proto) -{ - struct ppp_hdr *hdr; - int answer; + len += PPP_HDRLEN; + hdr = data - PPP_HDRLEN; - hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr), - GFP_ATOMIC); - if (hdr == NULL) - answer = 1; - else { - memcpy (&hdr[1], data, len); - answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1], - len, proto); - kfree (hdr); - } + hdr[0] = PPP_ALLSTATIONS; + hdr[1] = PPP_UI; + hdr[2] = proto >> 8; + hdr[3] = proto; - return answer; + return ppp_dev_xmit_frame (ppp, ppp->wbuf, hdr, len); } -#endif /* !defined(IPX_CHANGE) */ -#endif /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */ /* * Send a frame to the remote. @@ -3138,8 +3076,8 @@ static int ppp_dev_xmit (sk_buff *skb, struct device *dev) { int answer, len; - u_char *data; - struct ppp *ppp = dev2ppp (dev); + __u8 *data; + struct ppp *ppp = dev2ppp (dev); struct tty_struct *tty = ppp2tty (ppp); /* * just a little sanity check. @@ -3154,15 +3092,8 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) */ if (!ppp->inuse) { dev_kfree_skb (skb, FREE_WRITE); - dev_close (dev); return 0; } -/* - * Validate the tty linkage - */ - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n", - dev->name, skb); /* * Validate the tty interface */ @@ -3179,46 +3110,71 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) */ len = skb->len; data = skb_data(skb); + + if (data == (__u8 *) 0) { + if (ppp->flags & SC_DEBUG) + printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n", + dev->name); + dev_kfree_skb (skb, FREE_WRITE); + return 0; + } +/* + * Detect a change in the transfer size + */ + if (ppp->mtu != ppp2dev (ppp)->mtu) { + ppp_changedmtu (ppp, + ppp2dev (ppp)->mtu, + ppp->mru); + } +/* + * Acquire the lock on the transmission buffer. If the buffer was busy then + * mark the device as busy. + * We also require that ppp->tbuf be unlocked, in order to serialize + * calls to ppp_dev_xmit_frame (which does compression) and the output + * of frames w.r.t. tty writes from pppd. + */ + CHECK_BUF_MAGIC(ppp->wbuf); + if (ppp->tbuf->locked || lock_buffer (ppp->wbuf) != 0) { + dev->tbusy = 1; + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "dev_xmit blocked, t=%lu w=%lu\n", + ppp->tbuf->locked, ppp->wbuf->locked); + return 1; + } /* * Look at the protocol in the skb to determine the difference between * an IP frame and an IPX frame. */ - -#if defined(NEW_SKBUFF) || defined(IPX_CHANGE) switch (ntohs (skb->protocol)) { case ETH_P_IPX: - answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX); + answer = ppp_dev_xmit_other (dev, ppp, data, len, PPP_IPX); break; case ETH_P_IP: - answer = ppp_dev_xmit_ip (dev, ppp, data); + answer = ppp_dev_xmit_ip (ppp, ppp->wbuf, data, len, + ppp->sc_npmode[NP_IP]); break; default: /* All others have no support at this time. */ -#if 1 /* I **REALLY** want to toss this. For the time being, I'll assume - that this is IP. However, if you start to see the message below - then you should fix the skb->protocol to have the proper values. */ - - printk (KERN_ERR - "ppp: strange protocol type %x in ppp_dev_xmit\n", - skb->protocol); - answer = ppp_dev_xmit_ip (dev, ppp, data); - break; -#else /* Shortly, this is what it will be! */ dev_kfree_skb (skb, FREE_WRITE); return 0; -#endif /* if 1 */ } -#else /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */ - answer = ppp_dev_xmit_ip (dev, ppp, data); -#endif - /* * This is the end of the transmission. Release the buffer if it was sent. */ if (answer == 0) { + /* packet queued OK */ dev_kfree_skb (skb, FREE_WRITE); - ppp->ddinfo.xmit_idle = jiffies; + } else { + ppp->wbuf->locked = 0; + if (answer < 0) { + /* packet should be dropped */ + dev_kfree_skb (skb, FREE_WRITE); + answer = 0; + } else { + /* packet should be queued for later */ + dev->tbusy = 1; + } } return answer; } @@ -3231,102 +3187,30 @@ static struct enet_statistics * ppp_dev_stats (struct device *dev) { struct ppp *ppp = dev2ppp (dev); - static struct enet_statistics ppp_stats; - - ppp_stats.rx_packets = ppp->stats.ppp_ipackets; - ppp_stats.rx_errors = ppp->stats.ppp_ierrors; - ppp_stats.rx_dropped = ppp->stats.ppp_ierrors; - ppp_stats.rx_fifo_errors = 0; - ppp_stats.rx_length_errors = 0; - ppp_stats.rx_over_errors = 0; - ppp_stats.rx_crc_errors = 0; - ppp_stats.rx_frame_errors = 0; - ppp_stats.tx_packets = ppp->stats.ppp_opackets; - ppp_stats.tx_errors = ppp->stats.ppp_oerrors; - ppp_stats.tx_dropped = 0; - ppp_stats.tx_fifo_errors = 0; - ppp_stats.collisions = 0; - ppp_stats.tx_carrier_errors = 0; - ppp_stats.tx_aborted_errors = 0; - ppp_stats.tx_window_errors = 0; - ppp_stats.tx_heartbeat_errors = 0; - - if (ppp->flags & SC_DEBUG) - printk (KERN_INFO "ppp_dev_stats called"); - return &ppp_stats; -} - -#if defined(NEW_SKBUFF) -/* - * This defines the protocol layer which is blank since the - * driver does all the cooking. - */ - -static int ppp_dev_input (struct protocol *self, struct protocol *lower, - sk_buff *skb, void *saddr, void *daddr) -{ - return protocol_pass_demultiplex(self, NULL, skb, NULL, NULL); -} - -static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type, - int subid, void *saddr, void *daddr, void *opt) -{ - if(skb->dev==NULL) - { - printk("ppp_dev_output: No device.\n"); - kfree_skb(skb, FREE_WRITE); - return -1; - } - dev_queue_xmit(skb, skb->dev, skb->priority); - return 0; -} - -static int ppp_dev_getkey(int protocol, int subid, unsigned char *key) -{ - switch (protocol) - { - case htons (ETH_P_IP): - case htons (ETH_P_IPX): - return 0; - - default: - break; - } - return -EAFNOSUPPORT; -} - -#else - -#if USE_SKB_PROTOCOL == 0 -/* - * Called to enquire about the type of the frame in the buffer. Return - * ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame. - */ + ppp->estats.rx_packets = ppp->stats.ppp_ipackets; + ppp->estats.rx_errors = ppp->stats.ppp_ierrors; + ppp->estats.tx_packets = ppp->stats.ppp_opackets; + ppp->estats.tx_errors = ppp->stats.ppp_oerrors; +#if LINUX_VERSION_CODE >= VERSION(2,1,25) + ppp->estats.rx_bytes = ppp->stats.ppp_ibytes; + ppp->estats.tx_bytes = ppp->stats.ppp_obytes; +#endif -static unsigned short -ppp_dev_type (sk_buff *skb, struct device *dev) -{ - return (htons (ETH_P_IP)); + return &ppp->estats; } -#endif -#if USE_SKB_PROTOCOL == 0 -static int ppp_dev_header (unsigned char *buff, struct device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len, struct sk_buff *skb) -#else +#if LINUX_VERSION_CODE < VERSION(2,1,15) static int ppp_dev_header (sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len) -#endif + __u16 type, void *daddr, + void *saddr, unsigned int len) { return (0); } static int -ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr, - sk_buff *skb) +ppp_dev_rebuild (void *eth, struct device *dev, + unsigned long raddr, struct sk_buff *skb) { return (0); } @@ -3337,71 +3221,80 @@ ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr, * Miscellany called by various functions above. *************************************************************/ +/* Locate the previous instance of the PPP channel */ +static struct ppp * +ppp_find (int pid_value) +{ + struct ppp *ppp; + + /* try to find the device which this pid is already using */ + for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { + if (ppp->inuse && ppp->sc_xfer == pid_value) { + ppp->sc_xfer = 0; + break; + } + } + return ppp; +} + /* allocate or create a PPP channel */ static struct ppp * ppp_alloc (void) { int if_num; int status; - ppp_ctrl_t *ctl; struct device *dev; struct ppp *ppp; /* try to find an free device */ - ctl = ppp_list; - if_num = 0; - - while (ctl) { - ppp = ctl2ppp (ctl); - if (!set_bit(0, &ppp->inuse)) - return (ppp); - ctl = ctl->next; - if (++if_num == max_dev) - return (NULL); - } -/* - * There are no available items. Allocate a device from the system pool - */ - ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL); - if (ctl) { - (void) memset(ctl, 0, sizeof(ppp_ctrl_t)); - ppp = ctl2ppp (ctl); - dev = ctl2dev (ctl); - - /* initialize channel control data */ - set_bit(0, &ppp->inuse); - - ppp->line = if_num; - ppp->tty = NULL; - ppp->dev = dev; - - dev->next = NULL; - dev->init = ppp_init_dev; - dev->name = ctl->name; - dev->base_addr = (unsigned long) if_num; - dev->priv = (void *) ppp; - - sprintf (dev->name, "ppp%d", if_num); - - /* link in the new channel */ - ctl->next = ppp_list; - ppp_list = ctl; - -/* register device so that we can be ifconfig'd */ -/* ppp_init_dev() will be called as a side-effect */ - - status = register_netdev (dev); - if (status == 0) { - printk (KERN_INFO "registered device %s\n", dev->name); - return (ppp); - } + if_num = 0; + for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { + if (!test_and_set_bit(0, &ppp->inuse)) + return ppp; + ++if_num; + } +/* + * There are no available units, so make a new one. + */ + ppp = (struct ppp *) kmalloc (sizeof(struct ppp), GFP_KERNEL); + if (ppp == 0) + return 0; + memset(ppp, 0, sizeof(*ppp)); + + /* initialize channel control data */ + set_bit(0, &ppp->inuse); + ppp->line = if_num; + ppp->tty = NULL; + ppp->backup_tty = NULL; + if (ppp_last == 0) + ppp_list = ppp; + else + ppp_last->next = ppp; + ppp_last = ppp; + ppp->next = 0; + + dev = ppp2dev(ppp); + dev->next = NULL; + dev->init = ppp_init_dev; + dev->name = ppp->name; + sprintf(dev->name, "ppp%d", if_num); + dev->base_addr = (__u32) if_num; + dev->priv = (void *) ppp; + + /* register device so that we can be ifconfig'd */ + /* ppp_init_dev() will be called as a side-effect */ + status = register_netdev (dev); + if (status == 0) { + printk (KERN_INFO "registered device %s\n", dev->name); + } else { printk (KERN_ERR "ppp_alloc - register_netdev(%s) = %d failure.\n", dev->name, status); + ppp = NULL; /* This one will forever be busy as it is not initialized */ } - return (NULL); + return ppp; } /* @@ -3409,9 +3302,9 @@ ppp_alloc (void) */ static void -ppp_print_hex (register u_char * out, const u_char * in, int count) +ppp_print_hex (register __u8 * out, const __u8 * in, int count) { - register u_char next_ch; + register __u8 next_ch; static char hex[] = "0123456789ABCDEF"; while (count-- > 0) { @@ -3423,9 +3316,9 @@ ppp_print_hex (register u_char * out, const u_char * in, int count) } static void -ppp_print_char (register u_char * out, const u_char * in, int count) +ppp_print_char (register __u8 * out, const __u8 * in, int count) { - register u_char next_ch; + register __u8 next_ch; while (count-- > 0) { next_ch = *in++; @@ -3442,11 +3335,11 @@ ppp_print_char (register u_char * out, const u_char * in, int count) } static void -ppp_print_buffer (const u_char * name, const u_char * buf, int count) +ppp_print_buffer (const __u8 * name, const __u8 * buf, int count) { - u_char line[44]; + __u8 line[44]; - if (name != (u_char *) NULL) + if (name != (__u8 *) NULL) printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count); while (count > 8) { @@ -3487,7 +3380,7 @@ static struct compressor *find_compressor (int type) lnk = ppp_compressors; while (lnk != (struct compressor_link *) 0) { - if ((int) (unsigned char) lnk->comp->compress_proto == type) { + if ((int) (__u8) lnk->comp->compress_proto == type) { restore_flags(flags); return lnk->comp; } @@ -3506,14 +3399,14 @@ static int ppp_register_compressor (struct compressor *cp) new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL); if (new == (struct compressor_link *) 0) - return 1; + return 1; save_flags(flags); cli(); if (find_compressor (cp->compress_proto)) { restore_flags(flags); - kfree (new); + kfree (new); return 0; } @@ -3537,7 +3430,7 @@ static void ppp_unregister_compressor (struct compressor *cp) lnk = ppp_compressors; while (lnk != (struct compressor_link *) 0) { if (lnk->comp == cp) { - if (prev) + if (prev) prev->next = lnk->next; else ppp_compressors = lnk->next; @@ -3565,8 +3458,10 @@ init_module(void) if (status != 0) printk (KERN_INFO "PPP: ppp_init() failure %d\n", status); +#if LINUX_VERSION_CODE < VERSION(2,1,18) else (void) register_symtab (&ppp_syms); +#endif return (status); } @@ -3574,27 +3469,23 @@ void cleanup_module(void) { int status; - ppp_ctrl_t *ctl, *next_ctl; struct device *dev; - struct ppp *ppp; + struct ppp *ppp, *next_ppp; int busy_flag = 0; /* * Ensure that the devices are not in operation. */ - ctl = ppp_list; - while (ctl) { - ppp = ctl2ppp (ctl); + for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { if (ppp->inuse && ppp->tty != NULL) { busy_flag = 1; break; } - dev = ctl2dev (ctl); + dev = ppp2dev (ppp); if (dev->start || dev->flags & IFF_UP) { busy_flag = 1; break; } - ctl = ctl->next; } /* * Ensure that there are no compressor modules registered @@ -3608,7 +3499,7 @@ cleanup_module(void) return; } /* - * Release the tty registration of the line dicipline so that no new entries + * Release the tty registration of the line discipline so that no new entries * may be created. */ status = tty_register_ldisc (N_PPP, NULL); @@ -3621,17 +3512,12 @@ cleanup_module(void) "PPP: ppp line discipline successfully unregistered\n"); /* * De-register the devices so that there is no problem with them - */ - next_ctl = ppp_list; - while (next_ctl) { - ctl = next_ctl; - next_ctl = ctl->next; - ppp = ctl2ppp (ctl); - dev = ctl2dev (ctl); - - ppp_release (ppp); - unregister_netdev (dev); - kfree (ctl); + */ + for (ppp = ppp_list; ppp != 0; ppp = next_ppp) { + next_ppp = ppp->next; + ppp_release (ppp); + unregister_netdev (&ppp->dev); + kfree (ppp); } } #endif