bonding: fix potential deadlock in bond_uninit()
[safe/jmp/linux-2.6] / drivers / net / ppp_async.c
index 5e48b9a..6a375ea 100644 (file)
 #include <linux/ppp_channel.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
+#include <asm/string.h>
 
 #define PPP_VERSION    "2.4.2"
 
-#define OBUFSIZE       256
+#define OBUFSIZE       4096
 
 /* Structure for storing local state. */
 struct asyncppp {
@@ -123,8 +125,8 @@ static struct ppp_channel_ops async_ops = {
  * way to fix this is to use a rwlock in the tty struct, but for now
  * we use a single global rwlock for all ttys in ppp line discipline.
  *
- * FIXME: this is no longer true. The _close path for the ldisc is 
- * now guaranteed to be sane. 
+ * FIXME: this is no longer true. The _close path for the ldisc is
+ * now guaranteed to be sane.
  */
 static DEFINE_RWLOCK(disc_data_lock);
 
@@ -155,14 +157,17 @@ ppp_asynctty_open(struct tty_struct *tty)
 {
        struct asyncppp *ap;
        int err;
+       int speed;
+
+       if (tty->ops->write == NULL)
+               return -EOPNOTSUPP;
 
        err = -ENOMEM;
-       ap = kmalloc(sizeof(*ap), GFP_KERNEL);
-       if (ap == 0)
+       ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+       if (!ap)
                goto out;
 
        /* initialize the asyncppp structure */
-       memset(ap, 0, sizeof(*ap));
        ap->tty = tty;
        ap->mru = PPP_MRU;
        spin_lock_init(&ap->xmit_lock);
@@ -183,12 +188,14 @@ ppp_asynctty_open(struct tty_struct *tty)
        ap->chan.private = ap;
        ap->chan.ops = &async_ops;
        ap->chan.mtu = PPP_MRU;
+       speed = tty_get_baud_rate(tty);
+       ap->chan.speed = speed;
        err = ppp_register_channel(&ap->chan);
        if (err)
                goto out_free;
 
        tty->disc_data = ap;
-
+       tty->receive_room = 65536;
        return 0;
 
  out_free:
@@ -214,7 +221,7 @@ ppp_asynctty_close(struct tty_struct *tty)
        ap = tty->disc_data;
        tty->disc_data = NULL;
        write_unlock_irq(&disc_data_lock);
-       if (ap == 0)
+       if (!ap)
                return;
 
        /*
@@ -229,11 +236,9 @@ ppp_asynctty_close(struct tty_struct *tty)
        tasklet_kill(&ap->tsk);
 
        ppp_unregister_channel(&ap->chan);
-       if (ap->rpkt != 0)
-               kfree_skb(ap->rpkt);
+       kfree_skb(ap->rpkt);
        skb_queue_purge(&ap->rqueue);
-       if (ap->tpkt != 0)
-               kfree_skb(ap->tpkt);
+       kfree_skb(ap->tpkt);
        kfree(ap);
 }
 
@@ -275,7 +280,7 @@ ppp_asynctty_write(struct tty_struct *tty, struct file *file,
  * Called in process context only. May be re-entered by multiple
  * ioctl calling threads.
  */
+
 static int
 ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
                   unsigned int cmd, unsigned long arg)
@@ -284,14 +289,11 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
        int err, val;
        int __user *p = (int __user *)arg;
 
-       if (ap == 0)
+       if (!ap)
                return -ENXIO;
        err = -EFAULT;
        switch (cmd) {
        case PPPIOCGCHAN:
-               err = -ENXIO;
-               if (ap == 0)
-                       break;
                err = -EFAULT;
                if (put_user(ppp_channel_index(&ap->chan), p))
                        break;
@@ -299,25 +301,17 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
                break;
 
        case PPPIOCGUNIT:
-               err = -ENXIO;
-               if (ap == 0)
-                       break;
                err = -EFAULT;
                if (put_user(ppp_unit_number(&ap->chan), p))
                        break;
                err = 0;
                break;
 
-       case TCGETS:
-       case TCGETA:
-               err = n_tty_ioctl(tty, file, cmd, arg);
-               break;
-
        case TCFLSH:
                /* flush our buffers and the serial port's buffer */
                if (arg == TCIOFLUSH || arg == TCOFLUSH)
                        ppp_async_flush_output(ap);
-               err = n_tty_ioctl(tty, file, cmd, arg);
+               err = tty_perform_flush(tty, arg);
                break;
 
        case FIONREAD:
@@ -328,7 +322,8 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
                break;
 
        default:
-               err = -ENOIOCTLCMD;
+               /* Try the various mode ioctls */
+               err = tty_mode_ioctl(tty, file, cmd, arg);
        }
 
        ap_put(ap);
@@ -342,16 +337,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
        return 0;
 }
 
-static int
-ppp_asynctty_room(struct tty_struct *tty)
-{
-       return 65535;
-}
-
-/*
- * This can now be called from hard interrupt level as well
- * as soft interrupt level or mainline.
- */
+/* May sleep, don't call from interrupt level or with interrupts disabled */
 static void
 ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
@@ -359,17 +345,15 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
        struct asyncppp *ap = ap_get(tty);
        unsigned long flags;
 
-       if (ap == 0)
+       if (!ap)
                return;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_async_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
-       if (skb_queue_len(&ap->rqueue))
+       if (!skb_queue_empty(&ap->rqueue))
                tasklet_schedule(&ap->tsk);
        ap_put(ap);
-       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
-           && tty->driver->unthrottle)
-               tty->driver->unthrottle(tty);
+       tty_unthrottle(tty);
 }
 
 static void
