fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / slip.c
index 6209a35..a0806d2 100644 (file)
  */
 
 #define SL_CHECK_TRANSMIT
-#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -73,6 +73,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/if_arp.h>
 #include <linux/if_slip.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include "slip.h"
 #ifdef CONFIG_INET
@@ -85,8 +86,8 @@
 
 static struct net_device **slip_devs;
 
-int slip_maxdev = SL_NRUNIT;           /* Can be overridden with insmod! */
-MODULE_PARM(slip_maxdev, "i");
+static int slip_maxdev = SL_NRUNIT;
+module_param(slip_maxdev, int, 0);
 MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices");
 
 static int slip_esc(unsigned char *p, unsigned char *d, int len);
@@ -112,7 +113,7 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd);
 *      on actively running device.
 *********************************/
 
-/* 
+/*
    Allocate channel buffers.
  */
 
@@ -184,15 +185,12 @@ sl_alloc_bufs(struct slip *sl, int mtu)
        /* Cleanup */
 err_exit:
 #ifdef SL_INCLUDE_CSLIP
-       if (cbuff)
-               kfree(cbuff);
+       kfree(cbuff);
        if (slcomp)
                slhc_free(slcomp);
 #endif
-       if (xbuff)
-               kfree(xbuff);
-       if (rbuff)
-               kfree(rbuff);
+       kfree(xbuff);
+       kfree(rbuff);
        return err;
 }
 
@@ -200,22 +198,16 @@ err_exit:
 static void
 sl_free_bufs(struct slip *sl)
 {
-       void * tmp;
-
        /* Free all SLIP frame buffers. */
-       if ((tmp = xchg(&sl->rbuff, NULL)) != NULL)
-               kfree(tmp);
-       if ((tmp = xchg(&sl->xbuff, NULL)) != NULL)
-               kfree(tmp);
+       kfree(xchg(&sl->rbuff, NULL));
+       kfree(xchg(&sl->xbuff, NULL));
 #ifdef SL_INCLUDE_CSLIP
-       if ((tmp = xchg(&sl->cbuff, NULL)) != NULL)
-               kfree(tmp);
-       if ((tmp = xchg(&sl->slcomp, NULL)) != NULL)
-               slhc_free(tmp);
+       kfree(xchg(&sl->cbuff, NULL));
+       slhc_free(xchg(&sl->slcomp, NULL));
 #endif
 }
 
-/* 
+/*
    Reallocate slip channel buffers.
  */
 
@@ -237,10 +229,10 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
        if (len < 576 * 2)
                len = 576 * 2;
 
-       xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
-       rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+       xbuff = kmalloc(len + 4, GFP_ATOMIC);
+       rbuff = kmalloc(len + 4, GFP_ATOMIC);
 #ifdef SL_INCLUDE_CSLIP
-       cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
+       cbuff = kmalloc(len + 4, GFP_ATOMIC);
 #endif
 
 
@@ -296,13 +288,10 @@ done_on_bh:
        spin_unlock_bh(&sl->lock);
 
 done:
-       if (xbuff)
-               kfree(xbuff);
-       if (rbuff)
-               kfree(rbuff);
+       kfree(xbuff);
+       kfree(rbuff);
 #ifdef SL_INCLUDE_CSLIP
-       if (cbuff)
-               kfree(cbuff);
+       kfree(cbuff);
 #endif
        return err;
 }
@@ -365,7 +354,7 @@ sl_bump(struct slip *sl)
 #endif  /* SL_INCLUDE_CSLIP */
 
        sl->rx_bytes+=count;
-       
+
        skb = dev_alloc_skb(count);
        if (skb == NULL)  {
                printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
@@ -417,7 +406,7 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
         *       14 Oct 1994  Dmitry Gorodchanin.
         */
        sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-       actual = sl->tty->driver->write(sl->tty, 0, sl->xbuff, count);
+       actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
 #ifdef SL_CHECK_TRANSMIT
        sl->dev->trans_start = jiffies;
 #endif
@@ -451,20 +440,18 @@ static void slip_write_wakeup(struct tty_struct *tty)
                return;
        }
 
