X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=linux%2Fppp.c;h=8cc2727179ff912ee64c66f4de3907d26a33b87e;hp=66c5e185f1306e46c3d3f492dadb538bffb4e674;hb=7d7bc679a40a78e9f255635dacc5e1247176d075;hpb=492bed62999458a3e61f9d46b929ce1e1ca8a72b diff --git a/linux/ppp.c b/linux/ppp.c index 66c5e18..8cc2727 100644 --- a/linux/ppp.c +++ b/linux/ppp.c @@ -4,7 +4,7 @@ * Al Longyear * Extensively rewritten by Paul Mackerras * - * ==FILEVERSION 980704== + * ==FILEVERSION 990412== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -45,7 +45,7 @@ #define PPP_MAX_RCV_QLEN 32 /* max # frames we queue up for pppd */ -/* $Id: ppp.c,v 1.19 1998/07/07 04:27:37 paulus Exp $ */ +/* $Id: ppp.c,v 1.25 1999/04/16 11:29:13 paulus Exp $ */ #include #include @@ -103,6 +103,9 @@ #include #endif +#undef PPP_VERSION +#define PPP_VERSION "2.3.7" + #if LINUX_VERSION_CODE >= VERSION(2,1,4) #if LINUX_VERSION_CODE >= VERSION(2,1,5) @@ -142,7 +145,7 @@ #endif #if LINUX_VERSION_CODE < VERSION(2,1,57) -#define signal_pending(tsk) ((tsk)->pending & ~(tsk)->blocked) +#define signal_pending(tsk) ((tsk)->signal & ~(tsk)->blocked) #endif #if LINUX_VERSION_CODE < VERSION(2,1,60) @@ -153,6 +156,24 @@ typedef ssize_t rw_ret_t; typedef size_t rw_count_t; #endif +#if LINUX_VERSION_CODE < VERSION(2,1,86) +#define KFREE_SKB(s) dev_kfree_skb((s), FREE_WRITE) +#else +#define KFREE_SKB(s) kfree_skb(s) +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,15) +#define LIBERATE_SKB(s) ((s)->free = 1) +#else +#define LIBERATE_SKB(s) do { } while (0) +#endif + +#if LINUX_VERSION_CODE < VERSION(2,1,95) +#define SUSER() suser() +#else +#define SUSER() capable(CAP_NET_ADMIN) +#endif + /* * Local functions */ @@ -164,9 +185,11 @@ static void ppp_unregister_compressor (struct compressor *cp); static void ppp_async_init(struct ppp *ppp); static void ppp_async_release(struct ppp *ppp); +static int ppp_tty_sync_push(struct ppp *ppp); static int ppp_tty_push(struct ppp *ppp); static int ppp_async_encode(struct ppp *ppp); static int ppp_async_send(struct ppp *, struct sk_buff *); +static int ppp_sync_send(struct ppp *, struct sk_buff *); static int ppp_ioctl(struct ppp *, unsigned int, unsigned long); static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp); @@ -177,6 +200,7 @@ static void ppp_receive_error(struct ppp *ppp); static void ppp_output_wakeup(struct ppp *ppp); static void ppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); +static void ppp_send_frames(struct ppp *ppp); static struct sk_buff *ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb); static struct ppp *ppp_find (int pid_value); @@ -238,7 +262,6 @@ static struct symbol_table ppp_syms = { #include X(ppp_register_compressor), X(ppp_unregister_compressor), - X(ppp_crc16_table), #include }; #else @@ -315,7 +338,6 @@ __u16 ppp_crc16_table[256] = 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -EXPORT_SYMBOL(ppp_crc16_table); #ifdef CHECK_CHARACTERS static __u32 paritytab[8] = @@ -350,7 +372,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; @@ -438,10 +462,10 @@ ppp_async_release(struct ppp *ppp) struct sk_buff *skb; if ((skb = ppp->rpkt) != NULL) - kfree_skb(skb); + KFREE_SKB(skb); ppp->rpkt = NULL; if ((skb = ppp->tpkt) != NULL) - kfree_skb(skb); + KFREE_SKB(skb); ppp->tpkt = NULL; } @@ -526,6 +550,9 @@ ppp_tty_close (struct tty_struct *tty) return; if (ppp->backup_tty) { ppp->tty = ppp->backup_tty; + if (ppp_tty_push(ppp)) + ppp_output_wakeup(ppp); + wake_up_interruptible(&ppp->read_wait); } else { ppp->tty = 0; ppp->sc_xfer = 0; @@ -535,7 +562,6 @@ ppp_tty_close (struct tty_struct *tty) ppp_async_release(ppp); ppp_release(ppp); - ppp->inuse = 0; MOD_DEC_USE_COUNT; } } @@ -592,7 +618,6 @@ ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf, if (file->f_flags & O_NONBLOCK) break; - current->timeout = 0; interruptible_sleep_on(&ppp->read_wait); err = -EINTR; if (signal_pending(current)) @@ -620,12 +645,12 @@ ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf, /* * Copy the received data from the buffer to the caller's area. */ - err = COPY_TO_USER(buf, skb->data, len); - if (err == 0) - err = len; + err = len; + if (COPY_TO_USER(buf, skb->data, len)) + err = -EFAULT; out: - kfree_skb(skb); + KFREE_SKB(skb); return err; } @@ -672,13 +697,14 @@ ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data, printk(KERN_ERR "ppp_tty_write: no memory\n"); return 0; } + LIBERATE_SKB(skb); new_data = skb_put(skb, count); /* * Retrieve the user's buffer */ if (COPY_FROM_USER(new_data, data, count)) { - kfree_skb(skb); + KFREE_SKB(skb); return -EFAULT; } @@ -712,7 +738,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, /* * The user must have an euid of root to do these requests. */ - if (!capable(CAP_NET_ADMIN)) + if (!SUSER()) return -EPERM; switch (param2) { @@ -931,6 +957,135 @@ ppp_tty_wakeup (struct tty_struct *tty) ppp_output_wakeup(ppp); } +/* + * Send a packet to the peer over a synchronous tty line. + * All encoding and FCS are handled by hardware. + * Addr/Ctrl and Protocol field compression implemented. + * Returns -1 iff the packet could not be accepted at present, + * 0 if the packet was accepted but we can't accept another yet, or + * 1 if we can accept another packet immediately. + * If this procedure returns 0, ppp_output_wakeup will be called + * exactly once. + */ +static int +ppp_sync_send(struct ppp *ppp, struct sk_buff *skb) +{ + unsigned char *data; + int islcp; + + CHECK_PPP(0); + + if (ppp->tpkt != NULL) + return -1; + ppp->tpkt = skb; + + data = ppp->tpkt->data; + + /* + * LCP packets with code values between 1 (configure-reqest) + * and 7 (code-reject) must be sent as though no options + * had been negotiated. + */ + islcp = PPP_PROTOCOL(data) == PPP_LCP + && 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7; + + /* only reset idle time for data packets */ + if (PPP_PROTOCOL(data) < 0x8000) + ppp->last_xmit = jiffies; + ++ppp->stats.ppp_opackets; + ppp->stats.ppp_ooctects += ppp->tpkt->len; + + if ( !(data[2]) && (ppp->flags & SC_COMP_PROT) ) { + /* compress protocol field */ + data[2] = data[1]; + data[1] = data[0]; + skb_pull(ppp->tpkt,1); + data = ppp->tpkt->data; + } + + /* + * Do address/control compression + */ + if ((ppp->flags & SC_COMP_AC) && !islcp + && PPP_ADDRESS(data) == PPP_ALLSTATIONS + && PPP_CONTROL(data) == PPP_UI) { + /* strip addr and control field */ + skb_pull(ppp->tpkt,2); + } + + return ppp_tty_sync_push(ppp); +} + +/* + * Push a synchronous frame out to the tty. + * Returns 1 if frame accepted (or discarded), 0 otherwise. + */ +static int +ppp_tty_sync_push(struct ppp *ppp) +{ + int sent; + struct tty_struct *tty = ppp2tty(ppp); + unsigned long flags; + + CHECK_PPP(0); + + if (ppp->tpkt == NULL) + return 0; + + /* prevent reentrancy with tty_pushing flag */ + save_flags(flags); + cli(); + if (ppp->tty_pushing) { + /* record wakeup attempt so we don't loose */ + /* a wakeup call while doing push processing */ + ppp->woke_up=1; + restore_flags(flags); + return 0; + } + ppp->tty_pushing = 1; + restore_flags(flags); + + if (tty == NULL || tty->disc_data != (void *) ppp) + goto flush; + + for(;;){ + ppp->woke_up=0; + + /* Note: Sync driver accepts complete frame or nothing */ + tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len); + if (sent < 0) { + /* write error (possible loss of CD) */ + /* record error and discard current packet */ + ppp->stats.ppp_oerrors++; + break; + } + ppp->stats.ppp_obytes += sent; + if (sent < ppp->tpkt->len) { + /* driver unable to accept frame just yet */ + save_flags(flags); + cli(); + if (ppp->woke_up) { + /* wake up called while processing */ + /* try to send the frame again */ + restore_flags(flags); + continue; + } + /* wait for wakeup callback to try send again */ + ppp->tty_pushing = 0; + restore_flags(flags); + return 0; + } + break; + } +flush: + /* done with current packet (sent or discarded) */ + KFREE_SKB(ppp->tpkt); + ppp->tpkt = 0; + ppp->tty_pushing = 0; + return 1; +} + /* * Send a packet to the peer over an async tty line. * Returns -1 iff the packet could not be accepted at present, @@ -963,6 +1118,9 @@ ppp_tty_push(struct ppp *ppp) { int avail, sent, done = 0; struct tty_struct *tty = ppp2tty(ppp); + + if ( ppp->flags & SC_SYNC ) + return ppp_tty_sync_push(ppp); CHECK_PPP(0); if (ppp->tty_pushing) @@ -994,7 +1152,7 @@ flush: ppp->tty_pushing = 1; ppp->stats.ppp_oerrors++; if (ppp->tpkt != 0) { - kfree_skb(ppp->tpkt); + KFREE_SKB(ppp->tpkt); ppp->tpkt = 0; done = 1; } @@ -1098,7 +1256,7 @@ ppp_async_encode(struct ppp *ppp) *buf++ = PPP_FLAG; ppp->olim = buf; - kfree_skb(ppp->tpkt); + KFREE_SKB(ppp->tpkt); ppp->tpkt = 0; return 1; } @@ -1161,6 +1319,74 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data, ppp->stats.ppp_ibytes += count; skb = ppp->rpkt; + + if ( ppp->flags & SC_SYNC ) { + /* synchronous mode */ + + if (ppp->toss==0xE0) { + /* this is the 1st frame, reset vj comp */ + ppp_receive_error(ppp); + ppp->toss = 0; + } + + /* + * Allocate an skbuff for frame. + * The 128 is room for VJ header expansion. + */ + + if (skb == NULL) + skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN); + + if (skb == NULL) { + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "couldn't " + "alloc skb for recv\n"); + } else { + LIBERATE_SKB(skb); + /* + * Decompress A/C and protocol compression here. + */ + p = skb_put(skb, 2); + p[0] = PPP_ALLSTATIONS; + p[1] = PPP_UI; + if (*data == PPP_ALLSTATIONS) { + data += 2; + count -= 2; + } + if ((*data & 1) != 0) { + p = skb_put(skb, 1); + p[0] = 0; + } + + /* copy frame to socket buffer */ + p = skb_put(skb, count); + memcpy(p,data,count); + + /* + * Check if we've overflowed the MRU + */ + if (skb->len >= ppp->mru + PPP_HDRLEN + 2 + || skb_tailroom(skb) <= 0) { + ++ppp->estats.rx_length_errors; + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "rcv frame too long: " + "len=%d mru=%d hroom=%d troom=%d\n", + skb->len, ppp->mru, skb_headroom(skb), + skb_tailroom(skb)); + } else { + if (!ppp_receive_frame(ppp, skb)) { + KFREE_SKB(skb); + ppp_receive_error(ppp); + } + } + + /* Reset for the next frame */ + skb = NULL; + } + ppp->rpkt = skb; + return; + } + while (count-- > 0) { /* * Collect the character and error condition for the character. @@ -1227,7 +1453,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data, "ppp: tossing frame (%x)\n", ppp->toss); if (skb != NULL) - kfree_skb(skb); + KFREE_SKB(skb); if (!(ppp->toss == 0xE0 || ppp->toss == 0x80)) ++ppp->stats.ppp_ierrors; ppp_receive_error(ppp); @@ -1276,6 +1502,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data, ppp->toss = 1; continue; } + LIBERATE_SKB(skb); } /* @@ -1355,6 +1582,7 @@ typedef struct ppp_proto_struct { } ppp_proto_type; static int rcv_proto_ip (struct ppp *, struct sk_buff *); +static int rcv_proto_ipv6 (struct ppp *, struct sk_buff *); static int rcv_proto_ipx (struct ppp *, struct sk_buff *); static int rcv_proto_at (struct ppp *, struct sk_buff *); static int rcv_proto_vjc_comp (struct ppp *, struct sk_buff *); @@ -1365,6 +1593,7 @@ static int rcv_proto_unknown (struct ppp *, struct sk_buff *); static ppp_proto_type proto_list[] = { { PPP_IP, rcv_proto_ip }, + { PPP_IPV6, rcv_proto_ipv6 }, { PPP_IPX, rcv_proto_ipx }, { PPP_AT, rcv_proto_at }, { PPP_VJC_COMP, rcv_proto_vjc_comp }, @@ -1504,7 +1733,9 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } - return COPY_TO_USER((void *) ifr->ifr_ifru.ifru_data, &u, nb); + if (COPY_TO_USER((void *) ifr->ifr_ifru.ifru_data, &u, nb)) + return -EFAULT; + return 0; } /* @@ -1525,7 +1756,7 @@ ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3) /* * The user must have an euid of root to do these requests. */ - if (!capable(CAP_NET_ADMIN)) + if (!SUSER()) return -EPERM; switch (param2) { @@ -1537,6 +1768,7 @@ ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3) break; if (temp_i < PPP_MRU) temp_i = PPP_MRU; + ppp->mru = temp_i; if (ppp->flags & SC_DEBUG) printk(KERN_INFO "ppp_ioctl: set mru to %x\n", temp_i); @@ -1736,8 +1968,9 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) /* * Fetch the compression parameters */ + error = -EFAULT; if (COPY_FROM_USER(&data, odp, sizeof (data))) - return -EFAULT; + goto out; nb = data.length; ptr = data.ptr; @@ -1745,10 +1978,11 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) nb = CCP_MAX_OPTION_LENGTH; if (COPY_FROM_USER(ccp_option, ptr, nb)) - return -EFAULT; + goto out; + error = -EINVAL; if (ccp_option[1] < 2) /* preliminary check on the length byte */ - return -EINVAL; + goto out; save_flags(flags); cli(); @@ -1771,7 +2005,7 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) "%s: no compressor for [%x %x %x], %x\n", ppp->name, ccp_option[0], ccp_option[1], ccp_option[2], nb); - return -EINVAL; /* compressor not loaded */ + goto out; /* compressor not loaded */ } /* @@ -1786,7 +2020,6 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) 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(KERN_DEBUG "%s: comp_alloc failed\n", @@ -1807,7 +2040,7 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) error = -ENOBUFS; } } - +out: return error; } @@ -1977,7 +2210,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb) if (skb == NULL) return 1; if (skb->len == 0) { - kfree_skb(skb); + KFREE_SKB(skb); return 1; } data = skb->data; @@ -1994,23 +2227,25 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb) return 0; } - /* - * Verify the FCS of the frame and discard the FCS characters - * from the end of the buffer. - */ - if (ppp->rfcs != PPP_GOODFCS) { - if (ppp->flags & SC_DEBUG) { - printk(KERN_DEBUG - "ppp: frame with bad fcs, length = %d\n", - count); - ppp_print_buffer("bad frame", data, count); + if ( !(ppp->flags & SC_SYNC) ) { + /* + * Verify the FCS of the frame and discard the FCS characters + * from the end of the buffer. + */ + if (ppp->rfcs != PPP_GOODFCS) { + if (ppp->flags & SC_DEBUG) { + printk(KERN_DEBUG + "ppp: frame with bad fcs, length = %d\n", + count); + ppp_print_buffer("bad frame", data, count); + } + ++ppp->estats.rx_crc_errors; + return 0; } - ++ppp->estats.rx_crc_errors; - return 0; + count -= 2; /* ignore the fcs characters */ + skb_trim(skb, count); } - count -= 2; /* ignore the fcs characters */ - skb_trim(skb, count); - + /* * Process the active decompressor. */ @@ -2026,13 +2261,14 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb) printk(KERN_ERR "ppp_recv_frame: no memory\n"); new_count = DECOMP_ERROR; } else { + LIBERATE_SKB(new_skb); new_count = (*ppp->sc_rcomp->decompress) (ppp->sc_rc_state, data, count, new_skb->data, ppp->mru + PPP_HDRLEN); } if (new_count > 0) { /* Frame was decompressed OK */ - kfree_skb(skb); + KFREE_SKB(skb); skb = new_skb; count = new_count; data = skb_put(skb, count); @@ -2047,7 +2283,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb) printk(KERN_INFO "%s: decomp err %d\n", ppp->name, new_count); if (new_skb != 0) - kfree_skb(new_skb); + KFREE_SKB(new_skb); if (ppp->slcomp != 0) slhc_toss(ppp->slcomp); ++ppp->stats.ppp_ierrors; @@ -2095,7 +2331,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb) * Update the appropriate statistic counter. */ if (!(*proto_ptr->func)(ppp, skb)) { - kfree_skb(skb); + KFREE_SKB(skb); ++ppp->stats.ppp_discards; } @@ -2127,12 +2363,9 @@ ppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb) */ skb->dev = ppp2dev(ppp); /* We are the device */ skb->protocol = htons(proto); - skb->mac.raw = skb->data; skb_pull(skb, PPP_HDRLEN); /* pull off ppp header */ + skb->mac.raw = skb->data; ppp->last_recv = jiffies; -#if LINUX_VERSION_CODE < VERSION(2,1,15) - skb->free = 1; -#endif netif_rx (skb); return 1; } @@ -2150,6 +2383,19 @@ rcv_proto_ip(struct ppp *ppp, struct sk_buff *skb) return 0; } +/* + * Process the receipt of an IPv6 frame + */ +static int +rcv_proto_ipv6(struct ppp *ppp, struct sk_buff *skb) +{ + CHECK_PPP(0); + if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0) + && ppp->sc_npmode[NP_IPV6] == NPMODE_PASS) + return ppp_rcv_rx(ppp, ETH_P_IPV6, skb); + return 0; +} + /* * Process the receipt of an IPX frame */ @@ -2189,13 +2435,17 @@ rcv_proto_vjc_comp(struct ppp *ppp, struct sk_buff *skb) return 0; new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN, skb->len - PPP_HDRLEN); - if (new_count < 0) { + if (new_count <= 0) { if (ppp->flags & SC_DEBUG) printk(KERN_NOTICE "ppp: error in VJ decompression\n"); return 0; } - skb_put(skb, new_count + PPP_HDRLEN - skb->len); + new_count += PPP_HDRLEN; + if (new_count > skb->len) + skb_put(skb, new_count - skb->len); + else + skb_trim(skb, new_count); return rcv_proto_ip(ppp, skb); } @@ -2240,7 +2490,7 @@ rcv_proto_unknown(struct ppp *ppp, struct sk_buff *skb) while (ppp->rcv_q.qlen > PPP_MAX_RCV_QLEN) { struct sk_buff *skb = skb_dequeue(&ppp->rcv_q); if (skb) - kfree_skb(skb); + KFREE_SKB(skb); } wake_up_interruptible (&ppp->read_wait); @@ -2265,8 +2515,8 @@ extern inline __u8 * store_long (register __u8 *p, register int value) { /* * Compress and send an frame to the peer. - * Should be called with dev->tbusy == 1, having been set by the caller. - * That is, we use dev->tbusy as a lock to prevent reentry of this + * Should be called with xmit_busy == 1, having been set by the caller. + * That is, we use xmit_busy as a lock to prevent reentry of this * procedure. */ static void @@ -2337,10 +2587,11 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) new_skb = alloc_skb(ppp->mtu + PPP_HDRLEN, GFP_ATOMIC); if (new_skb == NULL) { printk(KERN_ERR "ppp_send_frame: no memory\n"); - kfree_skb(skb); - ppp->dev.tbusy = 0; + KFREE_SKB(skb); + ppp->xmit_busy = 0; return; } + LIBERATE_SKB(new_skb); /* Compress the frame. */ new_count = (*ppp->sc_xcomp->compress) @@ -2350,26 +2601,29 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) /* Did it compress? */ if (new_count > 0 && (ppp->flags & SC_CCP_UP)) { skb_put(new_skb, new_count); - kfree_skb(skb); + KFREE_SKB(skb); skb = new_skb; } else { /* * The frame could not be compressed, or it could not * be sent in compressed form because CCP is down. */ - kfree_skb(new_skb); + KFREE_SKB(new_skb); } } /* * Send the frame */ - ret = ppp_async_send(ppp, skb); + if ( ppp->flags & SC_SYNC ) + ret = ppp_sync_send(ppp, skb); + else + ret = ppp_async_send(ppp, skb); if (ret > 0) { /* we can release the lock */ - ppp->dev.tbusy = 0; + ppp->xmit_busy = 0; } else if (ret < 0) { - /* this can't happen, since the caller got the tbusy lock */ + /* can't happen, since the caller got the xmit_busy lock */ printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n"); } } @@ -2389,6 +2643,7 @@ ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb) printk(KERN_ERR "ppp: no memory for vj compression\n"); return skb; } + LIBERATE_SKB(new_skb); orig_data = data = skb->data + PPP_HDRLEN; len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN, @@ -2397,7 +2652,7 @@ ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb) if (data == orig_data) { /* Couldn't compress the data */ - kfree_skb(new_skb); + KFREE_SKB(new_skb); return skb; } @@ -2419,7 +2674,7 @@ ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb) data[2] = 0; data[3] = proto; - kfree_skb(skb); + KFREE_SKB(skb); return new_skb; } @@ -2428,15 +2683,18 @@ ppp_send_frames(struct ppp *ppp) { struct sk_buff *skb; - while (!test_and_set_bit(0, &ppp->dev.tbusy)) { + while (!test_and_set_bit(0, &ppp->xmit_busy)) { skb = skb_dequeue(&ppp->xmt_q); if (skb == NULL) { - ppp->dev.tbusy = 0; - mark_bh(NET_BH); + ppp->xmit_busy = 0; break; } ppp_send_frame(ppp, skb); } + if (!ppp->xmit_busy && ppp->dev.tbusy) { + ppp->dev.tbusy = 0; + mark_bh(NET_BH); + } } /* @@ -2448,11 +2706,11 @@ ppp_output_wakeup(struct ppp *ppp) { CHECK_PPP_VOID(); - if (!ppp->dev.tbusy) { - printk(KERN_ERR "ppp_output_wakeup called but tbusy==0\n"); + if (!ppp->xmit_busy) { + printk(KERN_ERR "ppp_output_wakeup called but xmit_busy==0\n"); return; } - ppp->dev.tbusy = 0; + ppp->xmit_busy = 0; ppp_send_frames(ppp); } @@ -2494,7 +2752,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) if (skb == NULL) return 0; if (skb->data == NULL) { - kfree_skb(skb); + KFREE_SKB(skb); return 0; } @@ -2503,7 +2761,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) * queued to be sent. */ if (!ppp->inuse) { - dev_kfree_skb(skb); + KFREE_SKB(skb); return 0; } @@ -2515,7 +2773,7 @@ ppp_dev_xmit(struct 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); + KFREE_SKB(skb); return 0; } @@ -2528,6 +2786,10 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) proto = PPP_IP; npmode = ppp->sc_npmode[NP_IP]; break; + case ETH_P_IPV6: + proto = PPP_IPV6; + npmode = ppp->sc_npmode[NP_IPV6]; + break; case ETH_P_IPX: proto = PPP_IPX; npmode = ppp->sc_npmode[NP_IPX]; @@ -2541,7 +2803,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) if (ppp->flags & SC_DEBUG) printk(KERN_INFO "%s: packet for unknown proto %x\n", ppp->name, ntohs(skb->protocol)); - dev_kfree_skb(skb); + KFREE_SKB(skb); return 0; } @@ -2560,7 +2822,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) */ if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: returning frame\n", ppp->name); - dev_kfree_skb(skb); + KFREE_SKB(skb); return 0; case NPMODE_ERROR: @@ -2569,7 +2831,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) printk(KERN_DEBUG "ppp_dev_xmit: dropping (npmode = %d) on %s\n", npmode, ppp->name); - dev_kfree_skb(skb); + KFREE_SKB(skb); return 0; } @@ -2577,9 +2839,15 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) * The dev->tbusy field acts as a lock to allow only * one packet to be processed at a time. If we can't * get the lock, try again later. + * We deliberately queue as little as possible inside + * the ppp driver in order to minimize the latency + * for high-priority packets. */ - if (test_and_set_bit(0, &dev->tbusy)) + if (test_and_set_bit(0, &ppp->xmit_busy)) { + dev->tbusy = 1; /* can't take it now */ return 1; + } + dev->tbusy = 0; /* * Put the 4-byte PPP header on the packet. @@ -2592,13 +2860,15 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) if (new_skb == NULL) { printk(KERN_ERR "%s: skb hdr alloc failed\n", ppp->name); - dev_kfree_skb(skb); - dev->tbusy = 0; + KFREE_SKB(skb); + ppp->xmit_busy = 0; + ppp_send_frames(ppp); return 0; } + LIBERATE_SKB(new_skb); skb_reserve(new_skb, PPP_HDRLEN); memcpy(skb_put(new_skb, skb->len), skb->data, skb->len); - dev_kfree_skb(skb); + KFREE_SKB(skb); skb = new_skb; } @@ -2609,6 +2879,8 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev) hdr[3] = proto; ppp_send_frame(ppp, skb); + if (!ppp->xmit_busy) + ppp_send_frames(ppp); return 0; } @@ -2718,7 +2990,12 @@ ppp_alloc(void) */ dev = ppp2dev(ppp); dev->name = ppp->name; +#if LINUX_VERSION_CODE < VERSION(2,1,31) + if_num = (ppp_list == 0)? 0: ppp_last->line + 1; + sprintf(ppp->name, "ppp%d", if_num); +#else if_num = dev_alloc_name(dev, "ppp%d"); +#endif if (if_num < 0) { printk(KERN_ERR "ppp: dev_alloc_name failed (%d)\n", if_num); kfree(ppp); @@ -2772,6 +3049,7 @@ ppp_generic_init(struct ppp *ppp) ppp->last_xmit = jiffies; ppp->last_recv = jiffies; + ppp->xmit_busy = 0; /* clear statistics */ memset(&ppp->stats, 0, sizeof (struct pppstat)); @@ -2809,9 +3087,15 @@ ppp_release(struct ppp *ppp) } while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL) - kfree_skb(skb); + KFREE_SKB(skb); while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL) - kfree_skb(skb); + KFREE_SKB(skb); + + ppp->inuse = 0; + if (ppp->dev.tbusy) { + ppp->dev.tbusy = 0; + mark_bh(NET_BH); + } } /*