@@ -378,7 +362,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty)
        struct asyncppp *ap = ap_get(tty);
 
        clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       if (ap == 0)
+       if (!ap)
                return;
        set_bit(XMIT_WAKEUP, &ap->xmit_flags);
        tasklet_schedule(&ap->tsk);
@@ -386,7 +370,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty)
 }
 
 
-static struct tty_ldisc ppp_ldisc = {
+static struct tty_ldisc_ops ppp_ldisc = {
        .owner  = THIS_MODULE,
        .magic  = TTY_LDISC_MAGIC,
        .name   = "ppp",
@@ -397,7 +381,6 @@ static struct tty_ldisc ppp_ldisc = {
        .write  = ppp_asynctty_write,
        .ioctl  = ppp_asynctty_ioctl,
        .poll   = ppp_asynctty_poll,
-       .receive_room = ppp_asynctty_room,
        .receive_buf = ppp_asynctty_receive,
        .write_wakeup = ppp_asynctty_wakeup,
 };
@@ -575,8 +558,8 @@ ppp_async_encode(struct asyncppp *ap)
                 * Start of a new packet - insert the leading FLAG
                 * character if necessary.
                 */
-               if (islcp || flag_time == 0
-                   || jiffies - ap->last_xmit >= flag_time)
+               if (islcp || flag_time == 0 ||
+                   time_after_eq(jiffies, ap->last_xmit + flag_time))
                        *buf++ = PPP_FLAG;
                ap->last_xmit = jiffies;
                fcs = PPP_INITFCS;
@@ -686,7 +669,7 @@ ppp_async_push(struct asyncppp *ap)
                if (!tty_stuffed && ap->optr < ap->olim) {
                        avail = ap->olim - ap->optr;
                        set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-                       sent = tty->driver->write(tty, ap->optr, avail);
+                       sent = tty->ops->write(tty, ap->optr, avail);
                        if (sent < 0)
                                goto flush;     /* error, e.g. loss of CD */
                        ap->optr += sent;
@@ -694,7 +677,7 @@ ppp_async_push(struct asyncppp *ap)
                                tty_stuffed = 1;
                        continue;
                }
-               if (ap->optr >= ap->olim && ap->tpkt != 0) {
+               if (ap->optr >= ap->olim && ap->tpkt) {
                        if (ppp_async_encode(ap)) {
                                /* finished processing ap->tpkt */
                                clear_bit(XMIT_FULL, &ap->xmit_flags);
@@ -713,8 +696,8 @@ ppp_async_push(struct asyncppp *ap)
                 */
                clear_bit(XMIT_BUSY, &ap->xmit_flags);
                /* any more work to do? if not, exit the loop */
-               if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)
-                     || (!tty_stuffed && ap->tpkt != 0)))
+               if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) ||
+                     (!tty_stuffed && ap->tpkt)))
                        break;
                /* more work to do, see if we can do it now */
                if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags))
