X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=linux%2Fppp.c;h=cd7e605ac1bf771bfa91847f3fc3819c99165e71;hp=af329c8d93d073d2af0e476495129bf5428b4a00;hb=6bca842794ae41bfc71bdf27cde3bf6ecd843540;hpb=80e8f1536f549b54573f0147d5cd3b895d81e2cc diff --git a/linux/ppp.c b/linux/ppp.c index af329c8..cd7e605 100644 --- a/linux/ppp.c +++ b/linux/ppp.c @@ -1,8 +1,17 @@ /* - PPP for Linux - - $Id: ppp.c,v 1.3 1994/12/08 02:03:55 paulus Exp $ -*/ + * PPP for Linux + * + * ==PPPVERSION 2.1.3== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, increment the last number above. + * ppp.c is shipped with a PPP distribution as well as with the kernel; + * if everyone increases the PPPVERSION number above, then scripts + * can do the right thing when deciding whether to install a new ppp.c + * file. Don't change the format of that line otherwise, so the + * installation script can recognize it. + * + */ /* Sources: @@ -26,12 +35,26 @@ 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. + + PPP_COMPRESS - Enable the PPP compression protocol. This protocol + is under contention with Motorolla's patent, so use + with caution. NEW_SKBUFF - Use NET3.020 sk_buff's */ -/* #define NEW_SKBUFF */ -#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) /* */ +/* #define NEW_SKBUFF 1 */ +#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) +#define CHECK_CHARACTERS 1 +#define PPP_COMPRESS 1 + +/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 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. + */ #include #include @@ -62,7 +85,7 @@ #ifdef NEW_SKBUFF #include #else -#define skb_data(skb) ((skb)->data) +#define skb_data(skb) ((unsigned char *) (skb)->data) typedef struct sk_buff sk_buff; #endif @@ -75,10 +98,33 @@ typedef struct sk_buff sk_buff; #include #include +#ifdef MODULE +#include +#include +#define STATIC static +#else +#define MOD_INC_USE_COUNT while(0) { } +#define MOD_DEC_USE_COUNT while(0) { } +#endif /* def MODULE */ + +#ifdef PPP_COMPRESS +#undef PACKETPTR +#define PACKETPTR 1 +#include +#undef PACKETPTR + +#define bsd_decompress (*ppp->sc_rcomp->decompress) +#define bsd_compress (*ppp->sc_xcomp->compress) +#endif + #ifndef PPP_IPX #define PPP_IPX 0x2b /* IPX protocol over PPP */ #endif +#ifndef PPP_LQR +#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */ +#endif + /* * Local functions */ @@ -86,14 +132,37 @@ typedef struct sk_buff sk_buff; 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 int ppp_do_ip (struct ppp *, unsigned short, u_char *, int); -static int ppp_us_queue (struct ppp *, unsigned short, u_char *, int); static struct ppp *ppp_alloc (void); -static void ppp_print_buffer (const u_char *, u_char *, int, int); +static void ppp_print_buffer (const u_char *, u_char *, int); extern inline void ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, register u_char chr); extern inline int lock_buffer (register struct ppp_buffer *buf); +static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd); + +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_ccp (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 *); + +/* + * List of compressors we know about. + * We leave some space so maybe we can modload compressors. + */ + +#ifdef PPP_COMPRESS +extern struct compressor ppp_bsd_compress; + +struct compressor *ppp_compressors[8] = { + &ppp_bsd_compress, + NULL +}; +#endif /* PPP_COMPRESS */ #define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c)) @@ -146,10 +215,7 @@ static void ppp_tty_receive (struct tty_struct *tty, u_char * cp, char *fp, int count); static void ppp_tty_wakeup (struct tty_struct *tty); - #define PRINTK(p) printk p ; -#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p)) -#define PRINTKN(n,p) {if (ppp_debug >= n) PRINTK (p)} #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;} @@ -159,26 +225,79 @@ static void ppp_tty_wakeup (struct tty_struct *tty); #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)) + +#if 1 +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; + +static ppp_ctrl_t *ppp_list = NULL; + +#define ctl2ppp(ctl) (struct ppp *) &ctl->ppp +#define ctl2dev(ctl) (struct device *) &ctl->dev +#undef PPP_NRUNIT + +#else + +#define PPP_NRUNIT 4 +static struct ppp ppp_ctrl[PPP_NRUNIT]; +#undef dev2ppp +#define dev2ppp(dev) ((struct ppp *) &ppp_ctrl[dev->base_addr]) +#endif + /* 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_VJ 4 /* vj compression 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 */ static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n"; -static int first_time = 1; static char szVersion[] = PPP_VERSION; -static int ppp_debug = 5; -static int ppp_debug_netpackets = 0; -static struct tty_ldisc ppp_ldisc; -static struct ppp ppp_ctrl [PPP_NRUNIT]; #ifdef NEW_SKBUFF -struct protocol proto_ppp; +static struct protocol proto_ppp; +#endif + +/* + * Information for the protocol decoder + */ + +typedef int (*pfn_proto) (struct ppp *, u_short, u_char *, int); + +typedef struct ppp_proto_struct { + int proto; + pfn_proto func; +} ppp_proto_type; + +ppp_proto_type proto_list[] = { + { 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 }, +#ifdef PPP_COMPRESS + { PPP_CCP, rcv_proto_ccp }, #endif + { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */ +}; /* FCS table from RFC1331 */ @@ -218,83 +337,126 @@ static unsigned short fcstab[256] = 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; +#ifdef CHECK_CHARACTERS +static unsigned paritytab[8] = +{ + 0x96696996, 0x69969669, 0x69969669, 0x96696996, + 0x69969669, 0x96696996, 0x96696996, 0x69969669 +}; +#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; + return p; +} + /************************************************************* * INITIALIZATION *************************************************************/ -/* called at boot time for each ppp device */ +/* This procedure is called once and once only to define who we are to + * the operating system and the various procedures that it may use in + * accessing the ppp protocol. + */ -int -ppp_init (struct device *dev) +static int +ppp_first_time (void) { - struct ppp *ppp; - int i; - - ppp = &ppp_ctrl[dev->base_addr]; - - if (first_time) { - first_time = 0; - - printk (KERN_INFO "PPP: version %s (%d channels)" + static struct tty_ldisc ppp_ldisc; + int status; + +#ifdef PPP_NRUNIT +#define PPP_UNITS3(x) #x +#define PPP_UNITS2(x) PPP_UNITS3(x) +#define PPP_UNITS1(x) PPP_UNITS2(x) +#define PPP_UNITS "(" PPP_UNITS1(PPP_NRUNIT) " devices)" +#else +#define PPP_UNITS "(dynamic channel allocation)" +#endif + printk (KERN_INFO + "PPP: version %s " PPP_UNITS #ifdef NEW_SKBUFF - " NEW_SKBUFF" + " NEW_SKBUFF" +#endif + "\n", szVersion); +#undef PPP_UNITS +#undef PPP_UNITS1 +#undef PPP_UNITS2 +#undef PPP_UNITS3 + + printk (KERN_INFO + "TCP compression code copyright 1989 Regents of the " + "University of California\n"); + +#ifndef PPP_NRUNIT + printk (KERN_INFO + "PPP Dynamic channel allocation code copyright 1995 " + "Caldera, Inc.\n"); #endif - "\n", szVersion, PPP_NRUNIT); - printk (KERN_INFO - "TCP compression code copyright 1989 Regents of the " - "University of California\n"); - - (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc)); - ppp_ldisc.magic = TTY_LDISC_MAGIC; - ppp_ldisc.open = ppp_tty_open; - ppp_ldisc.close = ppp_tty_close; - ppp_ldisc.read = ppp_tty_read; - ppp_ldisc.write = ppp_tty_write; - ppp_ldisc.ioctl = ppp_tty_ioctl; - ppp_ldisc.select = ppp_tty_select; - ppp_ldisc.receive_room = ppp_tty_room; - ppp_ldisc.receive_buf = ppp_tty_receive; - ppp_ldisc.write_wakeup = ppp_tty_wakeup; - - i = tty_register_ldisc (N_PPP, &ppp_ldisc); - if (i == 0) { - printk (KERN_INFO "PPP line discipline registered.\n"); - } else { - printk (KERN_ERR "error registering line discipline: %d\n", i); - } +/* + * Register the protocol for the device + */ #ifdef NEW_SKBUFF - memset (&proto_ppp, 0, sizeof (proto_ppp)); + 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.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 = 0; /* PPP_HARD_HDR_LEN; */ - protocol_register(&proto_ppp); + protocol_register(&proto_ppp); #endif - } - /* initialize PPP control block */ - ppp_init_ctrl_blk (ppp); - ppp->inuse = 0; - ppp->line = dev->base_addr; - ppp->tty = NULL; - ppp->dev = dev; +/* + * Register the tty dicipline + */ + (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc)); + ppp_ldisc.magic = TTY_LDISC_MAGIC; + ppp_ldisc.open = ppp_tty_open; + ppp_ldisc.close = ppp_tty_close; + ppp_ldisc.read = ppp_tty_read; + ppp_ldisc.write = ppp_tty_write; + ppp_ldisc.ioctl = ppp_tty_ioctl; + ppp_ldisc.select = ppp_tty_select; + 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"); + else + printk (KERN_ERR "error registering line discipline: %d\n", + status); + return status; +} - /* clear statistics */ - memset (&ppp->p, '\0', sizeof (struct ppp_stats)); +/************************************************************* + * INITIALIZATION + *************************************************************/ +/* called when the device is actually created */ + +static int +ppp_init_dev (struct device *dev) +{ + int indx; #ifdef NEW_SKBUFF dev->default_protocol = &proto_ppp; /* Our protocol layer is PPP */ #else dev->hard_header = ppp_dev_header; dev->type_trans = ppp_dev_type; dev->rebuild_header = ppp_dev_rebuild; - dev->hard_header_len = 0; + dev->hard_header_len = 0; /* PPP_HARD_HDR_LEN; */ #endif /* device INFO */ @@ -307,9 +469,8 @@ ppp_init (struct device *dev) dev->addr_len = 0; dev->type = ARPHRD_PPP; - for (i = 0; i < DEV_NUMBUFFS; i++) { - skb_queue_head_init (&dev->buffs[i]); - } + for (indx = 0; indx < DEV_NUMBUFFS; indx++) + skb_queue_head_init (&dev->buffs[indx]); /* New-style flags */ dev->flags = IFF_POINTOPOINT; @@ -357,14 +518,49 @@ ppp_init_ctrl_blk (register struct ppp *ppp) #endif /* clear statistics */ - memset (&ppp->p, '\0', sizeof (struct ppp_stats)); + memset (&ppp->stats, '\0', sizeof (struct pppstat)); /* Reset the demand dial information */ ppp->ddinfo.ip_sjiffies = ppp->ddinfo.ip_rjiffies = ppp->ddinfo.nip_sjiffies = ppp->ddinfo.nip_rjiffies = jiffies; + +#ifdef PPP_COMPRESS + ppp->sc_xc_state = + ppp->sc_rc_state = NULL; +#endif /* PPP_COMPRESS */ +} + +/* called at boot/load time for each ppp device defined in the kernel */ + +#ifndef MODULE +int +ppp_init (struct device *dev) +{ + static int first_time = 1; + int answer = 0; + + if (first_time) { + first_time = 0; + answer = ppp_first_time(); + } +/* + * Un-register the devices defined at the start of the system. They will + * be added when they are needed again. The first device just gets us into + * this code to register the handlers. + */ +#if 1 + unregister_netdev (dev); +#else + ppp_init_dev (dev); + ppp_init_ctrl_blk (dev2ppp (dev)); + dev2ppp (dev) -> inuse = 0; + dev2ppp (dev) -> dev = dev; +#endif + return answer; } +#endif /* * Routine to allocate a buffer for later use by the driver. @@ -397,9 +593,8 @@ ppp_alloc_buf (int size, int type) static void ppp_free_buf (struct ppp_buffer *ptr) { - if (ptr != NULL) { + if (ptr != NULL) kfree (ptr); - } } /* @@ -417,9 +612,8 @@ lock_buffer (register struct ppp_buffer *buf) save_flags (flags); cli (); state = buf->locked; - if (state == 0) { + if (state == 0) buf->locked = 2; - } /* * Restore the flags and return the previous state. 0 implies success. */ @@ -452,30 +646,35 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) /* * Allocate the buffer from the kernel for the data */ - dev = ppp->dev; + dev = ppp2dev (ppp); mru = new_mru; + /* allow for possible escapement of every character */ mtu = (new_mtu * 2) + 20; /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */ - if (mru < PPP_MRU) { + if (mru < PPP_MRU) mru = PPP_MRU; - } - mru += 10; - PRINTKN (2, (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n", - dev->name, new_mtu, new_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 + 4, 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 + 4, BUFFER_TYPE_VJ); + new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, 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); /* * If the buffers failed to allocate then complain and release the partial * allocations. */ if (new_wbuf == NULL || new_tbuf == NULL || new_rbuf == NULL || new_cbuf == NULL) { - PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp: failed to allocate new buffers\n"); + ppp_free_buf (new_wbuf); ppp_free_buf (new_tbuf); ppp_free_buf (new_rbuf); @@ -505,16 +704,16 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) /* * Update the parameters for the new buffer sizes */ - ppp->toss = 0xE0; /* To ignore characters until new FLAG */ + ppp->toss = 0xE0; /* To ignore characters until new FLAG */ ppp->escape = 0; /* No pending escape character */ - dev->mtu = - ppp->mtu = new_mtu; - ppp->mru = new_mru; + dev->mtu = + ppp->mtu = new_mtu; + ppp->mru = new_mru; - ppp->s1buf = NULL; - ppp->s2buf = NULL; - ppp->xbuf = NULL; + ppp->s1buf = NULL; + ppp->s2buf = NULL; + ppp->xbuf = NULL; ppp->tty->flags &= ~TTY_DO_WRITE_WAKEUP; ppp->flags &= ~SC_XMIT_BUSY; @@ -530,6 +729,26 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) return 1; } +/* + * CCP is down; free (de)compressor state if necessary. + */ + +#ifdef PPP_COMPRESS +static void +ppp_ccp_closed (struct ppp *ppp) +{ + if (ppp->sc_xc_state) { + (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state); + ppp->sc_xc_state = NULL; + } + + if (ppp->sc_rc_state) { + (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state); + ppp->sc_rc_state = NULL; + } +} +#endif /* PPP_COMPRESS */ + /* * Called to release all of the information in the current PPP structure. * @@ -540,13 +759,26 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) static void ppp_release (struct ppp *ppp) { - if (ppp->tty != NULL && ppp->tty->disc_data == ppp) { - ppp->tty->disc_data = NULL; /* Break the tty->ppp link */ - } - if (ppp->dev) { - ppp->dev->flags &= ~IFF_UP; /* down the device */ - ppp->dev->flags |= IFF_POINTOPOINT; + struct tty_struct *tty; + struct device *dev; + + tty = ppp2tty (ppp); + dev = ppp2dev (ppp); + +#ifdef PPP_COMPRESS + ppp_ccp_closed (ppp); + ppp->sc_xc_state = + ppp->sc_rc_state = NULL; +#endif /* PPP_COMPRESS */ + + if (tty != NULL && tty->disc_data == ppp) + tty->disc_data = NULL; /* Break the tty->ppp link */ + + if (dev && dev->flags & IFF_UP) { + dev_close (dev); /* close the device properly */ + dev->flags = 0; /* prevent recursion */ } + ppp_free_buf (ppp->rbuf); ppp_free_buf (ppp->wbuf); ppp_free_buf (ppp->cbuf); @@ -566,8 +798,9 @@ ppp_release (struct ppp *ppp) slhc_free (ppp->slcomp); ppp->slcomp = NULL; } + ppp->inuse = 0; - ppp->tty = NULL; + ppp->tty = NULL; } /* @@ -579,37 +812,41 @@ ppp_release (struct ppp *ppp) static void ppp_tty_close (struct tty_struct *tty) { - struct ppp *ppp = (struct ppp *) tty->disc_data; + struct ppp *ppp = tty2ppp (tty); if (ppp == NULL || ppp->magic != PPP_MAGIC) { - PRINTKN (1, - (KERN_WARNING "ppp: trying to close unopened tty!\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_WARNING + "ppp: trying to close unopened tty!\n"); } else { - CHECK_PPP_VOID (); - PRINTKN (2, - (KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name)); + CHECK_PPP_VOID(); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp: channel %s closing.\n", + ppp2dev(ppp) -> name); ppp_release (ppp); + MOD_DEC_USE_COUNT; } } /* * TTY callback. * - * Called when the tty dicipline is switched to PPP. + * Called when the tty discipline is switched to PPP. */ static int ppp_tty_open (struct tty_struct *tty) { - struct ppp *ppp = (struct ppp *) tty->disc_data; + struct ppp *ppp = tty2ppp (tty); /* * There should not be an existing table for this slot. */ if (ppp) { - PRINTKN (1, (KERN_ERR - "ppp_tty_open: gack! tty already associated to %s!\n", - ppp->magic == PPP_MAGIC ? ppp->dev->name - : "unknown")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_open: gack! tty already associated to %s!\n", + ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name + : "unknown"); return -EEXIST; } /* @@ -617,8 +854,9 @@ ppp_tty_open (struct tty_struct *tty) */ ppp = ppp_alloc (); if (ppp == NULL) { - PRINTKN (1, (KERN_ERR - "ppp_tty_open: couldn't allocate ppp channel\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_open: couldn't allocate ppp channel\n"); return -ENFILE; } /* @@ -628,29 +866,28 @@ ppp_tty_open (struct tty_struct *tty) ppp->tty = tty; tty->disc_data = ppp; /* - * Flush any pending characters in the driver and dicipline. + * Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) { + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); - } - if (tty->driver.flush_buffer) { + if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); - } /* * Allocate space for the default VJ header compression slots (16) */ ppp->slcomp = slhc_init (16, 16); if (ppp->slcomp == NULL) { - PRINTKN (1, (KERN_ERR - "ppp_tty_open: no space for compression buffers!\n")); + 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, ppp->dev->mtu, ppp->mru) == 0) { + if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) { ppp_release (ppp); return -ENOMEM; } @@ -659,13 +896,18 @@ ppp_tty_open (struct tty_struct *tty) */ ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD); if (ppp->ubuf == NULL) { - PRINTKN (1, (KERN_ERR - "ppp_tty_open: no space for user receive buffer\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_open: no space for user receive buffer\n"); ppp_release (ppp); return -ENOMEM; } - PRINTKN (2, (KERN_INFO "ppp: channel %s open\n", ppp->dev->name)); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp: channel %s open\n", + ppp2dev(ppp)->name); + + MOD_INC_USE_COUNT; return (ppp->line); } @@ -706,11 +948,10 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, * This could occur should the carrier drop. */ if (actual < 0) { - ppp->p.ppp_oerrors++; + ppp->stats.ppp_oerrors++; actual = count; - } else { + } else ppp->bytes_sent += actual; - } /* * If the buffer has been transmitted then clear the indicators. */ @@ -719,7 +960,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, xbuf = NULL; ppp->flags &= ~SC_XMIT_BUSY; /* - * Complete the transmisson on the current buffer. + * Complete the transmission on the current buffer. */ xbuf = ppp->xbuf; if (xbuf != NULL) { @@ -730,10 +971,10 @@ 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 (ppp->dev->flags & IFF_UP) { - ppp->dev->tbusy = 0; + if (ppp2dev (ppp) -> flags & IFF_UP) { + ppp2dev (ppp)->tbusy = 0; mark_bh (NET_BH); - dev_tint (ppp->dev); + dev_tint (ppp2dev (ppp)); } /* * Wake up the transmission queue for all completion events. @@ -776,11 +1017,12 @@ static void ppp_tty_wakeup (struct tty_struct *tty) { struct ppp_buffer *xbuf; - struct ppp *ppp = (struct ppp *) tty->disc_data; + struct ppp *ppp = tty2ppp (tty); if (!ppp || ppp->magic != PPP_MAGIC) { - PRINTKN (1, (KERN_ERR "PPP: write_wakeup called but couldn't " - "find PPP struct.\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG "PPP: write_wakeup called but " + "couldn't find PPP struct.\n"); return; } /* @@ -788,15 +1030,14 @@ ppp_tty_wakeup (struct tty_struct *tty) * there is no pending buffer. Otherwise, send the buffer. */ xbuf = ppp->xbuf; - if (xbuf == NULL) { + if (xbuf == NULL) tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - } else { + else ppp_tty_wakeup_code (ppp, tty, xbuf); - } } /* - * This function is called to transmit a buffer to the rmeote. The buffer + * This function is called to transmit a buffer to the remote. The buffer * is placed on the pending queue if there is presently a buffer being * sent or it is transmitted with the aid of ppp_tty_wakeup. */ @@ -820,11 +1061,10 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf) * priority queue. */ if (ppp->xbuf != NULL) { - if (xbuf->type == BUFFER_TYPE_TTY_WR) { + if (xbuf->type == BUFFER_TYPE_TTY_WR) ppp->s1buf = xbuf; - } else { + else ppp->s2buf = xbuf; - } restore_flags (flags); return; } @@ -838,7 +1078,7 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf) /* * Do the "tty wakeup_code" to actually send this buffer. */ - ppp_tty_wakeup_code (ppp, ppp->tty, xbuf); + ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf); } /************************************************************* @@ -849,14 +1089,6 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf) * user process reading this TTY. *************************************************************/ -#ifdef CHECK_CHARACTERS -static unsigned paritytab[8] = -{ - 0x96696996, 0x69969669, 0x69969669, 0x96696996, - 0x69969669, 0x96696996, 0x96696996, 0x69969669 -}; -#endif - /* * Callback function from tty driver. Return the amount of space left * in the receiver's buffer to decide if remote transmitter is to be @@ -876,24 +1108,26 @@ ppp_tty_room (struct tty_struct *tty) static void ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) { - register struct ppp *ppp = (struct ppp *) tty->disc_data; + register struct ppp *ppp = tty2ppp (tty); register struct ppp_buffer *buf = ppp->rbuf; u_char chr; /* - * Verify the table pointer and ensure that the line is still in PPP dicipline. + * Verify the table pointer and ensure that the line is + * still in PPP discipline. */ if (!ppp || ppp->magic != PPP_MAGIC) { - PRINTKN (1, ("PPP: handler called but couldn't find " - "PPP struct.\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "PPP: handler called but couldn't find " + "PPP struct.\n"); return; } CHECK_PPP_VOID (); /* * Print the buffer if desired */ - if (ppp_debug >= 5) { - ppp_print_buffer ("receive buffer", data, count, KERNEL_DS); - } + 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. @@ -902,9 +1136,8 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) ppp->bytes_rcvd++; chr = *data++; if (flags) { - if (*flags && ppp->toss == 0) { + if (*flags && ppp->toss == 0) ppp->toss = *flags; - } ++flags; } /* @@ -914,18 +1147,17 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) * 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. */ + #ifdef CHECK_CHARACTERS - if (chr & 0x80) { + if (chr & 0x80) ppp->flags |= SC_RCV_B7_1; - } else { + else ppp->flags |= SC_RCV_B7_0; - } - if (paritytab[chr >> 5] & (1 << (chr & 0x1F))) { + if (paritytab[chr >> 5] & (1 << (chr & 0x1F))) ppp->flags |= SC_RCV_ODDP; - } else { + else ppp->flags |= SC_RCV_EVNP; - } #endif /* * Branch on the character. Process the escape character. The sequence ESC ESC @@ -941,10 +1173,9 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) * first FLAG are also tossed by this procedure. */ case PPP_FLAG: /* PPP_FLAG: end of frame */ - ppp->p.ppp_ibytes = ppp->bytes_rcvd; - if (ppp->escape) { + ppp->stats.ppp_ibytes = ppp->bytes_rcvd; + if (ppp->escape) ppp->toss |= 0x80; - } /* * Process frames which are not to be ignored. If the processing failed, * then clean up the VJ tables. @@ -963,12 +1194,11 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) break; /* * All other characters in the data come here. If the character is in the - * recieve mask then ignore the character. + * receive mask then ignore the character. */ default: - if (in_rmap (ppp, chr)) { + 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. @@ -976,9 +1206,8 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) chr ^= ppp->escape; ppp->escape = 0; - if (ppp->toss != 0) { + if (ppp->toss != 0) break; - } /* * If the count sent is within reason then store the character, bump the * count, and update the FCS for the character. @@ -992,277 +1221,519 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count) * 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->p.ppp_ierrors++; + ppp->stats.ppp_ierrors++; ppp->toss |= 0xC0; break; } } } -/* on entry, a received frame is in ppp->rbuf.bufr - check it and dispose as appropriate */ +/* + * Put the input frame into the networking system for the indicated protocol + */ static int -ppp_doframe (struct ppp *ppp) +ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count) { - u_short proto; - u_char *data = buf_base (ppp->rbuf); - int count = ppp->rbuf->count; + sk_buff *skb = alloc_skb (count, GFP_ATOMIC); /* - * If there is a pending error from the receiver then log it and discard - * the damaged frame. + * Generate a skb buffer for the new frame. */ - if (ppp->toss) { - PRINTKN (1, (KERN_WARNING - "ppp_toss: tossing frame, reason = %d\n", - ppp->toss)); - ppp->p.ppp_ierrors++; + 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; } /* - * An empty frame is ignored. This occurs if the FLAG sequence precedes and - * follows each frame. + * Move the received data from the input buffer to the skb buffer. */ - if (count == 0) { - return 1; - } + skb->len = count; /* Store the length */ + skb->dev = ppp2dev (ppp); /* We are the device */ +#ifdef NEW_SKBUF + skb->protocol = proto; +#endif + memcpy ((u_char *) skb_data(skb), data, count); /* move data */ /* - * Print the received data. + * Tag the frame and kick it to the proper receive routine */ - if (ppp_debug >= 3) { - ppp_print_buffer ("receive frame", data, count, KERNEL_DS); - } + skb->free = 1; + ppp->ddinfo.ip_rjiffies = jiffies; + netif_rx (skb); + return 1; +} + /* - * Generate an error if the frame is too small. + * Process the receipt of an IP frame */ - if (count < 4) { - PRINTKN (1, (KERN_WARNING - "ppp: got runt ppp frame, %d chars\n", count)); - ppp->p.ppp_ierrors++; - return 1; + +static int +rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count) +{ + if (ppp2dev (ppp)->flags & IFF_UP) { + if (count > 0) + return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count); } + return 0; +} + /* - * Verify the CRC of the frame and discard the CRC characters from the - * end of the buffer. + * Process the receipt of an IPX frame */ - if (ppp->rbuf->fcs != PPP_GOODFCS) { - PRINTKN (1, (KERN_WARNING - "ppp: frame with bad fcs, excess = %x\n", - ppp->rbuf->fcs ^ PPP_GOODFCS)); - ppp->p.ppp_ierrors++; - return 0; - } - count -= 2; /* ignore the fcs characters */ + +static int +rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count) +{ +#ifdef NEW_SKBUF + if (ppp2dev (ppp)->flags & IFF_UP) { + if (count > 0) + return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count); + } else +#endif + return 0; +} + /* - * Ignore the leading ADDRESS and CONTROL fields in the frame. + * Process the receipt of an VJ Compressed frame */ - if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) { - data += 2; - count -= 2; - } - - proto = (u_short) * data++; /* PROTO compressed */ - if (proto & 1) { - count--; - } else { - proto = (proto << 8) | (u_short) * data++; - count -= 2; - } - /* Send the frame to the network if the ppp device is up */ - if (ppp->dev->flags & IFF_UP) { - if (ppp_do_ip (ppp, proto, data, count)) { - ppp->ddinfo.ip_rjiffies = jiffies; - return 1; +static int +rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto, + u_char *data, int count) +{ + if ((ppp->flags & SC_REJ_COMP_TCP) == 0) { + int new_count = slhc_uncompress (ppp->slcomp, data, count); + if (new_count >= 0) { + return rcv_proto_ip (ppp, PPP_IP, data, new_count); } + if (ppp->flags & SC_DEBUG) + printk (KERN_NOTICE + "ppp: error in VJ decompression\n"); } - - /* If we got here, it has to go to a user process doing a read, - so queue it. */ - if (ppp_us_queue (ppp, proto, data, count)) { - ppp->ddinfo.nip_rjiffies = jiffies; - return 1; - } - - /* couldn't cope. */ - PRINTKN (1, (KERN_WARNING - "ppp: dropping packet on the floor: nobody could take it.\n")); - ppp->p.ppp_ierrors++; - return 1; + return 0; } -/* Examine packet at C, attempt to pass up to net layer. - PROTO is the protocol field from the PPP frame. - Return 1 if could handle it, 0 otherwise. */ - -static int -ppp_do_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count) -{ - sk_buff *skb; /* - * Log the IP information + * Process the receipt of an VJ Un-compressed frame */ - PRINTKN (4, (KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n", - (int) proto, count, data[0])); - if (ppp_debug_netpackets) { - PRINTK ((KERN_DEBUG "%s <-- proto %x len %d\n", ppp->dev->name, - (int) proto, count)); +static int +rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto, + u_char *data, int count) +{ + 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); + } + if (ppp->flags & SC_DEBUG) + printk (KERN_NOTICE + "ppp: error in VJ memorizing\n"); } + return 0; +} + /* - * If this is uncompressed IP data then receive the data + * Receive all unclassified protocols. */ - switch (proto) { - case PPP_IP: - break; + +static int +rcv_proto_unknown (struct ppp *ppp, unsigned short proto, + u_char *data, int len) +{ + int totlen; + register int current_idx; + +#define PUTC(c) \ +{ \ + buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \ + current_idx &= ppp->ubuf->size; \ + if (current_idx == ppp->ubuf->tail) \ + goto failure; \ +} + /* - * For now, reject the IPX frames. Return 1 to indicate that it has been - * processed so that it is simply discarded. + * The total length includes the protocol data. + * Lock the user information buffer. */ - case PPP_IPX: - return 1; + if (set_bit (0, &ppp->ubuf->locked)) { + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_us_queue: can't get lock\n"); + } else { + current_idx = ppp->ubuf->head; /* - * Process compressed IP frame. If the remote told us to reject frames then - * do so now. Otherwise ensure that there is space in the buffer. + * Insert the buffer length (not counted), the protocol, and the data */ - case PPP_VJC_COMP: - if (ppp->flags & SC_REJ_COMP_TCP) { - return 1; + totlen = len + 2; + PUTC (totlen >> 8); + PUTC (totlen); + + PUTC (proto >> 8); + PUTC (proto); + + totlen -= 2; + while (totlen-- > 0) { + PUTC (*data++); } +#undef PUTC /* - * Uncompress the header. We now can _guarantee_ that there is room. + * The frame is complete. Update the head pointer and wakeup the pppd + * process. */ - count = slhc_uncompress (ppp->slcomp, data, count); - if (count <= 0) { - ppp->p.ppp_ierrors++; - PRINTKN (1, (KERN_NOTICE - "ppp: error in VJ decompression\n")); - return 1; - } - proto = PPP_IP; - break; + ppp->ubuf->head = current_idx; + + clear_bit (0, &ppp->ubuf->locked); + wake_up_interruptible (&ppp->read_wait); + if (ppp->tty->fasync != NULL) + kill_fasync (ppp->tty->fasync, SIGIO); + + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp: successfully queued %d bytes\n", + len + 2); + + ppp->ddinfo.nip_rjiffies = jiffies; + return 1; /* - * Process uncompressed IP frame + * The buffer is full. Unlock the header */ - case PPP_VJC_UNCOMP: - if ((ppp->flags & SC_REJ_COMP_TCP) == 0) { - if (slhc_remember (ppp->slcomp, - data, count) <= 0) { - ppp->p.ppp_ierrors++; - PRINTKN (1, (KERN_NOTICE - "ppp: error in VJ memorizing\n")); - return 1; +failure: + clear_bit (0, &ppp->ubuf->locked); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_us_queue: ran out of buffer space.\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); + return 0; +} + +/* + * Handle a CCP packet. + * + * The CCP packet is passed along to the pppd process just like any + * other PPP frame. The difference is that some processing needs to be + * immediate or the compressors will become confused on the peer. + */ + +#ifdef PPP_COMPRESS +static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd) +{ + int slen = CCP_LENGTH(dp); + + if (slen <= len) { + switch (CCP_CODE(dp)) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: +/* + * CCP must be going down - disable compression + */ + if (ppp->flags & SC_CCP_UP) { + ppp->flags &= ~(SC_CCP_UP | + SC_COMP_RUN | + SC_DECOMP_RUN); } - } - proto = PPP_IP; - break; + break; + + case CCP_CONFACK: + if (ppp->flags & SC_CCP_OPEN == 0) + break; + if (ppp->flags & SC_CCP_UP) + break; + if (slen < CCP_HDRLEN + CCP_OPT_MINLEN) + break; + if (slen < CCP_OPT_LENGTH (dp + CCP_HDRLEN) + + CCP_HDRLEN) + break; /* - * The frame is not a valid IP frame. Ignore it. + * we're agreeing to send compressed packets. */ - default: - return 0; - } + if (!rcvd) { + if (ppp->sc_xc_state == NULL) + break; + + if ((*ppp->sc_xcomp->comp_init) + (ppp->sc_xc_state, + dp + CCP_HDRLEN, + slen - CCP_HDRLEN, + ppp2dev (ppp)->base_addr, + ppp->flags & SC_DEBUG)) + ppp->flags |= SC_COMP_RUN; + break; + } /* - * If debugging net packets then print the information. Process the IP - * frames first. + * peer is agreeing to send compressed packets. */ - if (ppp_debug_netpackets && proto == PPP_IP) { - struct iphdr *iph = (struct iphdr *) data; - PRINTK ((KERN_INFO - "%s <-- src %lx dst %lx len %d\n", - ppp->dev->name, - iph->saddr, - iph->daddr, - count)); + if (ppp->sc_rc_state == NULL) + break; + + if ((*ppp->sc_rcomp->decomp_init) + (ppp->sc_rc_state, + dp + CCP_HDRLEN, + slen - CCP_HDRLEN, + ppp2dev (ppp)->base_addr, + ppp->mru, + ppp->flags & SC_DEBUG)) { + ppp->flags |= SC_DECOMP_RUN; + ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); + } + break; +/* + * The protocol sequence is complete at this end + */ + case CCP_RESETACK: + if (ppp->flags & SC_CCP_UP == 0) + break; + + if (!rcvd) { + if (ppp->sc_xc_state && + (ppp->flags & SC_COMP_RUN)) + (*ppp->sc_xcomp->comp_reset) + (ppp->sc_xc_state); + break; + } + + if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) { + (*ppp->sc_rcomp->decomp_reset) + (ppp->sc_rc_state); + ppp->flags &= ~SC_DC_ERROR; + } + break; + } } +} + +static int +rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len) +{ + ppp_proto_ccp (ppp, dp, len, 1); + return rcv_proto_unknown (ppp, proto, dp, len); +} +#endif /* PPP_COMPRESS */ + /* - * Generate a skb buffer for the new frame. + * 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. */ - skb = alloc_skb (count, GFP_ATOMIC); - if (skb == NULL) { - PRINTK ((KERN_ERR - "ppp_do_ip: packet dropped on %s (no memory)!\n", - ppp->dev->name)); + +static int +rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len) +{ + 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; } /* - * Move the received data from the input buffer to the skb buffer. + * Pass the frame to the pppd daemon. */ - else { + return rcv_proto_unknown (ppp, proto, data, len); +} - skb->len = count; /* Store the length */ - skb->dev = ppp->dev; /* We are the device */ - memcpy ((u_char *) skb_data(skb), data, count); /* move data */ +/* 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 len) +{ + u_short proto; + int count = len; + ppp_proto_type *proto_ptr; /* - * Tag the frame and kick it to the proper receive routine + * Ignore empty frames + */ + if (count <= 0) + return; +/* + * Count the frame and print it + */ + ++ppp->stats.ppp_ipackets; + if (ppp->flags & SC_LOG_INPKT) + ppp_print_buffer ("receive frame", data, count); +/* + * Ignore the leading ADDRESS and CONTROL fields in the frame. */ - skb->free = 1; - netif_rx (skb); /* Receive the buffer */ + if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) { + data += 2; + count -= 2; } - return 1; +/* + * Obtain the protocol from the frame + */ + proto = (u_short) *data++; + if (proto & 1) + count--; + else { + proto = (proto << 8) | (u_short) *data++; + count -= 2; + } +/* + * 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, count)) + ppp->stats.ppp_ioctects += len; + else + ++ppp->stats.ppp_discards; } -/* stuff packet at BUF, length LEN, into the us_rbuff buffer - prepend PROTO information */ +/* on entry, a received frame is in ppp->rbuf.bufr + check it and dispose as appropriate */ static int -ppp_us_queue (struct ppp *ppp, unsigned short proto, u_char * data, int len) +ppp_doframe (struct ppp *ppp) { - int totlen; - register int current_idx; + u_char *data = buf_base (ppp->rbuf); + int count = ppp->rbuf->count; +#ifdef PPP_COMPRESS + int proto; + int new_count; + u_char *new_data; +#endif /* - * The total length includes the protocol data. - * Lock the user information buffer. + * If there is a pending error from the receiver then log it and discard + * the damaged frame. */ - if (set_bit (0, &ppp->ubuf->locked)) { - PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n")); + 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; } - current_idx = ppp->ubuf->head; - -#define PUTC(c) \ -{ \ - buf_base (ppp->ubuf) [current_idx++] = (u_char) (c);\ - current_idx &= ppp->ubuf->size; \ - if (current_idx == ppp->ubuf->tail) { \ - goto failure; \ - } \ -} +/* + * 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 */ +#ifdef PPP_COMPRESS + proto = PPP_PROTOCOL (data); /* - * Insert the buffer length (not counted), the protocol, and the data + * Process the active decompressor. + */ + if ((ppp->sc_rc_state != (void *) 0) && + ((ppp->flags & SC_DECOMP_RUN) == 0)) { +/* + * If the frame is compressed then decompress it. */ - totlen = len + 2; - PUTC (totlen >> 8); - PUTC (totlen); + if (((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0) && + (proto == PPP_COMP)) { + 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); - PUTC (proto >> 8); - PUTC (proto); + switch (new_count) { + default: + ppp_doframe_lower (ppp, new_data, new_count); + kfree (new_data); + return 1; - while (len-- > 0) { - PUTC (*data++); - } -#undef PUTC + case DECOMP_OK: + break; + + case DECOMP_ERROR: + ppp->flags |= SC_DC_ERROR; + break; + + case DECOMP_FATALERROR: + ppp->flags |= SC_DC_FERROR; + break; + } /* - * The frame is complete. Update the head pointer and wakeup the pppd - * process. + * Log the error condition and discard the frame. */ - ppp->ubuf->head = current_idx; - - clear_bit (0, &ppp->ubuf->locked); /* Unlock the buffer header */ - wake_up_interruptible (&ppp->read_wait); /* select() processing */ - if (ppp->tty->fasync != NULL) { - kill_fasync (ppp->tty->fasync, SIGIO); /* SIGIO processing */ + 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 decompressor without + * actually decompressing the data + */ + (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, + data, + count); } - - PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen)); - return 1; +#endif /* - * The buffer is full. Unlock the header and return the failure condition. + * Process the uncompressed frame. */ - failure: - clear_bit (0, &ppp->ubuf->locked); - PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n")); - return 0; + ppp_doframe_lower (ppp, data, count); + return 1; } /************************************************************* @@ -1281,7 +1752,7 @@ static int ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, unsigned int nr) { - struct ppp *ppp = (struct ppp *) tty->disc_data; + struct ppp *ppp = tty2ppp (tty); u_char c; int len, indx; @@ -1295,38 +1766,41 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, * Validate the pointer to the PPP structure */ if (!ppp || ppp->magic != PPP_MAGIC) { - PRINTKN (1, (KERN_ERR - "ppp_tty_read: cannnot find ppp channel\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_read: cannot find ppp channel\n"); return -EIO; } CHECK_PPP (-ENXIO); - PRINTKN (4, (KERN_DEBUG "ppp_tty_read: called %x num %u\n", - (unsigned int) buf, - nr)); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_tty_read: called %x num %u\n", + (unsigned int) buf, + nr); /* * Acquire the read lock. */ for (;;) { if (set_bit (0, &ppp->ubuf->locked) != 0) { - PRINTKN (3, (KERN_DEBUG - "ppp_tty_read: sleeping(ubuf)\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_tty_read: sleeping(ubuf)\n"); current->timeout = 0; current->state = TASK_INTERRUPTIBLE; schedule (); - if (current->signal & ~current->blocked) { + if (current->signal & ~current->blocked) return -EINTR; - } continue; } /* * Fetch the length of the buffer from the first two bytes. */ - if (ppp->ubuf->head == ppp->ubuf->tail) { + if (ppp->ubuf->head == ppp->ubuf->tail) len = 0; - } else { + else { GETC (c); len = c << 8; GETC (c); @@ -1339,37 +1813,44 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, /* no data */ clear_bit (0, &ppp->ubuf->locked); if (file->f_flags & O_NONBLOCK) { - PRINTKN (4, (KERN_DEBUG - "ppp_tty_read: no data (EWOULDBLOCK)\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_tty_read: no data " + "(EWOULDBLOCK)\n"); return -EWOULDBLOCK; } current->timeout = 0; - PRINTKN (3, (KERN_DEBUG - "ppp_tty_read: sleeping(read_wait)\n")); + + 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) { + if (current->signal & ~current->blocked) return -EINTR; - } continue; } /* * Reset the time of the last read operation. */ ppp->ddinfo.nip_rjiffies = jiffies; - PRINTKN (4, (KERN_DEBUG "ppp_tty_read: len = %d\n", len)); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len); /* * 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. */ if (len + 2 > nr) { /* Can't copy it, update us_rbuff_head */ - PRINTKN (1, (KERN_DEBUG - "ppp: read of %u bytes too small for %d frame\n", - nr, len + 2)); + + 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->p.ppp_ierrors++; + ppp->stats.ppp_ierrors++; return -EOVERFLOW; } /* @@ -1378,6 +1859,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, */ put_fs_byte (PPP_ALLSTATIONS, buf++); put_fs_byte (PPP_UI, buf++); + indx = len; /* * Copy the received data from the buffer to the caller's area. @@ -1391,8 +1873,9 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf, */ clear_bit (0, &ppp->ubuf->locked); len += 2; /* Account for ADDRESS and CONTROL bytes */ - PRINTKN (3, - (KERN_DEBUG "ppp_tty_read: passing %d bytes up\n", len)); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_tty_read: passing %d bytes up\n", len); return len; } #undef GETC @@ -1409,10 +1892,11 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, /* * The buffer should not be full. */ - if ((buf->count < 0) || (buf->count > 3000)) { - PRINTK ((KERN_DEBUG "ppp_stuff_char: %x %d\n", - (unsigned int) buf->count, - (unsigned int) buf->count)) + if (ppp->flags & SC_DEBUG) { + if ((buf->count < 0) || (buf->count > 3000)) + printk (KERN_DEBUG "ppp_stuff_char: %x %d\n", + (unsigned int) buf->count, + (unsigned int) buf->count); } /* * Update the FCS and if the character needs to be escaped, do it. @@ -1428,119 +1912,355 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf, ins_char (buf, chr); } +/* + * Procedure to encode the data with the proper escapement 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) +{ + unsigned short int write_fcs; +/* + * Insert the leading FLAG character + */ + buf->count = 0; + +#ifdef OPTIMIZE_FLAG_TIME + if (non_ip) + ins_char (buf, PPP_FLAG); + else { + if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) + ins_char (buf, PPP_FLAG); + } + ppp->last_xmit = jiffies; +#else + ins_char (buf, PPP_FLAG); +#endif + + buf->fcs = PPP_INITFCS; +/* + * Insert the data + */ + while (count-- > 0) + ppp_stuff_char (ppp, buf, *data++); +/* + * Add the trailing CRC and the final flag character + */ + 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. + */ + ppp->stats.ppp_obytes += buf->count; + ppp_kick_tty (ppp, buf); +} + +/* + * Send an frame to the remote with the proper bsd compression. + * + * Return 0 if frame was queued for transmission. + * 1 if frame must be re-queued for later driver support. + */ + +int +ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, + u_char *data, int count) +{ + int address, control; + int proto; + u_char *new_data; + int new_count; +/* + * Print the buffer + */ + if (ppp->flags & SC_LOG_OUTPKT) + ppp_print_buffer ("write frame", data, count); +/* + * Determine if the frame may be compressed. Attempt to compress the + * frame if possible. + */ + address = PPP_ADDRESS (data); + control = PPP_CONTROL (data); + proto = PPP_PROTOCOL (data); + +#ifdef PPP_COMPRESS + if ((ppp->flags & SC_COMP_RUN != 0) && + (ppp->sc_xc_state != (void *) 0) && + (address == PPP_ALLSTATIONS) && + (control == PPP_UI) && + (proto != PPP_LCP) && + (proto != PPP_CCP)) { + new_data = kmalloc (count, GFP_ATOMIC); + if (new_data == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_dev_xmit_frame: no memory\n"); + 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 += count; + + ppp_dev_xmit_lower (ppp, buf, new_data, + new_count, 0); + kfree (new_data); + return 0; + } +/* + * The frame could not be compressed. + */ + kfree (new_data); + } +#endif +/* + * 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; +/* + * Do not compress the protocol id if not possible + */ + if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xFF00)) { + --data; + ++count; + } + + data += 3; + count -= 3; +/* + * Do not compress the address/control if not possible. + */ + if (address != PPP_ALLSTATIONS || + control != PPP_UI || + !(ppp->flags & SC_COMP_AC)) { + *--data = control; + *--data = address; + count += 2; + } +/* + * Go to the escape encoding + */ + ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00)); + return 0; +} + +/* + * Revise the tty frame for specific protocols. + */ + +static int +send_revise_frame (register struct ppp *ppp, u_char *data, int len) +{ + u_char *p; + + switch (PPP_PROTOCOL (data)) { +/* + * Update the LQR frame with the current MIB information. This saves having + * the daemon read old MIB data from the driver. + */ + case PPP_LQR: + len = 48; /* total size of this frame */ + p = (u_char *) &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; +/* + * Outbound compression frames + */ +#ifdef PPP_COMPRESS + case PPP_COMP: + ppp_proto_ccp (ppp, data, len, 0); + break; +#endif + +/* + * All other frame types + */ + default: + break; + } + + return len; +} + /* * write a frame with NR chars from BUF to TTY * we have to put the FCS field on ourselves */ static int -ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * buf, +ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data, unsigned int count) { - struct ppp *ppp = (struct ppp *) tty->disc_data; - int indx; - unsigned short write_fcs; + struct ppp *ppp = tty2ppp (tty); + u_char *new_data; /* * Verify the pointer to the PPP data and that the tty is still in PPP mode. */ if (!ppp || ppp->magic != PPP_MAGIC) { - PRINTKN (1,(KERN_ERR "ppp_tty_write: cannot find ppp unit\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_write: cannot find ppp unit\n"); return -EIO; } + CHECK_PPP (-ENXIO); -/* - * Detech a change in the transfer size - */ - if (ppp->mtu != ppp->dev->mtu) { /* Someone has been ifconfigging */ - ppp_changedmtu (ppp, - ppp->dev->mtu, - ppp->mru); - } /* * Ensure that the caller does not wish to send too much. */ if (count > PPP_MTU) { - PRINTKN (1, (KERN_WARNING - "ppp_tty_write: truncating user packet from %u to mtu %d\n", - count, PPP_MTU)); + 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; } -/* - * Print the buffer - */ - if (ppp_debug >= 3) { - ppp_print_buffer ("write frame", buf, count, USER_DS); - } /* * lock this PPP unit so we will be the only writer; * sleep if necessary */ while (lock_buffer (ppp->tbuf) != 0) { current->timeout = 0; - PRINTKN (3, (KERN_DEBUG "ppp_tty_write: sleeping\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG "ppp_tty_write: sleeping\n"); interruptible_sleep_on (&ppp->write_wait); - if (current->signal & ~current->blocked) { + if (current->signal & ~current->blocked) return -EINTR; - } } /* - * OK, locked. Add the leading FLAG character to the buffer. + * Allocate a buffer for the data and fetch it from the user space. */ - PRINTKN (4, (KERN_DEBUG "ppp_tty_write: acquired write lock\n")); - ppp->tbuf->count = 0; - -#ifdef OPTIMIZE_FLAG_TIME - if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) { - ins_char (ppp->tbuf, PPP_FLAG); + new_data = kmalloc (count, GFP_ATOMIC); + if (new_data == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_write: no memory\n"); + ppp->tbuf->locked = 0; + return 0; } - ppp->last_xmit = jiffies; -#else - ins_char (ppp->tbuf, PPP_FLAG); -#endif + + memcpy_fromfs (new_data, data, count); /* - * Add the data for the frame to the buffer. + * Change the LQR frame */ - ppp->tbuf->fcs = PPP_INITFCS; - indx = count; - while (indx-- > 0) { - register char chr = get_fs_byte (buf++); - ppp_stuff_char (ppp, ppp->tbuf, chr); - } + count = send_revise_frame (ppp, new_data, count); /* - * Add the trailing CRC and the final flag character + * Send the data */ - write_fcs = ppp->tbuf->fcs ^ 0xFFFF; - ppp_stuff_char (ppp, ppp->tbuf, write_fcs); - ppp_stuff_char (ppp, ppp->tbuf, write_fcs >> 8); + ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count); + kfree (new_data); + return (int) count; +} - PRINTKN (4, (KERN_DEBUG "ppp_tty_write: fcs is %hx\n", write_fcs)); /* - * Add the trailing FLAG character + * Process the BSD compression IOCTL event for the tty device. */ - ins_char (ppp->tbuf, PPP_FLAG); + +#ifdef PPP_COMPRESS +static int +ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) +{ + int error; + int nb; + u_char ccp_option[CCP_MAX_OPTION_LENGTH]; + struct compressor **cp; /* - * Update the time and print the data to the debug log. + * Validate the range of the ioctl */ - ppp->ddinfo.nip_sjiffies = jiffies; + error = verify_area (VERIFY_READ, odp, + (unsigned long) (&((struct ppp_option_data *) 0)->length) + + sizeof (odp->length)); - if (ppp_debug >= 6) { - ppp_print_buffer ("xmit buffer", - buf_base (ppp->tbuf), - ppp->tbuf->count, - KERNEL_DS); - } else { - PRINTKN (4, (KERN_DEBUG - "ppp_tty_write: writing %d chars\n", ppp->tbuf->count)); + if (error == 0) { + nb = (int) get_fs_long (odp->length); + if ((unsigned long) nb-1 >= (unsigned long) CCP_MAX_OPTION_LENGTH) + nb = CCP_MAX_OPTION_LENGTH; + + error = verify_area (VERIFY_READ, odp, nb); } -/* - * Start the transmitter and the request is complete. - */ - ppp->p.ppp_obytes += ppp->tbuf->count; - ++ppp->p.ppp_opackets; - ppp_kick_tty (ppp, ppp->tbuf); - return ((int) count); + if (error != 0) + return error; + + memcpy_fromfs (ccp_option, odp, nb); + if (ccp_option[1] < 2) /* preliminary check on the length byte */ + return (-EINVAL); + + for (cp = ppp_compressors; *cp != NULL; ++cp) + if ((*cp)->compress_proto == ccp_option[0]) { + /* + * Found a handler for the protocol - try to allocate + * a compressor or decompressor. + */ + error = 0; + if (odp->transmit) { + if (ppp->sc_xc_state != NULL) + (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); + + 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); + error = -ENOBUFS; + } + 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_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; + } + 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], + ccp_option[2], nb); + return (-EINVAL); /* no handler found */ } +#endif /* PPP_COMPRESS */ /* * Process the IOCTL event for the tty device. @@ -1550,24 +2270,24 @@ static int ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, unsigned long param3) { - struct ppp *ppp = (struct ppp *) tty->disc_data; + struct ppp *ppp = tty2ppp (tty); register int temp_i = 0; int error; /* * Verify the status of the PPP device. */ if (!ppp || ppp->magic != PPP_MAGIC) { - PRINTK ((KERN_ERR - "ppp_tty_ioctl: can't find PPP block from tty!\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_ioctl: can't find PPP block from tty!\n"); return -EBADF; } CHECK_PPP (-ENXIO); /* * The user must have an euid of root to do these requests. */ - if (!suser ()) { + if (!suser ()) return -EPERM; - } /* * Set the MRU value */ @@ -1576,12 +2296,13 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: set mru to %x\n", temp_i)); temp_i = (int) get_fs_long (param3); - if (ppp->mru != temp_i) { - ppp_changedmtu (ppp, ppp->dev->mtu, temp_i); - } + 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); } break; /* @@ -1597,9 +2318,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, SC_RCV_ODDP | SC_RCV_EVNP; #endif put_fs_long ((long) temp_i, param3); - PRINTKN (3, (KERN_DEBUG - "ppp_tty_ioctl: get flags: addr %lx flags %x\n", - param3, temp_i)); + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG + "ppp_tty_ioctl: get flags: addr %lx flags " + "%x\n", param3, temp_i); } break; /* @@ -1609,12 +2331,30 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - temp_i = (int) get_fs_long (param3); - ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK); - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: set flags to %x\n", temp_i)); + temp_i = (int) get_fs_long (param3) & SC_MASK; + temp_i |= (ppp->flags & ~SC_MASK); +#ifdef PPP_COMPRESS + if ((ppp->flags & SC_CCP_OPEN) && + (temp_i & SC_CCP_OPEN) == 0) + ppp_ccp_closed (ppp); +#else + temp_i &= ~SC_CCP_OPEN; +#endif + 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 + */ +#ifdef PPP_COMPRESS + case PPPIOCSCOMPRESS: + error = ppp_set_compression (ppp, + (struct ppp_option_data *) param3); + break; +#endif /* * Retrieve the transmit async map */ @@ -1623,9 +2363,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, sizeof (temp_i)); if (error == 0) { put_fs_long (ppp->xmit_async_map[0], param3); - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: get asyncmap: addr %lx asyncmap %lx\n", - param3, ppp->xmit_async_map[0])); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: get asyncmap: addr " + "%lx asyncmap %lx\n", + param3, ppp->xmit_async_map[0]); } break; /* @@ -1636,9 +2378,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, sizeof (temp_i)); if (error == 0) { ppp->xmit_async_map[0] = get_fs_long (param3); - PRINTKN (3, (KERN_INFO + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp_tty_ioctl: set xmit asyncmap %lx\n", - ppp->xmit_async_map[0])); + ppp->xmit_async_map[0]); } break; /* @@ -1649,9 +2392,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, sizeof (temp_i)); if (error == 0) { ppp->recv_async_map = get_fs_long (param3); - PRINTKN (3, (KERN_INFO + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp_tty_ioctl: set rcv asyncmap %lx\n", - ppp->recv_async_map)); + ppp->recv_async_map); } break; /* @@ -1661,10 +2405,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { - put_fs_long (ppp->dev->base_addr, param3); - PRINTKN (3, - (KERN_INFO "ppp_tty_ioctl: get unit: %d", - ppp->dev->base_addr)); + put_fs_long (ppp2dev (ppp)->base_addr, param3); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: get unit: %ld", + ppp2dev (ppp)->base_addr); } break; /* @@ -1674,12 +2419,13 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { - ppp_debug = (int) get_fs_long (param3); - ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8; - ppp_debug &= 0xff; - PRINTKN (1, (KERN_INFO - "ppp_tty_ioctl: set debug level %d, netpacket %d\n", - ppp_debug, ppp_debug_netpackets)); + temp_i = (int) (get_fs_long (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; } break; /* @@ -1689,14 +2435,14 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { - put_fs_long ((long) (ppp_debug | - (ppp_debug_netpackets << 8)), - param3); + temp_i = (ppp->flags >> 16) & 0x1F; + put_fs_long ((long) temp_i, param3); - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: get debug level %d\n", - ppp_debug | (ppp_debug_netpackets << 8))); - } + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: get debug level %d\n", + temp_i); + } break; /* * Get the times since the last send/receive frame operation @@ -1716,8 +2462,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, memcpy_tofs ((void *) param3, &cur_ddinfo, sizeof (struct ppp_ddinfo)); - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: read demand dial info\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: read demand dial info\n"); } break; /* @@ -1731,9 +2478,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, memcpy_tofs ((void *) param3, ppp->xmit_async_map, sizeof (ppp->xmit_async_map)); - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: get xasyncmap: addr %lx\n", - param3)); + + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: get xasyncmap: addr %lx\n", + param3); } break; /* @@ -1747,19 +2496,21 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, memcpy_fromfs (temp_tbl, (void *) param3, sizeof (ppp->xmit_async_map)); - temp_tbl[1] = 0x00000000; + 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) { + (temp_tbl[6] & temp_tbl[7]) != 0) error = -EINVAL; - } else { + else { memcpy (ppp->xmit_async_map, temp_tbl, sizeof (ppp->xmit_async_map)); - PRINTKN (3, (KERN_INFO - "ppp_tty_ioctl: set xasyncmap\n")); + + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp_tty_ioctl: set xasyncmap\n"); } } break; @@ -1771,17 +2522,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, sizeof (temp_i)); if (error == 0) { temp_i = (int) get_fs_long (param3) + 1; - PRINTKN (3, (KERN_INFO + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp_tty_ioctl: set maxcid to %d\n", - temp_i)); - if (ppp->slcomp != NULL) { + temp_i); + if (ppp->slcomp != NULL) slhc_free (ppp->slcomp); - } - ppp->slcomp = slhc_init (temp_i, temp_i); + ppp->slcomp = slhc_init (16, temp_i); if (ppp->slcomp == NULL) { - PRINTKN (1, (KERN_ERR - "ppp: no space for compression buffers!\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp: no space for compression buffers!\n"); ppp_release (ppp); error = -ENOMEM; } @@ -1798,10 +2550,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2, * All other ioctl() events will come here. */ default: - PRINTKN (1, (KERN_ERR - "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n", - param2, - param3)); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n", + param2, + param3); error = -ENOIOCTLCMD; break; @@ -1819,14 +2572,15 @@ static int ppp_tty_select (struct tty_struct *tty, struct inode *inode, struct file *filp, int sel_type, select_table * wait) { - struct ppp *ppp = (struct ppp *) tty->disc_data; + struct ppp *ppp = tty2ppp (tty); int result = 1; /* * Verify the status of the PPP device. */ if (!ppp || ppp->magic != PPP_MAGIC) { - PRINTK ((KERN_ERR - "ppp_tty_select: can't find PPP block from tty!\n")); + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_tty_select: can't find PPP block from tty!\n"); return -EBADF; } CHECK_PPP (0); @@ -1849,13 +2603,13 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, */ case SEL_EX: /* Is this a pty link and the remote disconnected? */ - if (tty->flags & (1 << TTY_SLAVE_CLOSED)) { + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) break; - } + /* Is this a local link and the modem disconnected? */ - if (tty_hung_up_p (filp)) { + if (tty_hung_up_p (filp)) break; - } + select_wait (&ppp->read_wait, wait); result = 0; break; @@ -1869,7 +2623,6 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, } break; } - return result; } @@ -1888,20 +2641,23 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode, static int ppp_dev_open (struct device *dev) { - struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + struct ppp *ppp = dev2ppp (dev); /* reset POINTOPOINT every time, since dev_close zaps it! */ dev->flags |= IFF_POINTOPOINT; - if (ppp->tty == NULL) { - PRINTKN (1, - (KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n", - dev->name)); + if (ppp2tty (ppp) == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp: %s not connected to a TTY! can't go open!\n", + dev->name); return -ENXIO; } - PRINTKN (2, (KERN_INFO "ppp: channel %s going up for IP packets!\n", - dev->name)); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp: channel %s going up for IP packets!\n", + dev->name); CHECK_PPP (-ENXIO); return 0; @@ -1914,20 +2670,23 @@ ppp_dev_open (struct device *dev) static int ppp_dev_close (struct device *dev) { - struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + struct ppp *ppp = dev2ppp (dev); - if (ppp->tty == NULL) { - PRINTKN (1, - (KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n", - dev->name)); + 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; } /* * We don't do anything about the device going down. It is not important * for us. */ - PRINTKN (2, (KERN_INFO "ppp: channel %s going down for IP packets!\n", - dev->name)); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO + "ppp: channel %s going down for IP packets!\n", + dev->name); CHECK_PPP (-ENXIO); return 0; } @@ -1979,7 +2738,7 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr) */ if (error == 0) { memset (&temp, 0, sizeof(temp)); - memcpy (&temp.p, &ppp->p, sizeof (struct pppstat)); + memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat)); /* * Header Compression statistics */ @@ -2022,7 +2781,7 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr) static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) { - struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + struct ppp *ppp = dev2ppp (dev); int error; /* * Process the requests @@ -2044,206 +2803,330 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) } /* - * Send a frame to the remote. + * 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. */ int -ppp_dev_xmit (sk_buff *skb, struct device *dev) +ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data) { - struct tty_struct *tty; - struct ppp *ppp; - u_char *data; - unsigned short proto; - int len; - unsigned short write_fcs; -/* - * just a little sanity check. - */ - if (skb == NULL) { - PRINTKN (3, (KERN_WARNING "ppp_dev_xmit: null packet!\n")); - return 0; - } + int proto = PPP_IP; + int len; + struct ppp_hdr *hdr; + struct tty_struct *tty = ppp2tty (ppp); /* - * Fetch the poitners to the data + * Obtain the length from the IP header. */ - ppp = &ppp_ctrl[dev->base_addr]; - tty = ppp->tty; - data = (u_char *) (&skb[1]); - len = skb->len; - proto = PPP_IP; - - PRINTKN (4, (KERN_DEBUG "ppp_dev_xmit [%s]: skb %lX busy %d\n", - dev->name, - (unsigned long int) skb, ppp->wbuf->locked)); - - CHECK_PPP (0); + len = ((struct iphdr *)data) -> tot_len; + len = ntohs (len); /* * Validate the tty interface */ - do { - if (tty == NULL) { - PRINTKN (1, - (KERN_ERR "ppp_dev_xmit: %s not connected to a TTY!\n", - dev->name)); - break; - } + 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)) { - PRINTKN (1, (KERN_WARNING + if (!(dev->flags & IFF_UP)) { + if (ppp->flags & SC_DEBUG) + printk (KERN_WARNING "ppp_dev_xmit: packet sent on interface %s," " which is down for IP\n", - dev->name)); - break; - } + dev->name); + return 0; + } /* * Detect a change in the transfer size */ - if (ppp->mtu != ppp->dev->mtu) { - ppp_changedmtu (ppp, - ppp->dev->mtu, - ppp->mru); - } -/* - * Fetch the length from the IP header. - */ - if (len < sizeof (struct iphdr)) { - PRINTKN (0, (KERN_ERR - "ppp_dev_xmit: given runt packet, ignoring\n")); - break; - } - len = ntohs (((struct iphdr *) skb_data(skb))->tot_len); + 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; - } + 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); /* * At this point, the buffer will be transmitted. There is no other exit. * * Try to compress the header. */ - if (ppp->flags & SC_COMP_TCP) { - /* last 0 argument says don't compress connection ID */ - len = slhc_compress (ppp->slcomp, data, len, - buf_base (ppp->cbuf), - &data, 0); + if (ppp->flags & SC_COMP_TCP) { + len = slhc_compress (ppp->slcomp, data, len, + buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN, + &data, + !(ppp->flags & SC_NO_TCP_CCID)); - if (data[0] & SL_TYPE_COMPRESSED_TCP) { - proto = PPP_VJC_COMP; - } else { - if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) { - proto = PPP_VJC_UNCOMP; - data[0] = (data[0] & 0x0f) | 0x40; - } - } + if (data[0] & SL_TYPE_COMPRESSED_TCP) { + proto = PPP_VJC_COMP; + data[0] ^= SL_TYPE_COMPRESSED_TCP; + } else { + if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) + proto = PPP_VJC_UNCOMP; + data[0] = (data[0] & 0x0f) | 0x40; } + } +/* + * 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); +} - if (ppp_debug_netpackets) { - struct iphdr *iph = (struct iphdr *) skb_data(skb); - PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x " - "dst %x proto %d\n", - dev->name, (int) proto, (int) len, (int) iph->saddr, - (int) iph->daddr, (int) iph->protocol)) - } /* - * Insert the leading FLAG character + * 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. */ - ppp->wbuf->count = 0; -#ifdef OPTIMIZE_FLAG_TIME - if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) { - ins_char (ppp->wbuf, PPP_FLAG); - } - ppp->last_xmit = jiffies; -#else - ins_char (ppp->wbuf, PPP_FLAG); -#endif +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); + + 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_ip1 (dev, ppp, (u_char *) &hdr[1]); + kfree (hdr); + } + + return answer; +} - ppp->wbuf->fcs = PPP_INITFCS; /* - * Insert the address and control data + * Send an IPX (or any other non-IP) frame to the remote. + * + * Return 0 if frame was queued for transmission. + * 1 if frame must be re-queued for later driver support. */ - if (!(ppp->flags & SC_COMP_AC)) { - ppp_stuff_char (ppp, ppp->wbuf, PPP_ALLSTATIONS); - ppp_stuff_char (ppp, ppp->wbuf, PPP_UI); - } + +int +ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp, + u_char *data, int len, int proto) +{ + struct tty_struct *tty = ppp2tty (ppp); + struct ppp_hdr *hdr; /* - * Insert the protocol. + * Validate the tty interface */ - if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00)) { - ppp_stuff_char (ppp, ppp->wbuf, proto >> 8); - } - ppp_stuff_char (ppp, ppp->wbuf, proto); + 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; + } /* - * Insert the data + * Ensure that the PPP device is still up */ - while (len-- > 0) { - ppp_stuff_char (ppp, ppp->wbuf, *data++); - } + 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; + } /* - * Add the trailing CRC and the final flag character + * 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 */ - write_fcs = ppp->wbuf->fcs ^ 0xFFFF; - ppp_stuff_char (ppp, ppp->wbuf, write_fcs); - ppp_stuff_char (ppp, ppp->wbuf, write_fcs >> 8); + if (ppp->flags & SC_LOG_OUTPKT) + ppp_print_buffer ("ppp outpkt", data, len); +/* + * 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); +} - PRINTKN (4, - (KERN_DEBUG "ppp_dev_xmit: fcs is %hx\n", write_fcs)); /* - * Add the trailing flag character + * 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. + */ + +int +ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp, + u_char *data, int len, int proto) +{ + struct ppp_hdr *hdr; + int answer; + + hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr), + GFP_ATOMIC); + if (hdr == NULL) + answer = 1; + else { + memcpy (&hdr[1], data, len); + answer = (dev, ppp, (u_char *) &hdr[1], len, proto); + kfree (hdr); + } + + return answer; +} + +/* + * Send a frame to the remote. + */ + +int +ppp_dev_xmit (sk_buff *skb, struct device *dev) +{ + int answer; + u_char *data; + struct ppp *ppp = dev2ppp (dev); + struct tty_struct *tty = ppp2tty (ppp); +/* + * just a little sanity check. */ - ins_char (ppp->wbuf, PPP_FLAG); + if (skb == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_WARNING "ppp_dev_xmit: null packet!\n"); + return 0; + } /* - * Update the times for the transmission. + * Avoid timing problem should tty hangup while data is queued to be sent */ - ppp->ddinfo.ip_sjiffies = jiffies; + if (!ppp->inuse) { + dev_kfree_skb (skb, FREE_WRITE); + dev_close (dev); + return 0; + } /* - * Print the buffer + * Validate the tty linkage */ - if (ppp_debug >= 6) { - ppp_print_buffer ("xmit buffer", buf_base (ppp->wbuf), - ppp->wbuf->count, KERNEL_DS); - } else { - PRINTKN (4, (KERN_DEBUG - "ppp_dev_xmit: writing %d chars\n", - ppp->wbuf->count)); - } + if (ppp->flags & SC_DEBUG) + printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n", + dev->name, (int) skb); /* - * Send the block to the tty driver. + * Validate the tty interface */ - ppp->p.ppp_obytes += ppp->wbuf->count; - ++ppp->p.ppp_opackets; - ppp_kick_tty (ppp, ppp->wbuf); + if (tty == NULL) { + if (ppp->flags & SC_DEBUG) + printk (KERN_ERR + "ppp_dev_xmit: %s not connected to a TTY!\n", + dev->name); + dev_kfree_skb (skb, FREE_WRITE); + return 0; } - while (0); /* - * This is the end of the transmission. Release the buffer. + * Fetch the pointer to the data */ - dev_kfree_skb (skb, FREE_WRITE); - return 0; + data = skb_data (skb); +/* + * Look at the protocol in the skb to determine the difference between + * an IP frame and an IPX frame. + */ + +#ifdef NEW_SKBUFF + switch (skb->protocol) { + case htons (ETH_P_IPX): + answer = ppp_dev_xmit_ipx (dev, ppp, data, skb->len, PPP_IPX); + break; + + case htons (ETH_P_IP): + answer = ppp_dev_xmit_ip (dev, ppp, data); + break; + + default: /* All others have no support at this time. */ + dev_kfree_skb (skb, FREE_WRITE); + return 0; + } +#else + 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) + dev_kfree_skb (skb, FREE_WRITE); + return answer; } +/* + * Generate the statistic information for the /proc/net/dev listing. + */ + static struct enet_statistics * ppp_dev_stats (struct device *dev) { - struct ppp *ppp = &ppp_ctrl[dev->base_addr]; + struct ppp *ppp = dev2ppp (dev); static struct enet_statistics ppp_stats; - ppp_stats.rx_packets = ppp->p.ppp_ipackets; - ppp_stats.rx_errors = ppp->p.ppp_ierrors; - ppp_stats.rx_dropped = ppp->p.ppp_ierrors; + 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->p.ppp_opackets; - ppp_stats.tx_errors = ppp->p.ppp_oerrors; + 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; @@ -2252,7 +3135,8 @@ ppp_dev_stats (struct device *dev) ppp_stats.tx_window_errors = 0; ppp_stats.tx_heartbeat_errors = 0; - PRINTKN (3, (KERN_INFO "ppp_dev_stats called")); + if (ppp->flags & SC_DEBUG) + printk (KERN_INFO "ppp_dev_stats called"); return &ppp_stats; } @@ -2286,7 +3170,8 @@ static int ppp_dev_getkey(int protocol, int subid, unsigned char *key) { switch (protocol) { - case ETH_P_IP: + case htons (ETH_P_IP): + case htons (ETH_P_IPX): return 0; default: @@ -2329,17 +3214,79 @@ ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr, * Miscellany called by various functions above. *************************************************************/ -/* allocate a PPP channel */ +/* allocate or create a PPP channel */ static struct ppp * ppp_alloc (void) { - int i; - for (i = 0; i < PPP_NRUNIT; i++) { - if (!set_bit (0, &ppp_ctrl[i].inuse)) { - return &ppp_ctrl[i]; +#if 1 + 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 == INT_MAX) + 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 ("registered device %s\n", dev->name); + return (ppp); } + + printk (KERN_ERR + "ppp_alloc - register_netdev(%s) = %d failure.\n", + dev->name, status); + /* This one will forever be busy as it is not initialized */ } - return NULL; + return (NULL); +#else + int i; + for (i = 0; i < PPP_NRUNIT; i++) + if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i]; + + return NULL; +#endif } /* @@ -2353,11 +3300,10 @@ ppp_print_hex (register u_char * out, u_char * in, int count) static char hex[] = "0123456789ABCDEF"; while (count-- > 0) { - next_ch = (u_char) get_fs_byte (in); + next_ch = *in++; *out++ = hex[(next_ch >> 4) & 0x0F]; *out++ = hex[next_ch & 0x0F]; ++out; - ++in; } } @@ -2367,46 +3313,127 @@ ppp_print_char (register u_char * out, u_char * in, int count) register u_char next_ch; while (count-- > 0) { - next_ch = (u_char) get_fs_byte (in); + next_ch = *in++; - if (next_ch < 0x20 || next_ch > 0x7e) { + if (next_ch < 0x20 || next_ch > 0x7e) *out++ = '.'; - } else { + else { *out++ = next_ch; - if (next_ch == '%') { /* printk/syslogd has a bug !! */ + if (next_ch == '%') /* printk/syslogd has a bug !! */ *out++ = '%'; - } } - ++in; } *out = '\0'; } static void -ppp_print_buffer (const u_char * name, u_char * buf, int count, int seg) +ppp_print_buffer (const u_char * name, u_char * buf, int count) { u_char line[44]; - int old_fs = get_fs (); - set_fs (seg); + if (name != (u_char *) NULL) + printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count); - if (name != (u_char *) NULL) { - PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count)); - } while (count > 8) { - memset (line, ' ', sizeof (line)); + memset (line, 32, 44); ppp_print_hex (line, buf, 8); ppp_print_char (&line[8 * 3], buf, 8); - PRINTK ((KERN_DEBUG "%s\n", line)); + printk (KERN_DEBUG "%s\n", line); count -= 8; buf += 8; } if (count > 0) { - memset (line, ' ', sizeof (line)); + memset (line, 32, 44); ppp_print_hex (line, buf, count); ppp_print_char (&line[8 * 3], buf, count); - PRINTK ((KERN_DEBUG "%s\n", line)); + printk (KERN_DEBUG "%s\n", line); + } +} + +/************************************************************* + * Module support routines + *************************************************************/ + +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; + +int +init_module(void) +{ + int status; + + /* register our line disciplines */ + status = ppp_first_time(); + if (status != 0) { + printk (KERN_INFO + "PPP: ppp_init() failure %d\n", status); + } + return (status); +} + +void +cleanup_module(void) +{ + int status; + ppp_ctrl_t *ctl, *next_ctl; + struct device *dev; + struct ppp *ppp; + int busy_flag = MOD_IN_USE; +/* + * Ensure that the devices are not in operation. + */ + if (!busy_flag) { + ctl = ppp_list; + while (ctl) { + ppp = ctl2ppp (ctl); + if (ppp->inuse && ppp->tty != NULL) { + busy_flag = 1; + break; + } + + dev = ctl2dev (ctl); + if (dev->start || dev->flags & IFF_UP) { + busy_flag = 1; + break; + } + ctl = ctl->next; + } + } + + if (busy_flag) { + printk (KERN_INFO + "PPP: device busy, remove delayed\n"); + return; + } +/* + * Release the tty registration of the line dicipline so that no new entries + * may be created. + */ + status = tty_register_ldisc (N_PPP, NULL); + if (status != 0) + printk (KERN_INFO + "PPP: Unable to unregister ppp line discipline " + "(err = %d)\n", status); + else + printk (KERN_INFO + "PPP: ppp line discipline successfully unregistered\n"); +/* + * De-register the devices so that there is no problem with them + */ + next = ppp_list; + while (next) { + ctl = next; + ppp = ctl2ppp (ctl); + dev = ctl2dev (ctl); + + ppp_release (ppp); + unregister_netdev (dev); +/* + * Release the storage occupied by the control structures + */ + next = ctl->next; + kfree (ctl); } - set_fs (old_fs); } +#endif