-       actual = tty->driver->write(tty, 0, sl->xhead, sl->xleft);
+       actual = tty->driver->write(tty, sl->xhead, sl->xleft);
        sl->xleft -= actual;
        sl->xhead += actual;
 }
 
 static void sl_tx_timeout(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        spin_lock(&sl->lock);
 
        if (netif_queue_stopped(dev)) {
-               struct slip *sl = (struct slip*)(dev->priv);
-
                if (!netif_running(dev))
                        goto out;
 
@@ -494,7 +481,7 @@ out:
 static int
 sl_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        spin_lock(&sl->lock);
        if (!netif_running(dev))  {
@@ -528,7 +515,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
 static int
 sl_close(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        spin_lock_bh(&sl->lock);
        if (sl->tty) {
@@ -547,7 +534,7 @@ sl_close(struct net_device *dev)
 
 static int sl_open(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        if (sl->tty==NULL)
                return -ENODEV;
@@ -561,7 +548,7 @@ static int sl_open(struct net_device *dev)
 
 static int sl_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        if (new_mtu < 68 || new_mtu > 65534)
                return -EINVAL;
@@ -577,7 +564,7 @@ static struct net_device_stats *
 sl_get_stats(struct net_device *dev)
 {
        static struct net_device_stats stats;
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 #ifdef SL_INCLUDE_CSLIP
        struct slcompress *comp;
 #endif
@@ -612,10 +599,10 @@ sl_get_stats(struct net_device *dev)
 
 static int sl_init(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        /*
-        *      Finish setting up the DEVICE info. 
+        *      Finish setting up the DEVICE info.
         */
 
        dev->mtu                = sl->mtu;
@@ -630,7 +617,7 @@ static int sl_init(struct net_device *dev)
 
 static void sl_uninit(struct net_device *dev)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
 
        sl_free_bufs(sl);
 }
@@ -663,18 +650,15 @@ static void sl_setup(struct net_device *dev)
  ******************************************/
 
 
-static int slip_receive_room(struct tty_struct *tty)
-{
-       return 65536;  /* We can handle an infinite amount of data. :-) */
-}
-
 /*
  * Handle the 'receiver data ready' interrupt.
  * This function is called by the 'tty_io' module in the kernel when
  * a block of SLIP data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
+ * and sent on to some IP layer for further processing. This will not
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
  */
+
 static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct slip *sl = (struct slip *) tty->disc_data;
@@ -717,7 +701,7 @@ static void sl_sync(void)
                if ((dev = slip_devs[i]) == NULL)
                        break;
 
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (sl->tty || sl->leased)
                        continue;
                if (dev->flags&IFF_UP)
@@ -736,7 +720,7 @@ sl_alloc(dev_t line)
        struct net_device *dev = NULL;
        struct slip       *sl;
 
-       if (slip_devs == NULL) 
+       if (slip_devs == NULL)
                return NULL;    /* Master array missing ! */
 
        for (i = 0; i < slip_maxdev; i++) {
@@ -744,7 +728,7 @@ sl_alloc(dev_t line)
                if (dev == NULL)
                        break;
 
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (sl->leased) {
                        if (sl->line != line)
                                continue;
@@ -786,7 +770,7 @@ sl_alloc(dev_t line)
                i = sel;
                dev = slip_devs[i];
                if (score > 1) {
-                       sl = dev->priv;
+                       sl = netdev_priv(dev);
                        sl->flags &= (1 << SLF_INUSE);
                        return sl;
                }
@@ -797,14 +781,14 @@ sl_alloc(dev_t line)
                return NULL;
 
        if (dev) {
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (test_bit(SLF_INUSE, &sl->flags)) {
                        unregister_netdevice(dev);
                        dev = NULL;
                        slip_devs[i] = NULL;
                }
        }
-       
+
        if (!dev) {
                char name[IFNAMSIZ];
                sprintf(name, "sl%d", i);
@@ -815,7 +799,7 @@ sl_alloc(dev_t line)
                dev->base_addr  = i;
        }
 
-       sl = dev->priv;
+       sl = netdev_priv(dev);
 
        /* Initialize channel control data */
        sl->magic       = SLIP_MAGIC;
@@ -831,7 +815,7 @@ sl_alloc(dev_t line)
        sl->outfill_timer.function=sl_outfill;
 #endif
        slip_devs[i] = dev;
-                                  
+
        return sl;
 }
 
@@ -841,16 +825,18 @@ sl_alloc(dev_t line)
  * SLIP line discipline is called for.  Because we are
  * sure the tty line exists, we only have to link it to
  * a free SLIP channel...
+ *
+ * Called in process context serialized from other ldisc calls.
  */
-static int
-slip_open(struct tty_struct *tty)
+
+static int slip_open(struct tty_struct *tty)
 {
        struct slip *sl;
        int err;
 
        if(!capable(CAP_NET_ADMIN))
                return -EPERM;
-               
+
        /* RTnetlink lock is misused here to serialize concurrent
           opens of slip channels. There are better ways, but it is
           the simplest one.
@@ -876,10 +862,6 @@ slip_open(struct tty_struct *tty)
        tty->disc_data = sl;
        sl->line = tty_devnum(tty);
        sl->pid = current->pid;
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
 
        if (!test_bit(SLF_INUSE, &sl->flags)) {
                /* Perform the low-level SLIP initialization. */
@@ -905,6 +887,7 @@ slip_open(struct tty_struct *tty)
 
        /* Done.  We have linked the TTY line to a channel. */
        rtnl_unlock();
+       tty->receive_room = 65536;      /* We don't flow control */
        return sl->dev->base_addr;
 
 err_free_bufs:
@@ -923,6 +906,9 @@ err_exit:
 }
 
 /*
+
+  FIXME: 1,2 are fixed 3 was never true anyway.
+
    Let me to blame a bit.
    1. TTY module calls this funstion on soft interrupt.
    2. TTY module calls this function WITH MASKED INTERRUPTS!
@@ -934,16 +920,15 @@ err_exit:
 
    By-product (not desired): sl? does not feel hangups and remains open.
    It is supposed, that user level program (dip, diald, slattach...)
-   will catch SIGHUP and make the rest of work. 
+   will catch SIGHUP and make the rest of work.
 
    I see no way to make more with current tty code. --ANK
  */
 
 /*
  * Close down a SLIP channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to SLIP
- * (which usually is TTY again).
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
  */
 static void
 slip_close(struct tty_struct *tty)
@@ -1254,7 +1239,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
 
 static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
 {
-       struct slip *sl = (struct slip*)(dev->priv);
+       struct slip *sl = netdev_priv(dev);
        unsigned long *p = (unsigned long *)&rq->ifr_ifru;
 
        if (sl == NULL)         /* Allocation failed ?? */
@@ -1306,7 +1291,7 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
                break;
 
         case SIOCSLEASE:
-               /* Resolve race condition, when ioctl'ing hanged up 
+               /* Resolve race condition, when ioctl'ing hanged up
                   and opened by another process device.
                 */
                if (sl->tty != current->signal->tty && sl->pid != current->pid) {
@@ -1335,7 +1320,6 @@ static struct tty_ldisc   sl_ldisc = {
        .close          = slip_close,
        .ioctl          = slip_ioctl,
        .receive_buf    = slip_receive_buf,
-       .receive_room   = slip_receive_room,
        .write_wakeup   = slip_write_wakeup,
 };
 
@@ -1366,7 +1350,7 @@ static int __init slip_init(void)
        }
 
        /* Clear the pointer array, we allocate devices when we need them */
-       memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev); 
+       memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
 
        /* Fill in our line protocol discipline, and register it */
        if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)  {
@@ -1384,23 +1368,21 @@ static void __exit slip_exit(void)
        unsigned long timeout = jiffies + HZ;
        int busy = 0;
 
-       if (slip_devs == NULL) 
+       if (slip_devs == NULL)
                return;
 
        /* First of all: check for active disciplines and hangup them.
         */
        do {
-               if (busy) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(HZ / 10);
-               }
+               if (busy)
+                       msleep_interruptible(100);
 
                busy = 0;
                for (i = 0; i < slip_maxdev; i++) {
                        dev = slip_devs[i];
                        if (!dev)
                                continue;
-                       sl = dev->priv;
+                       sl = netdev_priv(dev);
                        spin_lock_bh(&sl->lock);
                        if (sl->tty) {
                                busy++;
@@ -1417,13 +1399,13 @@ static void __exit slip_exit(void)
                        continue;
                slip_devs[i] = NULL;
 
-               sl = dev->priv;
+               sl = netdev_priv(dev);
                if (sl->tty) {
                        printk(KERN_ERR "%s: tty discipline still running\n",
                               dev->name);
                        /* Intentionally leak the control block. */
                        dev->destructor = NULL;
-               } 
+               }
 
                unregister_netdev(dev);
        }
@@ -1431,7 +1413,7 @@ static void __exit slip_exit(void)
        kfree(slip_devs);
        slip_devs = NULL;
 
-       if ((i = tty_register_ldisc(N_SLIP, NULL)))
+       if ((i = tty_unregister_ldisc(N_SLIP)))
        {
                printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
        }
@@ -1469,7 +1451,7 @@ static void sl_outfill(unsigned long sls)
                        if (!netif_queue_stopped(sl->dev))
                        {
                                /* if device busy no outfill */
-                               sl->tty->driver->write(sl->tty, 0, &s, 1);
+                               sl->tty->driver->write(sl->tty, &s, 1);
                        }
                }
                else