@@ -725,7 +708,7 @@ ppp_async_push(struct asyncppp *ap)
 
 flush:
        clear_bit(XMIT_BUSY, &ap->xmit_flags);
-       if (ap->tpkt != 0) {
+       if (ap->tpkt) {
                kfree_skb(ap->tpkt);
                ap->tpkt = NULL;
                clear_bit(XMIT_FULL, &ap->xmit_flags);
@@ -771,8 +754,8 @@ scan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count)
 
        for (i = 0; i < count; ++i) {
                c = buf[i];
-               if (c == PPP_ESCAPE || c == PPP_FLAG
-                   || (c < 0x20 && (ap->raccm & (1 << c)) != 0))
+               if (c == PPP_ESCAPE || c == PPP_FLAG ||
+                   (c < 0x20 && (ap->raccm & (1 << c)) != 0))
                        break;
        }
        return i;
@@ -807,9 +790,9 @@ process_input_packet(struct asyncppp *ap)
 
        /* check for address/control and protocol compression */
        p = skb->data;
-       if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+       if (p[0] == PPP_ALLSTATIONS) {
                /* chop off address/control */
-               if (skb->len < 3)
+               if (p[1] != PPP_UI || skb->len < 3)
                        goto err;
                p = skb_pull(skb, 2);
        }
@@ -835,8 +818,11 @@ process_input_packet(struct asyncppp *ap)
  err:
        /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
        ap->state = SC_PREV_ERROR;
-       if (skb)
+       if (skb) {
+               /* make skb appear as freshly allocated */
                skb_trim(skb, 0);
+               skb_reserve(skb, - skb_headroom(skb));
+       }
 }
 
 /* Called when the tty driver has data for us. Runs parallel with the
@@ -855,7 +841,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                s = 0;
                for (i = 0; i < count; ++i) {
                        c = buf[i];
-                       if (flags != 0 && flags[i] != 0)
+                       if (flags && flags[i] != 0)
                                continue;
                        s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0;
                        c = ((c >> 4) ^ c) & 0xf;
@@ -872,7 +858,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                        n = scan_ordinary(ap, buf, count);
 
                f = 0;
-               if (flags != 0 && (ap->state & SC_TOSS) == 0) {
+               if (flags && (ap->state & SC_TOSS) == 0) {
                        /* check the flags to see if any char had an error */
                        for (j = 0; j < n; ++j)
                                if ((f = flags[j]) != 0)
@@ -885,14 +871,21 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                } else if (n > 0 && (ap->state & SC_TOSS) == 0) {
                        /* stuff the chars in the skb */
                        skb = ap->rpkt;
-                       if (skb == 0) {
+                       if (!skb) {
                                skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
-                               if (skb == 0)
+                               if (!skb)
                                        goto nomem;
-                               /* Try to get the payload 4-byte aligned */
+                               ap->rpkt = skb;
+                       }
+                       if (skb->len == 0) {
+                               /* Try to get the payload 4-byte aligned.
+                                * This should match the
+                                * PPP_ALLSTATIONS/PPP_UI/compressed tests in
+                                * process_input_packet, but we do not have
+                                * enough chars here to test buf[1] and buf[2].
+                                */
                                if (buf[0] != PPP_ALLSTATIONS)
                                        skb_reserve(skb, 2 + (buf[0] & 1));
-                               ap->rpkt = skb;
                        }
                        if (n > skb_tailroom(skb)) {
                                /* packet overflowed MRU */
@@ -927,7 +920,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                ++n;
 
                buf += n;
-               if (flags != 0)
+               if (flags)
                        flags += n;
                count -= n;
        }