* Al Longyear <longyear@netcom.com>
* Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
*
- * ==FILEVERSION 980704==
+ * ==FILEVERSION 990910==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the
#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.33 1999/12/23 01:48:45 paulus Exp $ */
#include <linux/version.h>
#include <linux/config.h>
#include <linux/kerneld.h>
#endif
+#undef PPP_VERSION
+#define PPP_VERSION "2.3.11"
+
#if LINUX_VERSION_CODE >= VERSION(2,1,4)
#if LINUX_VERSION_CODE >= VERSION(2,1,5)
#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)
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
+
+#if LINUX_VERSION_CODE < VERSION(2,2,0)
+#define wmb() mb()
+#endif
+
/*
* Local functions
*/
-#ifdef CONFIG_MODULES
static int ppp_register_compressor (struct compressor *cp);
static void ppp_unregister_compressor (struct compressor *cp);
-#endif
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 void ppp_tty_flush_output(struct ppp *);
static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
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);
#include <linux/symtab_begin.h>
X(ppp_register_compressor),
X(ppp_unregister_compressor),
- X(ppp_crc16_table),
#include <linux/symtab_end.h>
};
#else
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
+#if LINUX_VERSION_CODE >= VERSION(2,1,18)
EXPORT_SYMBOL(ppp_crc16_table);
+#endif
#ifdef CHECK_CHARACTERS
static __u32 paritytab[8] =
*/
(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;
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;
}
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;
ppp_async_release(ppp);
ppp_release(ppp);
- ppp->inuse = 0;
MOD_DEC_USE_COUNT;
}
}
if (file->f_flags & O_NONBLOCK)
break;
- current->timeout = 0;
interruptible_sleep_on(&ppp->read_wait);
err = -EINTR;
if (signal_pending(current))
/*
* 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;
}
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;
}
/*
* The user must have an euid of root to do these requests.
*/
- if (!capable(CAP_NET_ADMIN))
+ if (!SUSER())
return -EPERM;
switch (param2) {
error = n_tty_ioctl (tty, file, param2, param3);
break;
+ case TCFLSH:
+ /*
+ * Flush our buffers, then call the generic code to
+ * flush the serial port's buffer.
+ */
+ if (param3 == TCIFLUSH || param3 == TCIOFLUSH) {
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
+ KFREE_SKB(skb);
+ }
+ if (param3 == TCIOFLUSH || param3 == TCOFLUSH)
+ ppp_tty_flush_output(ppp);
+ error = n_tty_ioctl (tty, file, param2, param3);
+ break;
+
case FIONREAD:
/*
* Returns how many bytes are available for a read().
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 lose */
+ /* 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,
{
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)
+ if (ppp->tty_pushing) {
+ ppp->woke_up = 1;
return 0;
+ }
if (tty == NULL || tty->disc_data != (void *) ppp)
goto flush;
while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
ppp->tty_pushing = 1;
+ mb();
+ ppp->woke_up = 0;
avail = ppp->olim - ppp->optr;
if (avail > 0) {
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
ppp->stats.ppp_obytes += sent;
ppp->optr += sent;
if (sent < avail) {
+ wmb();
ppp->tty_pushing = 0;
+ mb();
+ if (ppp->woke_up)
+ continue;
return done;
}
}
if (ppp->tpkt != 0)
done = ppp_async_encode(ppp);
+ wmb();
ppp->tty_pushing = 0;
}
return done;
flush:
ppp->tty_pushing = 1;
+ mb();
ppp->stats.ppp_oerrors++;
if (ppp->tpkt != 0) {
- kfree_skb(ppp->tpkt);
+ KFREE_SKB(ppp->tpkt);
ppp->tpkt = 0;
done = 1;
}
ppp->optr = ppp->olim;
+ wmb();
ppp->tty_pushing = 0;
return done;
}
*buf++ = PPP_FLAG;
ppp->olim = buf;
- kfree_skb(ppp->tpkt);
+ KFREE_SKB(ppp->tpkt);
ppp->tpkt = 0;
return 1;
}
return 0;
}
+/*
+ * Flush output from our internal buffers.
+ * Called for the TCFLSH ioctl.
+ */
+static void
+ppp_tty_flush_output(struct ppp *ppp)
+{
+ struct sk_buff *skb;
+ int done = 0;
+
+ while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
+ KFREE_SKB(skb);
+ ppp->tty_pushing = 1;
+ mb();
+ ppp->optr = ppp->olim;
+ if (ppp->tpkt != NULL) {
+ KFREE_SKB(ppp->tpkt);
+ ppp->tpkt = 0;
+ done = 1;
+ }
+ wmb();
+ ppp->tty_pushing = 0;
+ if (done)
+ ppp_output_wakeup(ppp);
+}
+
/*
* Callback function from tty driver. Return the amount of space left
* in the receiver's buffer to decide if remote transmitter is to be
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.
"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);
ppp->toss = 1;
continue;
}
+ LIBERATE_SKB(skb);
}
/*
} 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 *);
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 },
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;
}
/*
/*
* The user must have an euid of root to do these requests.
*/
- if (!capable(CAP_NET_ADMIN))
+ if (!SUSER())
return -EPERM;
switch (param2) {
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);
break;
switch (npi.protocol) {
+ case PPP_IPV6:
+ npi.protocol = NP_IPV6;
+ break;
case PPP_IP:
npi.protocol = NP_IP;
break;
/*
* Fetch the compression parameters
*/
+ error = -EFAULT;
if (COPY_FROM_USER(&data, odp, sizeof (data)))
- return -EFAULT;
+ goto out;
nb = data.length;
ptr = data.ptr;
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();
"%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 */
}
/*
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",
error = -ENOBUFS;
}
}
-
+out:
return error;
}
if (skb == NULL)
return 1;
if (skb->len == 0) {
- kfree_skb(skb);
+ KFREE_SKB(skb);
return 1;
}
data = skb->data;
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.
*/
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);
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;
* Update the appropriate statistic counter.
*/
if (!(*proto_ptr->func)(ppp, skb)) {
- kfree_skb(skb);
+ KFREE_SKB(skb);
++ppp->stats.ppp_discards;
}
*/
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;
}
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
*/
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);
}
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);
/*
* 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
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)
/* 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");
}
}
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,
if (data == orig_data) {
/* Couldn't compress the data */
- kfree_skb(new_skb);
+ KFREE_SKB(new_skb);
return skb;
}
data[2] = 0;
data[3] = proto;
- kfree_skb(skb);
+ KFREE_SKB(skb);
return new_skb;
}
{
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);
+ }
}
/*
{
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);
}
if (skb == NULL)
return 0;
if (skb->data == NULL) {
- kfree_skb(skb);
+ KFREE_SKB(skb);
return 0;
}
* queued to be sent.
*/
if (!ppp->inuse) {
- dev_kfree_skb(skb);
+ KFREE_SKB(skb);
return 0;
}
printk(KERN_ERR
"ppp_dev_xmit: %s not connected to a TTY!\n",
dev->name);
- dev_kfree_skb(skb);
+ KFREE_SKB(skb);
return 0;
}
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];
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;
}
*/
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:
printk(KERN_DEBUG
"ppp_dev_xmit: dropping (npmode = %d) on %s\n",
npmode, ppp->name);
- dev_kfree_skb(skb);
+ KFREE_SKB(skb);
return 0;
}
* 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.
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;
}
hdr[3] = proto;
ppp_send_frame(ppp, skb);
+ if (!ppp->xmit_busy)
+ ppp_send_frames(ppp);
return 0;
}
*/
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);
ppp->last_xmit = jiffies;
ppp->last_recv = jiffies;
+ ppp->xmit_busy = 0;
/* clear statistics */
memset(&ppp->stats, 0, sizeof (struct pppstat));
}
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);
+ }
}
/*
return (struct compressor *) 0;
}
-#ifdef CONFIG_MODULES
static int ppp_register_compressor (struct compressor *cp)
{
struct compressor_link *new;
}
restore_flags(flags);
}
-#endif
/*************************************************************
* Module support routines