X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=linux%2Fppp.c;h=aa7af25d8d6187a67e1abfa8bc4732076f8c09a2;hb=4f5726f47b4c847ac16a8c04885c82f3f108e909;hp=38472f90e2de50e2dd4c904ae9caf7b4494c2bd7;hpb=fafd2a0842d230623862c59a488dc7b4500ad64a;p=ppp.git diff --git a/linux/ppp.c b/linux/ppp.c index 38472f9..aa7af25 100644 --- a/linux/ppp.c +++ b/linux/ppp.c @@ -2,11 +2,12 @@ * * Michael Callahan * Al Longyear + * Paul Mackerras * * Dynamic PPP devices by Jim Freeman . * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid * - * ==FILEVERSION 970626== + * ==FILEVERSION 980319== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -47,19 +48,10 @@ #define CHECK_CHARACTERS 1 #define PPP_COMPRESS 1 -#ifndef PPP_MAX_DEV -#define PPP_MAX_DEV 256 -#endif - -/* $Id: ppp.c,v 1.13 1997/07/14 03:50:50 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.17 1998/03/24 23:54:59 paulus Exp $ */ #include +#include /* for CONFIG_KERNELD */ #include #include #include @@ -93,6 +85,11 @@ #include #include #include + +#if LINUX_VERSION_CODE >= VERSION(2,1,68) +#include +#endif + #include #include @@ -112,6 +109,10 @@ typedef struct sk_buff sk_buff; #include #include +#ifdef CONFIG_KERNELD +#include +#endif + #ifndef PPP_IPX #define PPP_IPX 0x2b /* IPX protocol over PPP */ #endif @@ -167,6 +168,22 @@ do { \ #define test_and_set_bit(nr, addr) set_bit(nr, addr) #endif +#if LINUX_VERSION_CODE < VERSION(2,1,57) +#define signal_pending(p) ((p)->signal & ~(p)->blocked) +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,25) +#define net_device_stats enet_statistics +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,60) +typedef int rw_ret_t; +typedef unsigned int rw_count_t; +#else +typedef ssize_t rw_ret_t; +typedef size_t rw_count_t; +#endif + static int ppp_register_compressor (struct compressor *cp); static void ppp_unregister_compressor (struct compressor *cp); @@ -185,7 +202,7 @@ extern inline void ppp_stuff_char (struct ppp *ppp, 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); + __u8 *data, int len, enum NPmode npmode); static int rcv_proto_ip (struct ppp *, __u16, __u8 *, int); static int rcv_proto_ipx (struct ppp *, __u16, __u8 *, int); @@ -205,20 +222,14 @@ static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int); #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"); -MODULE_PARM(max_dev, "i"); #endif /* @@ -235,7 +246,7 @@ static int ppp_dev_open (struct device *); static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd); 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 *); +static struct net_device_stats *ppp_dev_stats (struct device *); #if LINUX_VERSION_CODE < VERSION(2,1,15) static int ppp_dev_header (sk_buff *, struct device *, __u16, @@ -248,17 +259,18 @@ static int ppp_dev_rebuild (void *eth, struct device *dev, * TTY callbacks */ -static int ppp_tty_read (struct tty_struct *, struct file *, __u8 *, - unsigned int); -static int ppp_tty_write (struct tty_struct *, struct file *, const __u8 *, - unsigned int); +static rw_ret_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *, + rw_count_t); +static rw_ret_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *, + rw_count_t); 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); +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 *); @@ -418,6 +430,9 @@ ppp_first_time (void) */ (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc)); ppp_ldisc.magic = TTY_LDISC_MAGIC; +#if LINUX_VERSION_CODE >= VERSION(2,1,28) + ppp_ldisc.name = "ppp"; +#endif ppp_ldisc.open = ppp_tty_open; ppp_ldisc.close = ppp_tty_close; ppp_ldisc.read = ppp_tty_read; @@ -455,7 +470,7 @@ ppp_init_dev (struct device *dev) dev->rebuild_header = ppp_dev_rebuild; #endif - dev->hard_header_len = PPP_HARD_HDR_LEN; + dev->hard_header_len = PPP_HDRLEN; /* device INFO */ dev->mtu = PPP_MTU; @@ -481,11 +496,13 @@ ppp_init_dev (struct device *dev) /* New-style flags */ dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; +#if LINUX_VERSION_CODE < VERSION(2,1,67) dev->family = AF_INET; dev->pa_addr = 0; dev->pa_brdaddr = 0; dev->pa_mask = 0; dev->pa_alen = 4; /* sizeof (__u32) */ +#endif return 0; } @@ -518,14 +535,11 @@ ppp_init_ctrl_blk (register struct ppp *ppp) ppp->read_wait = NULL; ppp->write_wait = NULL; ppp->last_xmit = jiffies - flag_time; + ppp->last_recv = jiffies; /* clear statistics */ memset(&ppp->stats, 0, sizeof (struct pppstat)); - memset(&ppp->estats, 0, sizeof(struct enet_statistics)); - - /* 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->estats, 0, sizeof(ppp->estats)); /* PPP compression data */ ppp->sc_xc_state = @@ -622,7 +636,7 @@ ppp_free_buf (struct ppp_buffer *ptr) extern inline int lock_buffer (register struct ppp_buffer *buf) { - register int state; + unsigned long state; unsigned long flags; /* * Save the current state and if free then set it to the "busy" state @@ -689,9 +703,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru) */ if (new_wbuf == NULL || new_tbuf == NULL || new_rbuf == NULL || new_cbuf == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp: failed to allocate new buffers\n"); + printk (KERN_ERR "ppp: failed to allocate new buffers\n"); ppp_free_buf (new_wbuf); ppp_free_buf (new_tbuf); @@ -795,7 +807,7 @@ ppp_release (struct ppp *ppp) dev = ppp2dev (ppp); if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "ppp%s released\n", ppp->name); + printk(KERN_DEBUG "%s released\n", ppp->name); ppp_ccp_closed (ppp); @@ -806,11 +818,6 @@ ppp_release (struct ppp *ppp) 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 */ - } - ppp_free_buf (ppp->rbuf); ppp_free_buf (ppp->wbuf); ppp_free_buf (ppp->cbuf); @@ -889,8 +896,7 @@ ppp_tty_open (struct tty_struct *tty) * There should not be an existing table for this slot. */ if (ppp) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR + printk (KERN_ERR "ppp_tty_open: gack! tty already associated to %s!\n", ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name : "unknown"); @@ -912,8 +918,7 @@ ppp_tty_open (struct tty_struct *tty) } else { ppp = ppp_alloc(); if (ppp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR "ppp_alloc failed\n"); + printk (KERN_ERR "ppp_alloc failed\n"); return -ENFILE; } /* @@ -927,9 +932,8 @@ ppp_tty_open (struct tty_struct *tty) */ 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"); + printk (KERN_ERR "ppp_tty_open: " + "no space for compression buffers!\n"); ppp_release (ppp); return -ENOMEM; } @@ -945,9 +949,8 @@ ppp_tty_open (struct tty_struct *tty) */ 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"); + printk (KERN_ERR "ppp_tty_open: " + "no space for user receive buffer\n"); ppp_release (ppp); return -ENOMEM; } @@ -1038,9 +1041,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty, * transmission block. */ ppp2dev (ppp)->tbusy = 0; - if (ppp2dev (ppp) -> flags & IFF_UP) { - mark_bh (NET_BH); - } + mark_bh (NET_BH); /* * Wake up the transmission queue for all completion events. */ @@ -1220,6 +1221,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * 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. @@ -1242,6 +1244,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data, } ++flags; } + /* * 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 @@ -1360,6 +1363,7 @@ ppp_doframe (struct ppp *ppp) CHECK_PPP(0); CHECK_BUF_MAGIC(ppp->rbuf); + /* * If there is a pending error from the receiver then log it and discard * the damaged frame. @@ -1418,9 +1422,7 @@ ppp_doframe (struct ppp *ppp) */ 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"); + printk (KERN_ERR "ppp_doframe: no memory\n"); new_count = DECOMP_ERROR; } else { new_count = (*ppp->sc_rcomp->decompress) @@ -1439,8 +1441,7 @@ ppp_doframe (struct ppp *ppp) case DECOMP_FATALERROR: ppp->flags |= SC_DC_FERROR; - if (ppp->flags & SC_DEBUG) - printk(KERN_ERR "ppp: fatal decomp error\n"); + printk(KERN_ERR "ppp: fatal decomp error\n"); break; } /* @@ -1458,6 +1459,10 @@ ppp_doframe (struct ppp *ppp) (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, data, count); } + } else if (proto == PPP_COMP && (ppp->flags & SC_DEBUG)) { + printk(KERN_DEBUG "ppp: frame not decompressed: " + "flags=%x, count=%d, sc_rc_state=%p\n", + ppp->flags, count, ppp->sc_rc_state); } /* * Process the uncompressed frame. @@ -1533,7 +1538,7 @@ ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count) skb->free = 1; #endif - ppp->ddinfo.recv_idle = jiffies; + ppp->last_recv = jiffies; netif_rx (skb); return 1; } @@ -1795,6 +1800,9 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd) } break; } + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "ppp_proto_ccp: %s code %d, flags=%x\n", + (rcvd? "rcvd": "sent"), CCP_CODE(dp), ppp->flags); restore_flags(flags); } @@ -1828,14 +1836,14 @@ rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len) waiting if necessary */ -static int +static rw_ret_t ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, - unsigned int nr) + rw_count_t nr) { struct ppp *ppp = tty2ppp (tty); __u8 c; - int len, ret; int error; + rw_ret_t len, ret; #define GETC(c) \ { \ @@ -1849,8 +1857,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, if (!ppp) return -EIO; - if (ppp->magic != PPP_MAGIC) - return -EIO; + /* if (ppp->magic != PPP_MAGIC) + return -EIO; */ CHECK_PPP (-ENXIO); @@ -1881,7 +1889,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, current->state = TASK_INTERRUPTIBLE; schedule (); - if (current->signal & ~current->blocked) + if (signal_pending(current)) return -EINTR; continue; } @@ -1914,7 +1922,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, "ppp_tty_read: sleeping(read_wait)\n"); #endif interruptible_sleep_on (&ppp->read_wait); - if (current->signal & ~current->blocked) + if (signal_pending(current)) return -EINTR; } @@ -1927,8 +1935,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG - "ppp: read of %u bytes too small for %d " - "frame\n", nr, len + 2); + "ppp: read of %lu bytes too small for %ld " + "frame\n", (unsigned long) nr, (long) len + 2); ppp->stats.ppp_ierrors++; error = -EOVERFLOW; goto out; @@ -1960,10 +1968,6 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * 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: @@ -2031,7 +2035,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; @@ -2118,16 +2122,15 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, (control == PPP_UI) && (proto != PPP_LCP) && (proto != PPP_CCP)) { - new_data = kmalloc (ppp->mtu, GFP_ATOMIC); + new_data = kmalloc (ppp->mtu + PPP_HDRLEN, GFP_ATOMIC); if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_dev_xmit_frame: no memory\n"); + printk (KERN_ERR "ppp_dev_xmit_frame: no memory\n"); return 1; } new_count = (*ppp->sc_xcomp->compress) - (ppp->sc_xc_state, data, new_data, count, ppp->mtu); + (ppp->sc_xc_state, data, new_data, count, + ppp->mtu + PPP_HDRLEN); if (new_count > 0 && (ppp->flags & SC_CCP_UP)) { ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0); @@ -2189,13 +2192,14 @@ send_revise_frame (register struct ppp *ppp, __u8 *data, int len) * we have to put the FCS field on ourselves */ -static int +static rw_ret_t ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, - unsigned int count) + rw_count_t count) { struct ppp *ppp = tty2ppp (tty); __u8 *new_data; - int proto; + int error; + struct wait_queue wait = {current, NULL}; /* * Verify the pointers. @@ -2214,7 +2218,7 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, if (ppp->flags & SC_DEBUG) printk (KERN_WARNING "ppp_tty_write: truncating user packet " - "from %u to mtu %d\n", count, + "from %lu to mtu %d\n", (unsigned long) count, PPP_MTU + PPP_HDRLEN); count = PPP_MTU + PPP_HDRLEN; } @@ -2223,42 +2227,48 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, */ new_data = kmalloc (count, GFP_KERNEL); if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_write: no memory\n"); + printk (KERN_ERR "ppp_tty_write: no memory\n"); return 0; } /* * Retrieve the user's buffer */ - if (copy_from_user (new_data, data, count)) { - kfree (new_data); - return -EFAULT; - } + COPY_FROM_USER (error, new_data, data, count); + if (error) + goto out_free; /* - * lock this PPP unit so we will be the only writer; - * sleep if necessary + * Lock this PPP unit so we will be the only writer, + * sleeping if necessary. + * + * Note that we add our task to the wait queue before + * attempting to lock, as the lock flag may be cleared + * from an interrupt. */ - while (lock_buffer (ppp->tbuf) != 0) { + add_wait_queue(&ppp->write_wait, &wait); + while (1) { + error = 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); + current->state = TASK_INTERRUPTIBLE; + if (lock_buffer(ppp->tbuf) == 0) + break; + schedule(); + error = -EIO; ppp = tty2ppp (tty); - if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse - || tty != ppp->tty) { - kfree (new_data); - return 0; - } - - if (current->signal & ~current->blocked) { - kfree (new_data); - return -EINTR; + if (!ppp || ppp->magic != PPP_MAGIC || + !ppp->inuse || tty != ppp->tty) { + printk("ppp_tty_write: %p invalid after wait!\n", ppp); + break; } + error = -EINTR; + if (signal_pending(current)) + break; } + current->state = TASK_RUNNING; + remove_wait_queue(&ppp->write_wait, &wait); + if (error) + goto out_free; + /* * Change the LQR frame */ @@ -2266,46 +2276,43 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, /* * Send the data */ - if (proto == PPP_IP) { + 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); + count - PPP_HDRLEN, NPMODE_PASS); } else { ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count); } + error = count; +out_free: kfree (new_data); - return (int) count; + return error; } /* - * Process the BSD compression IOCTL event for the tty device. + * Process the set-compression ioctl. */ static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) { struct compressor *cp; - struct ppp_option_data data; - int error; - int nb; + int error, nb; + unsigned long flags; __u8 *ptr; __u8 ccp_option[CCP_MAX_OPTION_LENGTH]; - unsigned long flags; + struct ppp_option_data data; /* * Fetch the compression parameters */ - COPY_FROM_USER (error, - &data, - odp, - sizeof (data)); - + COPY_FROM_USER (error, &data, odp, sizeof (data)); if (error != 0) return error; @@ -2314,11 +2321,7 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH) nb = CCP_MAX_OPTION_LENGTH; - COPY_FROM_USER (error, - ccp_option, - ptr, - nb); - + COPY_FROM_USER (error, ccp_option, ptr, nb); if (error != 0) return error; @@ -2327,52 +2330,58 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) save_flags(flags); cli(); - ppp->flags &= ~(SC_COMP_RUN | SC_DECOMP_RUN); + ppp->flags &= ~(data.transmit? 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 - * a compressor or decompressor. - */ - error = 0; - if (data.transmit) { - if (ppp->sc_xc_state != NULL) - (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); +#ifdef CONFIG_KERNELD + if (cp == NULL) { + char modname[32]; + sprintf(modname, "ppp-compress-%d", ccp_option[0]); + request_module(modname); + cp = find_compressor(ccp_option[0]); + } +#endif /* CONFIG_KERNELD */ - ppp->sc_xcomp = cp; - ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); + if (cp == NULL) + goto out_no_comp; + /* + * Found a handler for the protocol - try to allocate + * a compressor or decompressor. + */ + error = 0; + if (data.transmit) { + if (ppp->sc_xc_state != NULL) + (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); + ppp->sc_xc_state = NULL; - if (ppp->sc_xc_state == NULL) { - if (ppp->flags & SC_DEBUG) - 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); - } - } 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(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); - } - } - return (error); + ppp->sc_xcomp = cp; + ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); + if (ppp->sc_xc_state == NULL) { + printk(KERN_WARNING "%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); + } else { + if (ppp->sc_rc_state != NULL) + (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); + ppp->sc_rc_state = NULL; + + ppp->sc_rcomp = cp; + ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); + if (ppp->sc_rc_state == NULL) { + printk(KERN_WARNING "%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); } + return error; +out_no_comp: if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n", ppp->name, ccp_option[0], ccp_option[1], @@ -2389,8 +2398,9 @@ 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; + register int temp_i = 0, oldflags; int error = 0; + unsigned long flags; /* * Verify the status of the PPP device. */ @@ -2440,16 +2450,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, 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 & SC_CCP_OPEN) && (temp_i & SC_CCP_OPEN) == 0) + ppp_ccp_closed(ppp); - if ((ppp->flags | temp_i) & SC_DEBUG) + save_flags(flags); + cli(); + oldflags = ppp->flags; + ppp->flags = temp_i |= (ppp->flags & ~SC_MASK); + restore_flags(flags); + if ((oldflags | 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 @@ -2530,14 +2542,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, case PPPIOCGIDLE: { struct ppp_idle cur_ddinfo; - __u32 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; - COPY_TO_USER (error, - (void *) param3, - &cur_ddinfo, + 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; @@ -2545,9 +2554,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, * Retrieve the extended async map */ case PPPIOCGXASYNCMAP: - COPY_TO_USER (error, - (void *) param3, - ppp->xmit_async_map, + COPY_TO_USER (error, (void *) param3, ppp->xmit_async_map, sizeof (ppp->xmit_async_map)); break; /* @@ -2557,13 +2564,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, { __u32 temp_tbl[8]; - COPY_FROM_USER (error, - temp_tbl, - (void *) param3, + 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; @@ -2593,16 +2598,15 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, temp_i = (temp_i & 255) + 1; if (ppp->flags & SC_DEBUG) printk (KERN_INFO - "ppp_tty_ioctl: set maxcid to %d\n", - temp_i); + "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); + ppp->slcomp = NULL; + 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"); + printk (KERN_ERR "ppp_tty_ioctl: " + "no space for compression buffers!\n"); ppp_release (ppp); error = -ENOMEM; } @@ -2618,9 +2622,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, { struct npioctl npi; - COPY_FROM_USER (error, - &npi, - (void *) param3, + COPY_FROM_USER (error, &npi, (void *) param3, sizeof (npi)); if (error != 0) break; @@ -2632,7 +2634,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, default: if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "pppioc[gs]npmode: " - "invalid proto %d\n", npi.protocol); + "invalid protocol %d\n", + npi.protocol); error = -EINVAL; } @@ -2642,9 +2645,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, if (param2 == PPPIOCGNPMODE) { npi.mode = ppp->sc_npmode[npi.protocol]; - COPY_TO_USER (error, - (void *) param3, - &npi, + COPY_TO_USER (error, (void *) param3, &npi, sizeof (npi)); break; } @@ -2653,6 +2654,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp: set np %d to %d\n", npi.protocol, npi.mode); + ppp2dev(ppp)->tbusy = 0; + mark_bh(NET_BH); } break; /* @@ -2676,11 +2679,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, */ default: if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n", - param2, - param3); - + printk (KERN_WARNING "ppp_tty_ioctl: " + "invalid ioctl=%x, addr=%lx\n", param2, param3); error = -ENOIOCTLCMD; break; } @@ -2763,10 +2763,16 @@ ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait) if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) { CHECK_PPP (0); +#if LINUX_VERSION_CODE < VERSION(2,1,89) poll_wait(&ppp->read_wait, wait); poll_wait(&ppp->write_wait, wait); +#else + poll_wait(filp, &ppp->read_wait, wait); + poll_wait(filp, &ppp->write_wait, wait); +#endif /* 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; @@ -2801,12 +2807,8 @@ ppp_dev_open (struct device *dev) { struct ppp *ppp = dev2ppp (dev); - /* reset POINTOPOINT every time, since dev_close zaps it! */ - dev->flags |= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - if (ppp2tty (ppp) == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR + printk (KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n", dev->name); return -ENXIO; @@ -2858,10 +2860,7 @@ ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr) /* * Move the version data */ - COPY_TO_USER (error, - result, - szVersion, - len); + COPY_TO_USER (error, result, szVersion, len); return error; } @@ -2897,10 +2896,7 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev) result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; - COPY_TO_USER (error, - result, - &temp, - sizeof (temp)); + COPY_TO_USER (error, result, &temp, sizeof (temp)); return error; } @@ -2932,10 +2928,7 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev */ result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data; - COPY_TO_USER (error, - result, - &temp, - sizeof (temp)); + COPY_TO_USER (error, result, &temp, sizeof (temp)); return error; } @@ -2984,14 +2977,14 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) static int ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf, - __u8 *data, int len) + __u8 *data, int len, enum NPmode npmode) { int proto = PPP_IP; __u8 *hdr; /* * Branch on the type of processing for the IP frame. */ - switch (ppp->sc_npmode[NP_IP]) { + switch (npmode) { case NPMODE_PASS: break; @@ -3052,7 +3045,7 @@ ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf, hdr[2] = 0; hdr[3] = proto; - return ppp_dev_xmit_frame (ppp, ppp->wbuf, hdr, len); + return ppp_dev_xmit_frame (ppp, buf, hdr, len); } /* @@ -3083,6 +3076,11 @@ ppp_dev_xmit_other (struct device *dev, struct ppp *ppp, /* * Send a frame to the remote. */ +#if LINUX_VERSION_CODE < VERSION(2,1,86) +#define FREE_SKB(skb) dev_kfree_skb(skb) +#else +#define FREE_SKB(skb) dev_kfree_skb(skb, FREE_WRITE) +#endif static int ppp_dev_xmit (sk_buff *skb, struct device *dev) @@ -3103,7 +3101,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) * Avoid timing problem should tty hangup while data is queued to be sent */ if (!ppp->inuse) { - dev_kfree_skb (skb, FREE_WRITE); + FREE_SKB (skb); return 0; } /* @@ -3114,7 +3112,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) printk (KERN_ERR "ppp_dev_xmit: %s not connected to a TTY!\n", dev->name); - dev_kfree_skb (skb, FREE_WRITE); + FREE_SKB (skb); return 0; } /* @@ -3127,7 +3125,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) if (ppp->flags & SC_DEBUG) printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n", dev->name); - dev_kfree_skb (skb, FREE_WRITE); + FREE_SKB (skb); return 0; } /* @@ -3149,7 +3147,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) if (ppp->tbuf->locked || lock_buffer (ppp->wbuf) != 0) { dev->tbusy = 1; if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "dev_xmit blocked, t=%d w=%d\n", + printk(KERN_DEBUG "dev_xmit blocked, t=%lu w=%lu\n", ppp->tbuf->locked, ppp->wbuf->locked); return 1; } @@ -3163,11 +3161,12 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) break; case ETH_P_IP: - answer = ppp_dev_xmit_ip (ppp, ppp->wbuf, data, len); + 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. */ - dev_kfree_skb (skb, FREE_WRITE); + FREE_SKB (skb); return 0; } /* @@ -3175,13 +3174,12 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) */ if (answer == 0) { /* packet queued OK */ - dev_kfree_skb (skb, FREE_WRITE); - ppp->ddinfo.xmit_idle = jiffies; + FREE_SKB (skb); } else { ppp->wbuf->locked = 0; if (answer < 0) { /* packet should be dropped */ - dev_kfree_skb (skb, FREE_WRITE); + FREE_SKB (skb); answer = 0; } else { /* packet should be queued for later */ @@ -3195,15 +3193,19 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev) * Generate the statistic information for the /proc/net/dev listing. */ -static struct enet_statistics * +static struct net_device_stats * ppp_dev_stats (struct device *dev) { struct ppp *ppp = dev2ppp (dev); - 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; + 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 return &ppp->estats; } @@ -3245,6 +3247,29 @@ ppp_find (int pid_value) return ppp; } +/* Collect hung up channels */ + +static void ppp_sync(void) +{ + struct device *dev; + struct ppp *ppp; + +#if LINUX_VERSION_CODE >= VERSION(2,1,68) + rtnl_lock(); +#endif + for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { + if (!ppp->inuse) { + dev = ppp2dev(ppp); + if (dev->flags & IFF_UP) + dev_close(dev); + } + } +#if LINUX_VERSION_CODE >= VERSION(2,1,68) + rtnl_unlock(); +#endif +} + + /* allocate or create a PPP channel */ static struct ppp * ppp_alloc (void) @@ -3254,11 +3279,24 @@ ppp_alloc (void) struct device *dev; struct ppp *ppp; + ppp_sync(); + /* try to find an free device */ if_num = 0; for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { - if (!set_bit(0, &ppp->inuse)) + if (!test_and_set_bit(0, &ppp->inuse)) { + + /* Reregister device */ + + dev = ppp2dev(ppp); + unregister_netdev (dev); + + if (register_netdev (dev)) { + printk(KERN_DEBUG "cannot reregister ppp device\n"); + return NULL; + } return ppp; + } ++if_num; } /*