slip: Move the SLIP drivers [Linux 3.2]

This Linux kernel change "slip: Move the SLIP drivers" is included in the Linux 3.2 release. This change is authored by Jeff Kirsher <jeffrey.t.kirsher [at] intel.com> on Wed Aug 3 03:17:13 2011 -0700. The commit for this change in Linux stable tree is b5451d7 (patch).

slip: Move the SLIP drivers

Move the Serial Line Internet Protocol (SLIP) drivers into
drivers/net/slip/ and make the necessary Kconfig and Makefile
changes.

Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: Alan Cox <alan@linux.intel.com>

There are 4737 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/Kconfig       |   74 +--
 drivers/net/Makefile      |    4 +-
 drivers/net/slhc.c        |  742 -----------------------
 drivers/net/slip.c        | 1444 ---------------------------------------------
 drivers/net/slip.h        |  101 ----
 drivers/net/slip/Kconfig  |   79 +++
 drivers/net/slip/Makefile |    6 +
 drivers/net/slip/slhc.c   |  742 +++++++++++++++++++++++
 drivers/net/slip/slip.c   | 1444 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/slip/slip.h   |  101 ++++
 10 files changed, 2376 insertions(+), 2361 deletions(-)
 delete mode 100644 drivers/net/slhc.c
 delete mode 100644 drivers/net/slip.c
 delete mode 100644 drivers/net/slip.h
 create mode 100644 drivers/net/slip/Kconfig
 create mode 100644 drivers/net/slip/Makefile
 create mode 100644 drivers/net/slip/slhc.c
 create mode 100644 drivers/net/slip/slip.c
 create mode 100644 drivers/net/slip/slip.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3f72686..b3206c9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -199,6 +199,8 @@ source "drivers/net/fddi/Kconfig"

 source "drivers/net/plip/Kconfig"

+source "drivers/net/slip/Kconfig"
+
 source "drivers/net/tokenring/Kconfig"

 source "drivers/net/wireless/Kconfig"
@@ -274,78 +276,6 @@ config RIONET_RX_SIZE
    depends on RIONET
    default "128"

-config SLIP
-   tristate "SLIP (serial line) support"
-   ---help---
-     Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
-     connect to your Internet service provider or to connect to some
-     other local Unix box or if you want to configure your Linux box as a
-     Slip/CSlip server for other people to dial in. SLIP (Serial Line
-     Internet Protocol) is a protocol used to send Internet traffic over
-     serial connections such as telephone lines or null modem cables;
-     nowadays, the protocol PPP is more commonly used for this same
-     purpose.
-
-     Normally, your access provider has to support SLIP in order for you
-     to be able to use it, but there is now a SLIP emulator called SLiRP
-     around (available from
-     <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
-     allows you to use SLIP over a regular dial up shell connection. If
-     you plan to use SLiRP, make sure to say Y to CSLIP, below. The
-     NET-3-HOWTO, available from
-     <http://www.tldp.org/docs.html#howto>, explains how to
-     configure SLIP. Note that you don't need this option if you just
-     want to run term (term is a program which gives you almost full
-     Internet connectivity if you have a regular dial up shell account on
-     some Internet connected Unix computer. Read
-     <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
-     support will enlarge your kernel by about 4 KB. If unsure, say N.
-
-     To compile this driver as a module, choose M here. The module
-     will be called slip.
-
-config SLIP_COMPRESSED
-   bool "CSLIP compressed headers"
-   depends on SLIP
-   select SLHC
-   ---help---
-     This protocol is faster than SLIP because it uses compression on the
-     TCP/IP headers (not on the data itself), but it has to be supported
-     on both ends. Ask your access provider if you are not sure and
-     answer Y, just in case. You will still be able to use plain SLIP. If
-     you plan to use SLiRP, the SLIP emulator (available from
-     <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
-     allows you to use SLIP over a regular dial up shell connection, you
-     definitely want to say Y here. The NET-3-HOWTO, available from
-     <http://www.tldp.org/docs.html#howto>, explains how to configure
-     CSLIP. This won't enlarge your kernel.
-
-config SLHC
-   tristate
-   help
-     This option enables Van Jacobsen serial line header compression
-     routines.
-
-config SLIP_SMART
-   bool "Keepalive and linefill"
-   depends on SLIP
-   help
-     Adds additional capabilities to the SLIP driver to support the
-     RELCOM line fill and keepalive monitoring. Ideal on poor quality
-     analogue lines.
-
-config SLIP_MODE_SLIP6
-   bool "Six bit SLIP encapsulation"
-   depends on SLIP
-   help
-     Just occasionally you may need to run IP over hostile serial
-     networks that don't pass all control characters or are only seven
-     bit. Saying Y here adds an extra mode you can use with SLIP:
-     "slip6". In this mode, SLIP will only send normal ASCII symbols over
-     the serial device. Naturally, this has to be supported at the other
-     end of the link as well. It's good enough, for example, to run IP
-     over the async ports of a Camtec JNT Pad. If unsure, say N.
-
 config NET_FC
    bool "Fibre Channel driver support"
    depends on SCSI && PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 52dae95..e6a183e 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -20,8 +20,6 @@ obj-$(CONFIG_RIONET) += rionet.o

 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_SLIP) += slip.o
-obj-$(CONFIG_SLHC) += slhc.o

 obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
 obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
@@ -48,6 +46,8 @@ obj-$(CONFIG_PPP_SYNC_TTY) += ppp/
 obj-$(CONFIG_PPPOE) += ppp/
 obj-$(CONFIG_PPPOL2TP) += ppp/
 obj-$(CONFIG_PPTP) += ppp/
+onj-$(CONFIG_SLIP) += slip/
+obj-$(CONFIG_SLHC) += slip/
 obj-$(CONFIG_TR) += tokenring/
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
deleted file mode 100644
index 0a0a664..0000000
--- a/drivers/net/slhc.c
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Routines to compress and uncompress tcp packets (for transmission
- * over low speed serial lines).
- *
- * Copyright (c) 1989 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
- * - Initial distribution.
- *
- *
- * modified for KA9Q Internet Software Package by
- * Katie Stevens (dkstevens@ucdavis.edu)
- * University of California, Davis
- * Computing Services
- * - 01-31-90  initial adaptation (from 1.19)
- * PPP.05  02-15-90 [ks]
- * PPP.08  05-02-90 [ks]   use PPP protocol field to signal compression
- * PPP.15  09-90    [ks]   improve mbuf handling
- * PPP.16  11-02    [karn] substantially rewritten to use NOS facilities
- *
- * - Feb 1991  Bill_Simpson@um.cc.umich.edu
- *         variable number of conversation slots
- *         allow zero or one slots
- *         separate routines
- *         status display
- * - Jul 1994  Dmitry Gorodchanin
- *         Fixes for memory leaks.
- *      - Oct 1994      Dmitry Gorodchanin
- *                      Modularization.
- * - Jan 1995  Bjorn Ekwall
- *         Use ip_fast_csum from ip.h
- * - July 1995 Christos A. Polyzols
- *         Spotted bug in tcp option checking
- *
- *
- * This module is a difficult issue. It's clearly inet code but it's also clearly
- * driver code belonging close to PPP and SLIP
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <net/slhc_vj.h>
-
-#ifdef CONFIG_INET
-/* Entire module is for IP only */
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/termios.h>
-#include <linux/in.h>
-#include <linux/fcntl.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/icmp.h>
-#include <net/tcp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <net/checksum.h>
-#include <asm/unaligned.h>
-
-static unsigned char *encode(unsigned char *cp, unsigned short n);
-static long decode(unsigned char **cpp);
-static unsigned char * put16(unsigned char *cp, unsigned short x);
-static unsigned short pull16(unsigned char **cpp);
-
-/* Initialize compression data structure
- * slots must be in range 0 to 255 (zero meaning no compression)
- */
-struct slcompress *
-slhc_init(int rslots, int tslots)
-{
-   register short i;
-   register struct cstate *ts;
-   struct slcompress *comp;
-
-   comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
-   if (! comp)
-       goto out_fail;
-
-   if ( rslots > 0  &&  rslots < 256 ) {
-       size_t rsize = rslots * sizeof(struct cstate);
-       comp->rstate = kzalloc(rsize, GFP_KERNEL);
-       if (! comp->rstate)
-           goto out_free;
-       comp->rslot_limit = rslots - 1;
-   }
-
-   if ( tslots > 0  &&  tslots < 256 ) {
-       size_t tsize = tslots * sizeof(struct cstate);
-       comp->tstate = kzalloc(tsize, GFP_KERNEL);
-       if (! comp->tstate)
-           goto out_free2;
-       comp->tslot_limit = tslots - 1;
-   }
-
-   comp->xmit_oldest = 0;
-   comp->xmit_current = 255;
-   comp->recv_current = 255;
-   /*
-    * don't accept any packets with implicit index until we get
-    * one with an explicit index.  Otherwise the uncompress code
-    * will try to use connection 255, which is almost certainly
-    * out of range
-    */
-   comp->flags |= SLF_TOSS;
-
-   if ( tslots > 0 ) {
-       ts = comp->tstate;
-       for(i = comp->tslot_limit; i > 0; --i){
-           ts[i].cs_this = i;
-           ts[i].next = &(ts[i - 1]);
-       }
-       ts[0].next = &(ts[comp->tslot_limit]);
-       ts[0].cs_this = 0;
-   }
-   return comp;
-
-out_free2:
-   kfree(comp->rstate);
-out_free:
-   kfree(comp);
-out_fail:
-   return NULL;
-}
-
-
-/* Free a compression data structure */
-void
-slhc_free(struct slcompress *comp)
-{
-   if ( comp == NULLSLCOMPR )
-       return;
-
-   if ( comp->tstate != NULLSLSTATE )
-       kfree( comp->tstate );
-
-   if ( comp->rstate != NULLSLSTATE )
-       kfree( comp->rstate );
-
-   kfree( comp );
-}
-
-
-/* Put a short in host order into a char array in network order */
-static inline unsigned char *
-put16(unsigned char *cp, unsigned short x)
-{
-   *cp++ = x >> 8;
-   *cp++ = x;
-
-   return cp;
-}
-
-
-/* Encode a number */
-static unsigned char *
-encode(unsigned char *cp, unsigned short n)
-{
-   if(n >= 256 || n == 0){
-       *cp++ = 0;
-       cp = put16(cp,n);
-   } else {
-       *cp++ = n;
-   }
-   return cp;
-}
-
-/* Pull a 16-bit integer in host order from buffer in network byte order */
-static unsigned short
-pull16(unsigned char **cpp)
-{
-   short rval;
-
-   rval = *(*cpp)++;
-   rval <<= 8;
-   rval |= *(*cpp)++;
-   return rval;
-}
-
-/* Decode a number */
-static long
-decode(unsigned char **cpp)
-{
-   register int x;
-
-   x = *(*cpp)++;
-   if(x == 0){
-       return pull16(cpp) & 0xffff;    /* pull16 returns -1 on error */
-   } else {
-       return x & 0xff;        /* -1 if PULLCHAR returned error */
-   }
-}
-
-/*
- * icp and isize are the original packet.
- * ocp is a place to put a copy if necessary.
- * cpp is initially a pointer to icp.  If the copy is used,
- *    change it to ocp.
- */
-
-int
-slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
-   unsigned char *ocp, unsigned char **cpp, int compress_cid)
-{
-   register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
-   register struct cstate *lcs = ocs;
-   register struct cstate *cs = lcs->next;
-   register unsigned long deltaS, deltaA;
-   register short changes = 0;
-   int hlen;
-   unsigned char new_seq[16];
-   register unsigned char *cp = new_seq;
-   struct iphdr *ip;
-   struct tcphdr *th, *oth;
-   __sum16 csum;
-
-
-   /*
-    *  Don't play with runt packets.
-    */
-
-   if(isize<sizeof(struct iphdr))
-       return isize;
-
-   ip = (struct iphdr *) icp;
-
-   /* Bail if this packet isn't TCP, or is an IP fragment */
-   if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
-       /* Send as regular IP */
-       if(ip->protocol != IPPROTO_TCP)
-           comp->sls_o_nontcp++;
-       else
-           comp->sls_o_tcp++;
-       return isize;
-   }
-   /* Extract TCP header */
-
-   th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
-   hlen = ip->ihl*4 + th->doff*4;
-
-   /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
-    *  some other control bit is set). Also uncompressible if
-    *  it's a runt.
-    */
-   if(hlen > isize || th->syn || th->fin || th->rst ||
-       ! (th->ack)){
-       /* TCP connection stuff; send as regular IP */
-       comp->sls_o_tcp++;
-       return isize;
-   }
-   /*
-    * Packet is compressible -- we're going to send either a
-    * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
-    * we need to locate (or create) the connection state.
-    *
-    * States are kept in a circularly linked list with
-    * xmit_oldest pointing to the end of the list.  The
-    * list is kept in lru order by moving a state to the
-    * head of the list whenever it is referenced.  Since
-    * the list is short and, empirically, the connection
-    * we want is almost always near the front, we locate
-    * states via linear search.  If we don't find a state
-    * for the datagram, the oldest state is (re-)used.
-    */
-   for ( ; ; ) {
-       if( ip->saddr == cs->cs_ip.saddr
-        && ip->daddr == cs->cs_ip.daddr
-        && th->source == cs->cs_tcp.source
-        && th->dest == cs->cs_tcp.dest)
-           goto found;
-
-       /* if current equal oldest, at end of list */
-       if ( cs == ocs )
-           break;
-       lcs = cs;
-       cs = cs->next;
-       comp->sls_o_searches++;
-   }
-   /*
-    * Didn't find it -- re-use oldest cstate.  Send an
-    * uncompressed packet that tells the other side what
-    * connection number we're using for this conversation.
-    *
-    * Note that since the state list is circular, the oldest
-    * state points to the newest and we only need to set
-    * xmit_oldest to update the lru linkage.
-    */
-   comp->sls_o_misses++;
-   comp->xmit_oldest = lcs->cs_this;
-   goto uncompressed;
-
-found:
-   /*
-    * Found it -- move to the front on the connection list.
-    */
-   if(lcs == ocs) {
-       /* found at most recently used */
-   } else if (cs == ocs) {
-       /* found at least recently used */
-       comp->xmit_oldest = lcs->cs_this;
-   } else {
-       /* more than 2 elements */
-       lcs->next = cs->next;
-       cs->next = ocs->next;
-       ocs->next = cs;
-   }
-
-   /*
-    * Make sure that only what we expect to change changed.
-    * Check the following:
-    * IP protocol version, header length & type of service.
-    * The "Don't fragment" bit.
-    * The time-to-live field.
-    * The TCP header length.
-    * IP options, if any.
-    * TCP options, if any.
-    * If any of these things are different between the previous &
-    * current datagram, we send the current datagram `uncompressed'.
-    */
-   oth = &cs->cs_tcp;
-
-   if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
-    || ip->tos != cs->cs_ip.tos
-    || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
-    || ip->ttl != cs->cs_ip.ttl
-    || th->doff != cs->cs_tcp.doff
-    || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
-    || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
-       goto uncompressed;
-   }
-
-   /*
-    * Figure out which of the changing fields changed.  The
-    * receiver expects changes in the order: urgent, window,
-    * ack, seq (the order minimizes the number of temporaries
-    * needed in this section of code).
-    */
-   if(th->urg){
-       deltaS = ntohs(th->urg_ptr);
-       cp = encode(cp,deltaS);
-       changes |= NEW_U;
-   } else if(th->urg_ptr != oth->urg_ptr){
-       /* argh! URG not set but urp changed -- a sensible
-        * implementation should never do this but RFC793
-        * doesn't prohibit the change so we have to deal
-        * with it. */
-       goto uncompressed;
-   }
-   if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
-       cp = encode(cp,deltaS);
-       changes |= NEW_W;
-   }
-   if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
-       if(deltaA > 0x0000ffff)
-           goto uncompressed;
-       cp = encode(cp,deltaA);
-       changes |= NEW_A;
-   }
-   if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
-       if(deltaS > 0x0000ffff)
-           goto uncompressed;
-       cp = encode(cp,deltaS);
-       changes |= NEW_S;
-   }
-
-   switch(changes){
-   case 0: /* Nothing changed. If this packet contains data and the
-        * last one didn't, this is probably a data packet following
-        * an ack (normal on an interactive connection) and we send
-        * it compressed.  Otherwise it's probably a retransmit,
-        * retransmitted ack or window probe.  Send it uncompressed
-        * in case the other side missed the compressed version.
-        */
-       if(ip->tot_len != cs->cs_ip.tot_len &&
-          ntohs(cs->cs_ip.tot_len) == hlen)
-           break;
-       goto uncompressed;
-       break;
-   case SPECIAL_I:
-   case SPECIAL_D:
-       /* actual changes match one of our special case encodings --
-        * send packet uncompressed.
-        */
-       goto uncompressed;
-   case NEW_S|NEW_A:
-       if(deltaS == deltaA &&
-           deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
-           /* special case for echoed terminal traffic */
-           changes = SPECIAL_I;
-           cp = new_seq;
-       }
-       break;
-   case NEW_S:
-       if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
-           /* special case for data xfer */
-           changes = SPECIAL_D;
-           cp = new_seq;
-       }
-       break;
-   }
-   deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
-   if(deltaS != 1){
-       cp = encode(cp,deltaS);
-       changes |= NEW_I;
-   }
-   if(th->psh)
-       changes |= TCP_PUSH_BIT;
-   /* Grab the cksum before we overwrite it below.  Then update our
-    * state with this packet's header.
-    */
-   csum = th->check;
-   memcpy(&cs->cs_ip,ip,20);
-   memcpy(&cs->cs_tcp,th,20);
-   /* We want to use the original packet as our compressed packet.
-    * (cp - new_seq) is the number of bytes we need for compressed
-    * sequence numbers.  In addition we need one byte for the change
-    * mask, one for the connection id and two for the tcp checksum.
-    * So, (cp - new_seq) + 4 bytes of header are needed.
-    */
-   deltaS = cp - new_seq;
-   if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
-       cp = ocp;
-       *cpp = ocp;
-       *cp++ = changes | NEW_C;
-       *cp++ = cs->cs_this;
-       comp->xmit_current = cs->cs_this;
-   } else {
-       cp = ocp;
-       *cpp = ocp;
-       *cp++ = changes;
-   }
-   *(__sum16 *)cp = csum;
-   cp += 2;
-/* deltaS is now the size of the change section of the compressed header */
-   memcpy(cp,new_seq,deltaS);  /* Write list of deltas */
-   memcpy(cp+deltaS,icp+hlen,isize-hlen);
-   comp->sls_o_compressed++;
-   ocp[0] |= SL_TYPE_COMPRESSED_TCP;
-   return isize - hlen + deltaS + (cp - ocp);
-
-   /* Update connection state cs & send uncompressed packet (i.e.,
-    * a regular ip/tcp packet but with the 'conversation id' we hope
-    * to use on future compressed packets in the protocol field).
-    */
-uncompressed:
-   memcpy(&cs->cs_ip,ip,20);
-   memcpy(&cs->cs_tcp,th,20);
-   if (ip->ihl > 5)
-     memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
-   if (th->doff > 5)
-     memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
-   comp->xmit_current = cs->cs_this;
-   comp->sls_o_uncompressed++;
-   memcpy(ocp, icp, isize);
-   *cpp = ocp;
-   ocp[9] = cs->cs_this;
-   ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
-   return isize;
-}
-
-
-int
-slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
-{
-   register int changes;
-   long x;
-   register struct tcphdr *thp;
-   register struct iphdr *ip;
-   register struct cstate *cs;
-   int len, hdrlen;
-   unsigned char *cp = icp;
-
-   /* We've got a compressed packet; read the change byte */
-   comp->sls_i_compressed++;
-   if(isize < 3){
-       comp->sls_i_error++;
-       return 0;
-   }
-   changes = *cp++;
-   if(changes & NEW_C){
-       /* Make sure the state index is in range, then grab the state.
-        * If we have a good state index, clear the 'discard' flag.
-        */
-       x = *cp++;  /* Read conn index */
-       if(x < 0 || x > comp->rslot_limit)
-           goto bad;
-
-       comp->flags &=~ SLF_TOSS;
-       comp->recv_current = x;
-   } else {
-       /* this packet has an implicit state index.  If we've
-        * had a line error since the last time we got an
-        * explicit state index, we have to toss the packet. */
-       if(comp->flags & SLF_TOSS){
-           comp->sls_i_tossed++;
-           return 0;
-       }
-   }
-   cs = &comp->rstate[comp->recv_current];
-   thp = &cs->cs_tcp;
-   ip = &cs->cs_ip;
-
-   thp->check = *(__sum16 *)cp;
-   cp += 2;
-
-   thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
-/*
- * we can use the same number for the length of the saved header and
- * the current one, because the packet wouldn't have been sent
- * as compressed unless the options were the same as the previous one
- */
-
-   hdrlen = ip->ihl * 4 + thp->doff * 4;
-
-   switch(changes & SPECIALS_MASK){
-   case SPECIAL_I:     /* Echoed terminal traffic */
-       {
-       register short i;
-       i = ntohs(ip->tot_len) - hdrlen;
-       thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
-       thp->seq = htonl( ntohl(thp->seq) + i);
-       }
-       break;
-
-   case SPECIAL_D:         /* Unidirectional data */
-       thp->seq = htonl( ntohl(thp->seq) +
-                 ntohs(ip->tot_len) - hdrlen);
-       break;
-
-   default:
-       if(changes & NEW_U){
-           thp->urg = 1;
-           if((x = decode(&cp)) == -1) {
-               goto bad;
-           }
-           thp->urg_ptr = htons(x);
-       } else
-           thp->urg = 0;
-       if(changes & NEW_W){
-           if((x = decode(&cp)) == -1) {
-               goto bad;
-           }
-           thp->window = htons( ntohs(thp->window) + x);
-       }
-       if(changes & NEW_A){
-           if((x = decode(&cp)) == -1) {
-               goto bad;
-           }
-           thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
-       }
-       if(changes & NEW_S){
-           if((x = decode(&cp)) == -1) {
-               goto bad;
-           }
-           thp->seq = htonl( ntohl(thp->seq) + x);
-       }
-       break;
-   }
-   if(changes & NEW_I){
-       if((x = decode(&cp)) == -1) {
-           goto bad;
-       }
-       ip->id = htons (ntohs (ip->id) + x);
-   } else
-       ip->id = htons (ntohs (ip->id) + 1);
-
-   /*
-    * At this point, cp points to the first byte of data in the
-    * packet.  Put the reconstructed TCP and IP headers back on the
-    * packet.  Recalculate IP checksum (but not TCP checksum).
-    */
-
-   len = isize - (cp - icp);
-   if (len < 0)
-       goto bad;
-   len += hdrlen;
-   ip->tot_len = htons(len);
-   ip->check = 0;
-
-   memmove(icp + hdrlen, cp, len - hdrlen);
-
-   cp = icp;
-   memcpy(cp, ip, 20);
-   cp += 20;
-
-   if (ip->ihl > 5) {
-     memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
-     cp += (ip->ihl - 5) * 4;
-   }
-
-   put_unaligned(ip_fast_csum(icp, ip->ihl),
-             &((struct iphdr *)icp)->check);
-
-   memcpy(cp, thp, 20);
-   cp += 20;
-
-   if (thp->doff > 5) {
-     memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
-     cp += ((thp->doff) - 5) * 4;
-   }
-
-   return len;
-bad:
-   comp->sls_i_error++;
-   return slhc_toss( comp );
-}
-
-
-int
-slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
-{
-   register struct cstate *cs;
-   unsigned ihl;
-
-   unsigned char index;
-
-   if(isize < 20) {
-       /* The packet is shorter than a legal IP header */
-       comp->sls_i_runt++;
-       return slhc_toss( comp );
-   }
-   /* Peek at the IP header's IHL field to find its length */
-   ihl = icp[0] & 0xf;
-   if(ihl < 20 / 4){
-       /* The IP header length field is too small */
-       comp->sls_i_runt++;
-       return slhc_toss( comp );
-   }
-   index = icp[9];
-   icp[9] = IPPROTO_TCP;
-
-   if (ip_fast_csum(icp, ihl)) {
-       /* Bad IP header checksum; discard */
-       comp->sls_i_badcheck++;
-       return slhc_toss( comp );
-   }
-   if(index > comp->rslot_limit) {
-       comp->sls_i_error++;
-       return slhc_toss(comp);
-   }
-
-   /* Update local state */
-   cs = &comp->rstate[comp->recv_current = index];
-   comp->flags &=~ SLF_TOSS;
-   memcpy(&cs->cs_ip,icp,20);
-   memcpy(&cs->cs_tcp,icp + ihl*4,20);
-   if (ihl > 5)
-     memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
-   if (cs->cs_tcp.doff > 5)
-     memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
-   cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
-   /* Put headers back on packet
-    * Neither header checksum is recalculated
-    */
-   comp->sls_i_uncompressed++;
-   return isize;
-}
-
-int
-slhc_toss(struct slcompress *comp)
-{
-   if ( comp == NULLSLCOMPR )
-       return 0;
-
-   comp->flags |= SLF_TOSS;
-   return 0;
-}
-
-#else /* CONFIG_INET */
-
-int
-slhc_toss(struct slcompress *comp)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
-  return -EINVAL;
-}
-int
-slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
-  return -EINVAL;
-}
-int
-slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
-   unsigned char *ocp, unsigned char **cpp, int compress_cid)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
-  return -EINVAL;
-}
-
-int
-slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
-  return -EINVAL;
-}
-
-void
-slhc_free(struct slcompress *comp)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
-}
-struct slcompress *
-slhc_init(int rslots, int tslots)
-{
-  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
-  return NULL;
-}
-
-#endif /* CONFIG_INET */
-
-/* VJ header compression */
-EXPORT_SYMBOL(slhc_init);
-EXPORT_SYMBOL(slhc_free);
-EXPORT_SYMBOL(slhc_remember);
-EXPORT_SYMBOL(slhc_compress);
-EXPORT_SYMBOL(slhc_uncompress);
-EXPORT_SYMBOL(slhc_toss);
-
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
deleted file mode 100644
index ba08341..0000000
--- a/drivers/net/slip.c
+++ /dev/null
@@ -1,1444 +0,0 @@
-/*
- * slip.c  This module implements the SLIP protocol for kernel-based
- *     devices like TTY.  It interfaces between a raw TTY, and the
- *     kernel's INET protocol layers.
- *
- * Version:    @(#)slip.c  0.8.3   12/24/94
- *
- * Authors:    Laurence Culhane, <loz@holmes.demon.co.uk>
- *     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * Fixes:
- *     Alan Cox    :   Sanity checks and avoid tx overruns.
- *                 Has a new sl->mtu field.
- *     Alan Cox    :   Found cause of overrun. ifconfig sl0
- *                 mtu upwards. Driver now spots this
- *                 and grows/shrinks its buffers(hack!).
- *                 Memory leak if you run out of memory
- *                 setting up a slip driver fixed.
- *     Matt Dillon :   Printable slip (borrowed from NET2E)
- * Pauline Middelink   :   Slip driver fixes.
- *     Alan Cox    :   Honours the old SL_COMPRESSED flag
- *     Alan Cox    :   KISS AX.25 and AXUI IP support
- *     Michael Riepe   :   Automatic CSLIP recognition added
- *     Charles Hedrick :   CSLIP header length problem fix.
- *     Alan Cox    :   Corrected non-IP cases of the above.
- *     Alan Cox    :   Now uses hardware type as per FvK.
- *     Alan Cox    :   Default to 192.168.0.0 (RFC 1597)
- *     A.N.Kuznetsov   :   dev_tint() recursion fix.
- * Dmitry Gorodchanin  :   SLIP memory leaks
- *      Dmitry Gorodchanin      :       Code cleanup. Reduce tty driver
- *                                      buffering from 4096 to 256 bytes.
- *                                      Improving SLIP response time.
- *                                      CONFIG_SLIP_MODE_SLIP6.
- *                                      ifconfig sl? up & down now works
- *                 correctly.
- *                 Modularization.
- *              Alan Cox        :       Oops - fix AX.25 buffer lengths
- *      Dmitry Gorodchanin      :       Even more cleanups. Preserve CSLIP
- *                                      statistics. Include CSLIP code only
- *                                      if it really needed.
- *     Alan Cox    :   Free slhc buffers in the right place.
- *     Alan Cox    :   Allow for digipeated IP over AX.25
- *     Matti Aarnio    :   Dynamic SLIP devices, with ideas taken
- *                 from Jim Freeman's <jfree@caldera.com>
- *                 dynamic PPP devices.  We do NOT kfree()
- *                 device entries, just reg./unreg. them
- *                 as they are needed.  We kfree() them
- *                 at module cleanup.
- *                 With MODULE-loading ``insmod'', user
- *                 can issue parameter:  slip_maxdev=1024
- *                 (Or how much he/she wants.. Default
- *                 is 256)
- * Stanislav Voronyi   :   Slip line checking, with ideas taken
- *                 from multislip BSDI driver which was
- *                 written by Igor Chechik, RELCOM Corp.
- *                 Only algorithms have been ported to
- *                 Linux SLIP driver.
- * Vitaly E. Lavrov    :   Sane behaviour on tty hangup.
- * Alexey Kuznetsov    :   Cleanup interfaces to tty & netdevice
- *                 modules.
- */
-
-#define SL_CHECK_TRANSMIT
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
-#include <linux/if_arp.h>
-#include <linux/if_slip.h>
-#include <linux/compat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include "slip.h"
-#ifdef CONFIG_INET
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <net/slhc_vj.h>
-#endif
-
-#define SLIP_VERSION   "0.8.4-NET3.019-NEWTTY"
-
-static struct net_device **slip_devs;
-
-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);
-static void slip_unesc(struct slip *sl, unsigned char c);
-#ifdef CONFIG_SLIP_MODE_SLIP6
-static int slip_esc6(unsigned char *p, unsigned char *d, int len);
-static void slip_unesc6(struct slip *sl, unsigned char c);
-#endif
-#ifdef CONFIG_SLIP_SMART
-static void sl_keepalive(unsigned long sls);
-static void sl_outfill(unsigned long sls);
-static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#endif
-
-/********************************
-*  Buffer administration routines:
-*  sl_alloc_bufs()
-*  sl_free_bufs()
-*  sl_realloc_bufs()
-*
-* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because
-*  sl_realloc_bufs provides strong atomicity and reallocation
-*  on actively running device.
-*********************************/
-
-/*
-   Allocate channel buffers.
- */
-
-static int sl_alloc_bufs(struct slip *sl, int mtu)
-{
-   int err = -ENOBUFS;
-   unsigned long len;
-   char *rbuff = NULL;
-   char *xbuff = NULL;
-#ifdef SL_INCLUDE_CSLIP
-   char *cbuff = NULL;
-   struct slcompress *slcomp = NULL;
-#endif
-
-   /*
-    * Allocate the SLIP frame buffers:
-    *
-    * rbuff    Receive buffer.
-    * xbuff    Transmit buffer.
-    * cbuff        Temporary compression buffer.
-    */
-   len = mtu * 2;
-
-   /*
-    * allow for arrival of larger UDP packets, even if we say not to
-    * also fixes a bug in which SunOS sends 512-byte packets even with
-    * an MSS of 128
-    */
-   if (len < 576 * 2)
-       len = 576 * 2;
-   rbuff = kmalloc(len + 4, GFP_KERNEL);
-   if (rbuff == NULL)
-       goto err_exit;
-   xbuff = kmalloc(len + 4, GFP_KERNEL);
-   if (xbuff == NULL)
-       goto err_exit;
-#ifdef SL_INCLUDE_CSLIP
-   cbuff = kmalloc(len + 4, GFP_KERNEL);
-   if (cbuff == NULL)
-       goto err_exit;
-   slcomp = slhc_init(16, 16);
-   if (slcomp == NULL)
-       goto err_exit;
-#endif
-   spin_lock_bh(&sl->lock);
-   if (sl->tty == NULL) {
-       spin_unlock_bh(&sl->lock);
-       err = -ENODEV;
-       goto err_exit;
-   }
-   sl->mtu      = mtu;
-   sl->buffsize = len;
-   sl->rcount   = 0;
-   sl->xleft    = 0;
-   rbuff = xchg(&sl->rbuff, rbuff);
-   xbuff = xchg(&sl->xbuff, xbuff);
-#ifdef SL_INCLUDE_CSLIP
-   cbuff = xchg(&sl->cbuff, cbuff);
-   slcomp = xchg(&sl->slcomp, slcomp);
-#endif
-#ifdef CONFIG_SLIP_MODE_SLIP6
-   sl->xdata    = 0;
-   sl->xbits    = 0;
-#endif
-   spin_unlock_bh(&sl->lock);
-   err = 0;
-
-   /* Cleanup */
-err_exit:
-#ifdef SL_INCLUDE_CSLIP
-   kfree(cbuff);
-   slhc_free(slcomp);
-#endif
-   kfree(xbuff);
-   kfree(rbuff);
-   return err;
-}
-
-/* Free a SLIP channel buffers. */
-static void sl_free_bufs(struct slip *sl)
-{
-   /* Free all SLIP frame buffers. */
-   kfree(xchg(&sl->rbuff, NULL));
-   kfree(xchg(&sl->xbuff, NULL));
-#ifdef SL_INCLUDE_CSLIP
-   kfree(xchg(&sl->cbuff, NULL));
-   slhc_free(xchg(&sl->slcomp, NULL));
-#endif
-}
-
-/*
-   Reallocate slip channel buffers.
- */
-
-static int sl_realloc_bufs(struct slip *sl, int mtu)
-{
-   int err = 0;
-   struct net_device *dev = sl->dev;
-   unsigned char *xbuff, *rbuff;
-#ifdef SL_INCLUDE_CSLIP
-   unsigned char *cbuff;
-#endif
-   int len = mtu * 2;
-
-/*
- * allow for arrival of larger UDP packets, even if we say not to
- * also fixes a bug in which SunOS sends 512-byte packets even with
- * an MSS of 128
- */
-   if (len < 576 * 2)
-       len = 576 * 2;
-
-   xbuff = kmalloc(len + 4, GFP_ATOMIC);
-   rbuff = kmalloc(len + 4, GFP_ATOMIC);
-#ifdef SL_INCLUDE_CSLIP
-   cbuff = kmalloc(len + 4, GFP_ATOMIC);
-#endif
-
-
-#ifdef SL_INCLUDE_CSLIP
-   if (xbuff == NULL || rbuff == NULL || cbuff == NULL)  {
-#else
-   if (xbuff == NULL || rbuff == NULL)  {
-#endif
-       if (mtu > sl->mtu) {
-           printk(KERN_WARNING "%s: unable to grow slip buffers, MTU change cancelled.n",
-                  dev->name);
-           err = -ENOBUFS;
-       }
-       goto done;
-   }
-   spin_lock_bh(&sl->lock);
-
-   err = -ENODEV;
-   if (sl->tty == NULL)
-       goto done_on_bh;
-
-   xbuff    = xchg(&sl->xbuff, xbuff);
-   rbuff    = xchg(&sl->rbuff, rbuff);
-#ifdef SL_INCLUDE_CSLIP
-   cbuff    = xchg(&sl->cbuff, cbuff);
-#endif
-   if (sl->xleft)  {
-       if (sl->xleft <= len)  {
-           memcpy(sl->xbuff, sl->xhead, sl->xleft);
-       } else  {
-           sl->xleft = 0;
-           dev->stats.tx_dropped++;
-       }
-   }
-   sl->xhead = sl->xbuff;
-
-   if (sl->rcount)  {
-       if (sl->rcount <= len) {
-           memcpy(sl->rbuff, rbuff, sl->rcount);
-       } else  {
-           sl->rcount = 0;
-           dev->stats.rx_over_errors++;
-           set_bit(SLF_ERROR, &sl->flags);
-       }
-   }
-   sl->mtu      = mtu;
-   dev->mtu      = mtu;
-   sl->buffsize = len;
-   err = 0;
-
-done_on_bh:
-   spin_unlock_bh(&sl->lock);
-
-done:
-   kfree(xbuff);
-   kfree(rbuff);
-#ifdef SL_INCLUDE_CSLIP
-   kfree(cbuff);
-#endif
-   return err;
-}
-
-
-/* Set the "sending" flag.  This must be atomic hence the set_bit. */
-static inline void sl_lock(struct slip *sl)
-{
-   netif_stop_queue(sl->dev);
-}
-
-
-/* Clear the "sending" flag.  This must be atomic, hence the ASM. */
-static inline void sl_unlock(struct slip *sl)
-{
-   netif_wake_queue(sl->dev);
-}
-
-/* Send one completely decapsulated IP datagram to the IP layer. */
-static void sl_bump(struct slip *sl)
-{
-   struct net_device *dev = sl->dev;
-   struct sk_buff *skb;
-   int count;
-
-   count = sl->rcount;
-#ifdef SL_INCLUDE_CSLIP
-   if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
-       unsigned char c = sl->rbuff[0];
-       if (c & SL_TYPE_COMPRESSED_TCP) {
-           /* ignore compressed packets when CSLIP is off */
-           if (!(sl->mode & SL_MODE_CSLIP)) {
-               printk(KERN_WARNING "%s: compressed packet ignoredn", dev->name);
-               return;
-           }
-           /* make sure we've reserved enough space for uncompress
-              to use */
-           if (count + 80 > sl->buffsize) {
-               dev->stats.rx_over_errors++;
-               return;
-           }
-           count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
-           if (count <= 0)
-               return;
-       } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
-           if (!(sl->mode & SL_MODE_CSLIP)) {
-               /* turn on header compression */
-               sl->mode |= SL_MODE_CSLIP;
-               sl->mode &= ~SL_MODE_ADAPTIVE;
-               printk(KERN_INFO "%s: header compression turned onn", dev->name);
-           }
-           sl->rbuff[0] &= 0x4f;
-           if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0)
-               return;
-       }
-   }
-#endif  /* SL_INCLUDE_CSLIP */
-
-   dev->stats.rx_bytes += count;
-
-   skb = dev_alloc_skb(count);
-   if (skb == NULL) {
-       printk(KERN_WARNING "%s: memory squeeze, dropping packet.n", dev->name);
-       dev->stats.rx_dropped++;
-       return;
-   }
-   skb->dev = dev;
-   memcpy(skb_put(skb, count), sl->rbuff, count);
-   skb_reset_mac_header(skb);
-   skb->protocol = htons(ETH_P_IP);
-   netif_rx_ni(skb);
-   dev->stats.rx_packets++;
-}
-
-/* Encapsulate one IP datagram and stuff into a TTY queue. */
-static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
-{
-   unsigned char *p;
-   int actual, count;
-
-   if (len > sl->mtu) {        /* Sigh, shouldn't occur BUT ... */
-       printk(KERN_WARNING "%s: truncating oversized transmit packet!n", sl->dev->name);
-       sl->dev->stats.tx_dropped++;
-       sl_unlock(sl);
-       return;
-   }
-
-   p = icp;
-#ifdef SL_INCLUDE_CSLIP
-   if (sl->mode & SL_MODE_CSLIP)
-       len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
-#endif
-#ifdef CONFIG_SLIP_MODE_SLIP6
-   if (sl->mode & SL_MODE_SLIP6)
-       count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
-   else
-#endif
-       count = slip_esc(p, (unsigned char *) sl->xbuff, len);
-
-   /* Order of next two lines is *very* important.
-    * When we are sending a little amount of data,
-    * the transfer may be completed inside the ops->write()
-    * routine, because it's running with interrupts enabled.
-    * In this case we *never* got WRITE_WAKEUP event,
-    * if we did not request it before write operation.
-    *       14 Oct 1994  Dmitry Gorodchanin.
-    */
-   set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
-   actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
-#ifdef SL_CHECK_TRANSMIT
-   sl->dev->trans_start = jiffies;
-#endif
-   sl->xleft = count - actual;
-   sl->xhead = sl->xbuff + actual;
-#ifdef CONFIG_SLIP_SMART
-   /* VSV */
-   clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
-#endif
-}
-
-/*
- * Called by the driver when there's room for more data.  If we have
- * more packets to send, we send them here.
- */
-static void slip_write_wakeup(struct tty_struct *tty)
-{
-   int actual;
-   struct slip *sl = tty->disc_data;
-
-   /* First make sure we're connected. */
-   if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
-       return;
-
-   if (sl->xleft <= 0)  {
-       /* Now serial buffer is almost free & we can start
-        * transmission of another packet */
-       sl->dev->stats.tx_packets++;
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       sl_unlock(sl);
-       return;
-   }
-
-   actual = tty->ops->write(tty, sl->xhead, sl->xleft);
-   sl->xleft -= actual;
-   sl->xhead += actual;
-}
-
-static void sl_tx_timeout(struct net_device *dev)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   spin_lock(&sl->lock);
-
-   if (netif_queue_stopped(dev)) {
-       if (!netif_running(dev))
-           goto out;
-
-       /* May be we must check transmitter timeout here ?
-        *      14 Oct 1994 Dmitry Gorodchanin.
-        */
-#ifdef SL_CHECK_TRANSMIT
-       if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ))  {
-           /* 20 sec timeout not reached */
-           goto out;
-       }
-       printk(KERN_WARNING "%s: transmit timed out, %s?n",
-           dev->name,
-           (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
-               "bad line quality" : "driver error");
-       sl->xleft = 0;
-       clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
-       sl_unlock(sl);
-#endif
-   }
-out:
-   spin_unlock(&sl->lock);
-}
-
-
-/* Encapsulate an IP datagram and kick it into a TTY queue. */
-static netdev_tx_t
-sl_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   spin_lock(&sl->lock);
-   if (!netif_running(dev)) {
-       spin_unlock(&sl->lock);
-       printk(KERN_WARNING "%s: xmit call when iface is downn", dev->name);
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-   }
-   if (sl->tty == NULL) {
-       spin_unlock(&sl->lock);
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-   }
-
-   sl_lock(sl);
-   dev->stats.tx_bytes += skb->len;
-   sl_encaps(sl, skb->data, skb->len);
-   spin_unlock(&sl->lock);
-
-   dev_kfree_skb(skb);
-   return NETDEV_TX_OK;
-}
-
-
-/******************************************
- *   Routines looking at netdevice side.
- ******************************************/
-
-/* Netdevice UP -> DOWN routine */
-
-static int
-sl_close(struct net_device *dev)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   spin_lock_bh(&sl->lock);
-   if (sl->tty)
-       /* TTY discipline is running. */
-       clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
-   netif_stop_queue(dev);
-   sl->rcount   = 0;
-   sl->xleft    = 0;
-   spin_unlock_bh(&sl->lock);
-
-   return 0;
-}
-
-/* Netdevice DOWN -> UP routine */
-
-static int sl_open(struct net_device *dev)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   if (sl->tty == NULL)
-       return -ENODEV;
-
-   sl->flags &= (1 << SLF_INUSE);
-   netif_start_queue(dev);
-   return 0;
-}
-
-/* Netdevice change MTU request */
-
-static int sl_change_mtu(struct net_device *dev, int new_mtu)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   if (new_mtu < 68 || new_mtu > 65534)
-       return -EINVAL;
-
-   if (new_mtu != dev->mtu)
-       return sl_realloc_bufs(sl, new_mtu);
-   return 0;
-}
-
-/* Netdevice get statistics request */
-
-static struct rtnl_link_stats64 *
-sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
-{
-   struct net_device_stats *devstats = &dev->stats;
-#ifdef SL_INCLUDE_CSLIP
-   struct slip *sl = netdev_priv(dev);
-   struct slcompress *comp = sl->slcomp;
-#endif
-   stats->rx_packets     = devstats->rx_packets;
-   stats->tx_packets     = devstats->tx_packets;
-   stats->rx_bytes       = devstats->rx_bytes;
-   stats->tx_bytes       = devstats->tx_bytes;
-   stats->rx_dropped     = devstats->rx_dropped;
-   stats->tx_dropped     = devstats->tx_dropped;
-   stats->tx_errors      = devstats->tx_errors;
-   stats->rx_errors      = devstats->rx_errors;
-   stats->rx_over_errors = devstats->rx_over_errors;
-
-#ifdef SL_INCLUDE_CSLIP
-   if (comp) {
-       /* Generic compressed statistics */
-       stats->rx_compressed   = comp->sls_i_compressed;
-       stats->tx_compressed   = comp->sls_o_compressed;
-
-       /* Are we really still needs this? */
-       stats->rx_fifo_errors += comp->sls_i_compressed;
-       stats->rx_dropped     += comp->sls_i_tossed;
-       stats->tx_fifo_errors += comp->sls_o_compressed;
-       stats->collisions     += comp->sls_o_misses;
-   }
-#endif
-   return stats;
-}
-
-/* Netdevice register callback */
-
-static int sl_init(struct net_device *dev)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   /*
-    *  Finish setting up the DEVICE info.
-    */
-
-   dev->mtu        = sl->mtu;
-   dev->type       = ARPHRD_SLIP + sl->mode;
-#ifdef SL_CHECK_TRANSMIT
-   dev->watchdog_timeo = 20*HZ;
-#endif
-   return 0;
-}
-
-
-static void sl_uninit(struct net_device *dev)
-{
-   struct slip *sl = netdev_priv(dev);
-
-   sl_free_bufs(sl);
-}
-
-/* Hook the destructor so we can free slip devices at the right point in time */
-static void sl_free_netdev(struct net_device *dev)
-{
-   int i = dev->base_addr;
-   free_netdev(dev);
-   slip_devs[i] = NULL;
-}
-
-static const struct net_device_ops sl_netdev_ops = {
-   .ndo_init       = sl_init,
-   .ndo_uninit     = sl_uninit,
-   .ndo_open       = sl_open,
-   .ndo_stop       = sl_close,
-   .ndo_start_xmit     = sl_xmit,
-   .ndo_get_stats64        = sl_get_stats64,
-   .ndo_change_mtu     = sl_change_mtu,
-   .ndo_tx_timeout     = sl_tx_timeout,
-#ifdef CONFIG_SLIP_SMART
-   .ndo_do_ioctl       = sl_ioctl,
-#endif
-};
-
-
-static void sl_setup(struct net_device *dev)
-{
-   dev->netdev_ops     = &sl_netdev_ops;
-   dev->destructor     = sl_free_netdev;
-
-   dev->hard_header_len    = 0;
-   dev->addr_len       = 0;
-   dev->tx_queue_len   = 10;
-
-   /* New-style flags. */
-   dev->flags      = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
-}
-
-/******************************************
-  Routines looking at TTY side.
- ******************************************/
-
-
-/*
- * 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. 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 = tty->disc_data;
-
-   if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
-       return;
-
-   /* Read the characters out of the buffer */
-   while (count--) {
-       if (fp && *fp++) {
-           if (!test_and_set_bit(SLF_ERROR, &sl->flags))
-               sl->dev->stats.rx_errors++;
-           cp++;
-           continue;
-       }
-#ifdef CONFIG_SLIP_MODE_SLIP6
-       if (sl->mode & SL_MODE_SLIP6)
-           slip_unesc6(sl, *cp++);
-       else
-#endif
-           slip_unesc(sl, *cp++);
-   }
-}
-
-/************************************
- *  slip_open helper routines.
- ************************************/
-
-/* Collect hanged up channels */
-static void sl_sync(void)
-{
-   int i;
-   struct net_device *dev;
-   struct slip   *sl;
-
-   for (i = 0; i < slip_maxdev; i++) {
-       dev = slip_devs[i];
-       if (dev == NULL)
-           break;
-
-       sl = netdev_priv(dev);
-       if (sl->tty || sl->leased)
-           continue;
-       if (dev->flags & IFF_UP)
-           dev_close(dev);
-   }
-}
-
-
-/* Find a free SLIP channel, and link in this `tty' line. */
-static struct slip *sl_alloc(dev_t line)
-{
-   int i;
-   char name[IFNAMSIZ];
-   struct net_device *dev = NULL;
-   struct slip       *sl;
-
-   for (i = 0; i < slip_maxdev; i++) {
-       dev = slip_devs[i];
-       if (dev == NULL)
-           break;
-   }
-   /* Sorry, too many, all slots in use */
-   if (i >= slip_maxdev)
-       return NULL;
-
-   sprintf(name, "sl%d", i);
-   dev = alloc_netdev(sizeof(*sl), name, sl_setup);
-   if (!dev)
-       return NULL;
-
-   dev->base_addr  = i;
-   sl = netdev_priv(dev);
-
-   /* Initialize channel control data */
-   sl->magic       = SLIP_MAGIC;
-   sl->dev         = dev;
-   spin_lock_init(&sl->lock);
-   sl->mode        = SL_MODE_DEFAULT;
-#ifdef CONFIG_SLIP_SMART
-   /* initialize timer_list struct */
-   init_timer(&sl->keepalive_timer);
-   sl->keepalive_timer.data = (unsigned long)sl;
-   sl->keepalive_timer.function = sl_keepalive;
-   init_timer(&sl->outfill_timer);
-   sl->outfill_timer.data = (unsigned long)sl;
-   sl->outfill_timer.function = sl_outfill;
-#endif
-   slip_devs[i] = dev;
-   return sl;
-}
-
-/*
- * Open the high-level part of the SLIP channel.
- * This function is called by the TTY module when the
- * 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)
-{
-   struct slip *sl;
-   int err;
-
-   if (!capable(CAP_NET_ADMIN))
-       return -EPERM;
-
-   if (tty->ops->write == NULL)
-       return -EOPNOTSUPP;
-
-   /* RTnetlink lock is misused here to serialize concurrent
-      opens of slip channels. There are better ways, but it is
-      the simplest one.
-    */
-   rtnl_lock();
-
-   /* Collect hanged up channels. */
-   sl_sync();
-
-   sl = tty->disc_data;
-
-   err = -EEXIST;
-   /* First make sure we're not already connected. */
-   if (sl && sl->magic == SLIP_MAGIC)
-       goto err_exit;
-
-   /* OK.  Find a free SLIP channel to use. */
-   err = -ENFILE;
-   sl = sl_alloc(tty_devnum(tty));
-   if (sl == NULL)
-       goto err_exit;
-
-   sl->tty = tty;
-   tty->disc_data = sl;
-   sl->pid = current->pid;
-
-   if (!test_bit(SLF_INUSE, &sl->flags)) {
-       /* Perform the low-level SLIP initialization. */
-       err = sl_alloc_bufs(sl, SL_MTU);
-       if (err)
-           goto err_free_chan;
-
-       set_bit(SLF_INUSE, &sl->flags);
-
-       err = register_netdevice(sl->dev);
-       if (err)
-           goto err_free_bufs;
-   }
-
-#ifdef CONFIG_SLIP_SMART
-   if (sl->keepalive) {
-       sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ;
-       add_timer(&sl->keepalive_timer);
-   }
-   if (sl->outfill) {
-       sl->outfill_timer.expires = jiffies + sl->outfill * HZ;
-       add_timer(&sl->outfill_timer);
-   }
-#endif
-
-   /* Done.  We have linked the TTY line to a channel. */
-   rtnl_unlock();
-   tty->receive_room = 65536;  /* We don't flow control */
-
-   /* TTY layer expects 0 on success */
-   return 0;
-
-err_free_bufs:
-   sl_free_bufs(sl);
-
-err_free_chan:
-   sl->tty = NULL;
-   tty->disc_data = NULL;
-   clear_bit(SLF_INUSE, &sl->flags);
-
-err_exit:
-   rtnl_unlock();
-
-   /* Count references from TTY module */
-   return err;
-}
-
-/*
- * Close down a SLIP channel.
- * This means flushing out any pending queues, and then returning. This
- * call is serialized against other ldisc functions.
- *
- * We also use this method fo a hangup event
- */
-
-static void slip_close(struct tty_struct *tty)
-{
-   struct slip *sl = tty->disc_data;
-
-   /* First make sure we're connected. */
-   if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)
-       return;
-
-   tty->disc_data = NULL;
-   sl->tty = NULL;
-
-   /* VSV = very important to remove timers */
-#ifdef CONFIG_SLIP_SMART
-   del_timer_sync(&sl->keepalive_timer);
-   del_timer_sync(&sl->outfill_timer);
-#endif
-   /* Flush network side */
-   unregister_netdev(sl->dev);
-   /* This will complete via sl_free_netdev */
-}
-
-static int slip_hangup(struct tty_struct *tty)
-{
-   slip_close(tty);
-   return 0;
-}
- /************************************************************************
-  *            STANDARD SLIP ENCAPSULATION          *
-  ************************************************************************/
-
-static int slip_esc(unsigned char *s, unsigned char *d, int len)
-{
-   unsigned char *ptr = d;
-   unsigned char c;
-
-   /*
-    * Send an initial END character to flush out any
-    * data that may have accumulated in the receiver
-    * due to line noise.
-    */
-
-   *ptr++ = END;
-
-   /*
-    * For each byte in the packet, send the appropriate
-    * character sequence, according to the SLIP protocol.
-    */
-
-   while (len-- > 0) {
-       switch (c = *s++) {
-       case END:
-           *ptr++ = ESC;
-           *ptr++ = ESC_END;
-           break;
-       case ESC:
-           *ptr++ = ESC;
-           *ptr++ = ESC_ESC;
-           break;
-       default:
-           *ptr++ = c;
-           break;
-       }
-   }
-   *ptr++ = END;
-   return ptr - d;
-}
-
-static void slip_unesc(struct slip *sl, unsigned char s)
-{
-
-   switch (s) {
-   case END:
-#ifdef CONFIG_SLIP_SMART
-       /* drop keeptest bit = VSV */
-       if (test_bit(SLF_KEEPTEST, &sl->flags))
-           clear_bit(SLF_KEEPTEST, &sl->flags);
-#endif
-
-       if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
-           (sl->rcount > 2))
-           sl_bump(sl);
-       clear_bit(SLF_ESCAPE, &sl->flags);
-       sl->rcount = 0;
-       return;
-
-   case ESC:
-       set_bit(SLF_ESCAPE, &sl->flags);
-       return;
-   case ESC_ESC:
-       if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
-           s = ESC;
-       break;
-   case ESC_END:
-       if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
-           s = END;
-       break;
-   }
-   if (!test_bit(SLF_ERROR, &sl->flags))  {
-       if (sl->rcount < sl->buffsize)  {
-           sl->rbuff[sl->rcount++] = s;
-           return;
-       }
-       sl->dev->stats.rx_over_errors++;
-       set_bit(SLF_ERROR, &sl->flags);
-   }
-}
-
-
-#ifdef CONFIG_SLIP_MODE_SLIP6
-/************************************************************************
- *          6 BIT SLIP ENCAPSULATION           *
- ************************************************************************/
-
-static int slip_esc6(unsigned char *s, unsigned char *d, int len)
-{
-   unsigned char *ptr = d;
-   unsigned char c;
-   int i;
-   unsigned short v = 0;
-   short bits = 0;
-
-   /*
-    * Send an initial END character to flush out any
-    * data that may have accumulated in the receiver
-    * due to line noise.
-    */
-
-   *ptr++ = 0x70;
-
-   /*
-    * Encode the packet into printable ascii characters
-    */
-
-   for (i = 0; i < len; ++i) {
-       v = (v << 8) | s[i];
-       bits += 8;
-       while (bits >= 6) {
-           bits -= 6;
-           c = 0x30 + ((v >> bits) & 0x3F);
-           *ptr++ = c;
-       }
-   }
-   if (bits) {
-       c = 0x30 + ((v << (6 - bits)) & 0x3F);
-       *ptr++ = c;
-   }
-   *ptr++ = 0x70;
-   return ptr - d;
-}
-
-static void slip_unesc6(struct slip *sl, unsigned char s)
-{
-   unsigned char c;
-
-   if (s == 0x70) {
-#ifdef CONFIG_SLIP_SMART
-       /* drop keeptest bit = VSV */
-       if (test_bit(SLF_KEEPTEST, &sl->flags))
-           clear_bit(SLF_KEEPTEST, &sl->flags);
-#endif
-
-       if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
-           (sl->rcount > 2))
-           sl_bump(sl);
-       sl->rcount = 0;
-       sl->xbits = 0;
-       sl->xdata = 0;
-   } else if (s >= 0x30 && s < 0x70) {
-       sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
-       sl->xbits += 6;
-       if (sl->xbits >= 8) {
-           sl->xbits -= 8;
-           c = (unsigned char)(sl->xdata >> sl->xbits);
-           if (!test_bit(SLF_ERROR, &sl->flags))  {
-               if (sl->rcount < sl->buffsize)  {
-                   sl->rbuff[sl->rcount++] = c;
-                   return;
-               }
-               sl->dev->stats.rx_over_errors++;
-               set_bit(SLF_ERROR, &sl->flags);
-           }
-       }
-   }
-}
-#endif /* CONFIG_SLIP_MODE_SLIP6 */
-
-/* Perform I/O control on an active SLIP channel. */
-static int slip_ioctl(struct tty_struct *tty, struct file *file,
-                   unsigned int cmd, unsigned long arg)
-{
-   struct slip *sl = tty->disc_data;
-   unsigned int tmp;
-   int __user *p = (int __user *)arg;
-
-   /* First make sure we're connected. */
-   if (!sl || sl->magic != SLIP_MAGIC)
-       return -EINVAL;
-
-   switch (cmd) {
-   case SIOCGIFNAME:
-       tmp = strlen(sl->dev->name) + 1;
-       if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
-           return -EFAULT;
-       return 0;
-
-   case SIOCGIFENCAP:
-       if (put_user(sl->mode, p))
-           return -EFAULT;
-       return 0;
-
-   case SIOCSIFENCAP:
-       if (get_user(tmp, p))
-           return -EFAULT;
-#ifndef SL_INCLUDE_CSLIP
-       if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))
-           return -EINVAL;
-#else
-       if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
-           (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))
-           /* return -EINVAL; */
-           tmp &= ~SL_MODE_ADAPTIVE;
-#endif
-#ifndef CONFIG_SLIP_MODE_SLIP6
-       if (tmp & SL_MODE_SLIP6)
-           return -EINVAL;
-#endif
-       sl->mode = tmp;
-       sl->dev->type = ARPHRD_SLIP + sl->mode;
-       return 0;
-
-   case SIOCSIFHWADDR:
-       return -EINVAL;
-
-#ifdef CONFIG_SLIP_SMART
-   /* VSV changes start here */
-   case SIOCSKEEPALIVE:
-       if (get_user(tmp, p))
-           return -EFAULT;
-       if (tmp > 255) /* max for unchar */
-           return -EINVAL;
-
-       spin_lock_bh(&sl->lock);
-       if (!sl->tty) {
-           spin_unlock_bh(&sl->lock);
-           return -ENODEV;
-       }
-       sl->keepalive = (u8)tmp;
-       if (sl->keepalive != 0) {
-           mod_timer(&sl->keepalive_timer,
-                   jiffies + sl->keepalive * HZ);
-           set_bit(SLF_KEEPTEST, &sl->flags);
-       } else
-           del_timer(&sl->keepalive_timer);
-       spin_unlock_bh(&sl->lock);
-       return 0;
-
-   case SIOCGKEEPALIVE:
-       if (put_user(sl->keepalive, p))
-           return -EFAULT;
-       return 0;
-
-   case SIOCSOUTFILL:
-       if (get_user(tmp, p))
-           return -EFAULT;
-       if (tmp > 255) /* max for unchar */
-           return -EINVAL;
-       spin_lock_bh(&sl->lock);
-       if (!sl->tty) {
-           spin_unlock_bh(&sl->lock);
-           return -ENODEV;
-       }
-       sl->outfill = (u8)tmp;
-       if (sl->outfill != 0) {
-           mod_timer(&sl->outfill_timer,
-                       jiffies + sl->outfill * HZ);
-           set_bit(SLF_OUTWAIT, &sl->flags);
-       } else
-           del_timer(&sl->outfill_timer);
-       spin_unlock_bh(&sl->lock);
-       return 0;
-
-   case SIOCGOUTFILL:
-       if (put_user(sl->outfill, p))
-           return -EFAULT;
-       return 0;
-   /* VSV changes end */
-#endif
-   default:
-       return tty_mode_ioctl(tty, file, cmd, arg);
-   }
-}
-
-#ifdef CONFIG_COMPAT
-static long slip_compat_ioctl(struct tty_struct *tty, struct file *file,
-                   unsigned int cmd, unsigned long arg)
-{
-   switch (cmd) {
-   case SIOCGIFNAME:
-   case SIOCGIFENCAP:
-   case SIOCSIFENCAP:
-   case SIOCSIFHWADDR:
-   case SIOCSKEEPALIVE:
-   case SIOCGKEEPALIVE:
-   case SIOCSOUTFILL:
-   case SIOCGOUTFILL:
-       return slip_ioctl(tty, file, cmd,
-                 (unsigned long)compat_ptr(arg));
-   }
-
-   return -ENOIOCTLCMD;
-}
-#endif
-
-/* VSV changes start here */
-#ifdef CONFIG_SLIP_SMART
-/* function do_ioctl called from net/core/dev.c
-   to allow get/set outfill/keepalive parameter
-   by ifconfig                                 */
-
-static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-   struct slip *sl = netdev_priv(dev);
-   unsigned long *p = (unsigned long *)&rq->ifr_ifru;
-
-   if (sl == NULL)     /* Allocation failed ?? */
-       return -ENODEV;
-
-   spin_lock_bh(&sl->lock);
-
-   if (!sl->tty) {
-       spin_unlock_bh(&sl->lock);
-       return -ENODEV;
-   }
-
-   switch (cmd) {
-   case SIOCSKEEPALIVE:
-       /* max for unchar */
-       if ((unsigned)*p > 255) {
-           spin_unlock_bh(&sl->lock);
-           return -EINVAL;
-       }
-       sl->keepalive = (u8)*p;
-       if (sl->keepalive != 0) {
-           sl->keepalive_timer.expires =
-                       jiffies + sl->keepalive * HZ;
-           mod_timer(&sl->keepalive_timer,
-                       jiffies + sl->keepalive * HZ);
-           set_bit(SLF_KEEPTEST, &sl->flags);
-       } else
-           del_timer(&sl->keepalive_timer);
-       break;
-
-   case SIOCGKEEPALIVE:
-       *p = sl->keepalive;
-       break;
-
-   case SIOCSOUTFILL:
-       if ((unsigned)*p > 255) { /* max for unchar */
-           spin_unlock_bh(&sl->lock);
-           return -EINVAL;
-       }
-       sl->outfill = (u8)*p;
-       if (sl->outfill != 0) {
-           mod_timer(&sl->outfill_timer,
-                       jiffies + sl->outfill * HZ);
-           set_bit(SLF_OUTWAIT, &sl->flags);
-       } else
-           del_timer(&sl->outfill_timer);
-       break;
-
-   case SIOCGOUTFILL:
-       *p = sl->outfill;
-       break;
-
-   case SIOCSLEASE:
-       /* Resolve race condition, when ioctl'ing hanged up
-          and opened by another process device.
-        */
-       if (sl->tty != current->signal->tty &&
-                       sl->pid != current->pid) {
-           spin_unlock_bh(&sl->lock);
-           return -EPERM;
-       }
-       sl->leased = 0;
-       if (*p)
-           sl->leased = 1;
-       break;
-
-   case SIOCGLEASE:
-       *p = sl->leased;
-   }
-   spin_unlock_bh(&sl->lock);
-   return 0;
-}
-#endif
-/* VSV changes end */
-
-static struct tty_ldisc_ops sl_ldisc = {
-   .owner      = THIS_MODULE,
-   .magic      = TTY_LDISC_MAGIC,
-   .name       = "slip",
-   .open       = slip_open,
-   .close      = slip_close,
-   .hangup     = slip_hangup,
-   .ioctl      = slip_ioctl,
-#ifdef CONFIG_COMPAT
-   .compat_ioctl   = slip_compat_ioctl,
-#endif
-   .receive_buf    = slip_receive_buf,
-   .write_wakeup   = slip_write_wakeup,
-};
-
-static int __init slip_init(void)
-{
-   int status;
-
-   if (slip_maxdev < 4)
-       slip_maxdev = 4; /* Sanity */
-
-   printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"
-#ifdef CONFIG_SLIP_MODE_SLIP6
-          " (6 bit encapsulation enabled)"
-#endif
-          ".n",
-          SLIP_VERSION, slip_maxdev);
-#if defined(SL_INCLUDE_CSLIP)
-   printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.n");
-#endif
-#ifdef CONFIG_SLIP_SMART
-   printk(KERN_INFO "SLIP linefill/keepalive option.n");
-#endif
-
-   slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev,
-                               GFP_KERNEL);
-   if (!slip_devs) {
-       printk(KERN_ERR "SLIP: Can't allocate slip devices array.n");
-       return -ENOMEM;
-   }
-
-   /* Fill in our line protocol discipline, and register it */
-   status = tty_register_ldisc(N_SLIP, &sl_ldisc);
-   if (status != 0) {
-       printk(KERN_ERR "SLIP: can't register line discipline (err = %d)n", status);
-       kfree(slip_devs);
-   }
-   return status;
-}
-
-static void __exit slip_exit(void)
-{
-   int i;
-   struct net_device *dev;
-   struct slip *sl;
-   unsigned long timeout = jiffies + HZ;
-   int busy = 0;
-
-   if (slip_devs == NULL)
-       return;
-
-   /* First of all: check for active disciplines and hangup them.
-    */
-   do {
-       if (busy)
-           msleep_interruptible(100);
-
-       busy = 0;
-       for (i = 0; i < slip_maxdev; i++) {
-           dev = slip_devs[i];
-           if (!dev)
-               continue;
-           sl = netdev_priv(dev);
-           spin_lock_bh(&sl->lock);
-           if (sl->tty) {
-               busy++;
-               tty_hangup(sl->tty);
-           }
-           spin_unlock_bh(&sl->lock);
-       }
-   } while (busy && time_before(jiffies, timeout));
-
-   /* FIXME: hangup is async so we should wait when doing this second
-      phase */
-
-   for (i = 0; i < slip_maxdev; i++) {
-       dev = slip_devs[i];
-       if (!dev)
-           continue;
-       slip_devs[i] = NULL;
-
-       sl = netdev_priv(dev);
-       if (sl->tty) {
-           printk(KERN_ERR "%s: tty discipline still runningn",
-                  dev->name);
-           /* Intentionally leak the control block. */
-           dev->destructor = NULL;
-       }
-
-       unregister_netdev(dev);
-   }
-
-   kfree(slip_devs);
-   slip_devs = NULL;
-
-   i = tty_unregister_ldisc(N_SLIP);
-   if (i != 0)
-       printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)n", i);
-}
-
-module_init(slip_init);
-module_exit(slip_exit);
-
-#ifdef CONFIG_SLIP_SMART
-/*
- * This is start of the code for multislip style line checking
- * added by Stanislav Voronyi. All changes before marked VSV
- */
-
-static void sl_outfill(unsigned long sls)
-{
-   struct slip *sl = (struct slip *)sls;
-
-   spin_lock(&sl->lock);
-
-   if (sl->tty == NULL)
-       goto out;
-
-   if (sl->outfill) {
-       if (test_bit(SLF_OUTWAIT, &sl->flags)) {
-           /* no packets were transmitted, do outfill */
-#ifdef CONFIG_SLIP_MODE_SLIP6
-           unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;
-#else
-           unsigned char s = END;
-#endif
-           /* put END into tty queue. Is it right ??? */
-           if (!netif_queue_stopped(sl->dev)) {
-               /* if device busy no outfill */
-               sl->tty->ops->write(sl->tty, &s, 1);
-           }
-       } else
-           set_bit(SLF_OUTWAIT, &sl->flags);
-
-       mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
-   }
-out:
-   spin_unlock(&sl->lock);
-}
-
-static void sl_keepalive(unsigned long sls)
-{
-   struct slip *sl = (struct slip *)sls;
-
-   spin_lock(&sl->lock);
-
-   if (sl->tty == NULL)
-       goto out;
-
-   if (sl->keepalive) {
-       if (test_bit(SLF_KEEPTEST, &sl->flags)) {
-           /* keepalive still high :(, we must hangup */
-           if (sl->outfill)
-               /* outfill timer must be deleted too */
-               (void)del_timer(&sl->outfill_timer);
-           printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.n", sl->dev->name);
-           /* this must hangup tty & close slip */
-           tty_hangup(sl->tty);
-           /* I think we need not something else */
-           goto out;
-       } else
-           set_bit(SLF_KEEPTEST, &sl->flags);
-
-       mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
-   }
-out:
-   spin_unlock(&sl->lock);
-}
-
-#endif
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_SLIP);
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
deleted file mode 100644
index 67673cf..0000000
--- a/drivers/net/slip.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * slip.h  Define the SLIP device driver interface and constants.
- *
- * NOTE:   THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY
- *     AS SOON AS POSSIBLE!
- *
- * Version:    @(#)slip.h  1.2.0   03/28/93
- *
- * Fixes:
- *     Alan Cox    :   Added slip mtu field.
- *     Matt Dillon :   Printable slip (borrowed from net2e)
- *     Alan Cox    :   Added SL_SLIP_LOTS
- * Dmitry Gorodchanin  :   A lot of changes in the 'struct slip'
- * Dmitry Gorodchanin  :   Added CSLIP statistics.
- * Stanislav Voronyi   :   Make line checking as created by
- *                 Igor Chechik, RELCOM Corp.
- * Craig Schlenter     :   Fixed #define bug that caused
- *                 CSLIP telnets to hang in 1.3.61-6
- *
- * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- */
-#ifndef _LINUX_SLIP_H
-#define _LINUX_SLIP_H
-
-
-#if defined(CONFIG_INET) && defined(CONFIG_SLIP_COMPRESSED)
-# define SL_INCLUDE_CSLIP
-#endif
-
-#ifdef SL_INCLUDE_CSLIP
-# define SL_MODE_DEFAULT SL_MODE_ADAPTIVE
-#else
-# define SL_MODE_DEFAULT SL_MODE_SLIP
-#endif
-
-/* SLIP configuration. */
-#define SL_NRUNIT  256     /* MAX number of SLIP channels;
-                      This can be overridden with
-                      insmod -oslip_maxdev=nnn */
-#define SL_MTU     296     /* 296; I am used to 600- FvK   */
-
-/* SLIP protocol characters. */
-#define END             0300       /* indicates end of frame   */
-#define ESC             0333       /* indicates byte stuffing  */
-#define ESC_END         0334       /* ESC ESC_END means END 'data' */
-#define ESC_ESC         0335       /* ESC ESC_ESC means ESC 'data' */
-
-
-struct slip {
-  int          magic;
-
-  /* Various fields. */
-  struct tty_struct    *tty;       /* ptr to TTY structure     */
-  struct net_device    *dev;       /* easy for intr handling   */
-  spinlock_t       lock;
-
-#ifdef SL_INCLUDE_CSLIP
-  struct slcompress    *slcomp;    /* for header compression   */
-  unsigned char        *cbuff;     /* compression buffer       */
-#endif
-
-  /* These are pointers to the malloc()ed frame buffers. */
-  unsigned char        *rbuff;     /* receiver buffer      */
-  int                   rcount;         /* received chars counter       */
-  unsigned char        *xbuff;     /* transmitter buffer       */
-  unsigned char         *xhead;         /* pointer to next byte to XMIT */
-  int                   xleft;          /* bytes left in XMIT queue     */
-  int          mtu;        /* Our mtu (to spot changes!)   */
-  int                   buffsize;       /* Max buffers sizes            */
-
-#ifdef CONFIG_SLIP_MODE_SLIP6
-  int          xdata, xbits;   /* 6 bit slip controls      */
-#endif
-
-  unsigned long        flags;      /* Flag values/ mode etc    */
-#define SLF_INUSE  0       /* Channel in use               */
-#define SLF_ESCAPE 1               /* ESC received                 */
-#define SLF_ERROR  2               /* Parity, etc. error           */
-#define SLF_KEEPTEST   3       /* Keepalive test flag      */
-#define SLF_OUTWAIT    4       /* is outpacket was flag    */
-
-  unsigned char        mode;       /* SLIP mode            */
-  unsigned char        leased;
-  pid_t            pid;
-#define SL_MODE_SLIP   0
-#define SL_MODE_CSLIP  1
-#define SL_MODE_SLIP6  2       /* Matt Dillon's printable slip */
-#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP)
-#define SL_MODE_AX25   4
-#define SL_MODE_ADAPTIVE 8
-#ifdef CONFIG_SLIP_SMART
-  unsigned char        outfill;    /* # of sec between outfill packet */
-  unsigned char        keepalive;  /* keepalive seconds        */
-  struct timer_list    outfill_timer;
-  struct timer_list    keepalive_timer;
-#endif
-};
-
-#define SLIP_MAGIC 0x5302
-
-#endif /* _LINUX_SLIP.H */
diff --git a/drivers/net/slip/Kconfig b/drivers/net/slip/Kconfig
new file mode 100644
index 0000000..211b160
--- /dev/null
+++ b/drivers/net/slip/Kconfig
@@ -0,0 +1,79 @@
+#
+# SLIP network device configuration
+#
+
+config SLIP
+   tristate "SLIP (serial line) support"
+   ---help---
+     Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+     connect to your Internet service provider or to connect to some
+     other local Unix box or if you want to configure your Linux box as a
+     Slip/CSlip server for other people to dial in. SLIP (Serial Line
+     Internet Protocol) is a protocol used to send Internet traffic over
+     serial connections such as telephone lines or null modem cables;
+     nowadays, the protocol PPP is more commonly used for this same
+     purpose.
+
+     Normally, your access provider has to support SLIP in order for you
+     to be able to use it, but there is now a SLIP emulator called SLiRP
+     around (available from
+     <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
+     allows you to use SLIP over a regular dial up shell connection. If
+     you plan to use SLiRP, make sure to say Y to CSLIP, below. The
+     NET-3-HOWTO, available from
+     <http://www.tldp.org/docs.html#howto>, explains how to
+     configure SLIP. Note that you don't need this option if you just
+     want to run term (term is a program which gives you almost full
+     Internet connectivity if you have a regular dial up shell account on
+     some Internet connected Unix computer. Read
+     <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
+     support will enlarge your kernel by about 4 KB. If unsure, say N.
+
+     To compile this driver as a module, choose M here. The module
+     will be called slip.
+
+config SLHC
+   tristate
+   ---help---
+     This option enables Van Jacobsen serial line header compression
+     routines.
+
+if SLIP
+
+config SLIP_COMPRESSED
+   bool "CSLIP compressed headers"
+   depends on SLIP
+   select SLHC
+   ---help---
+     This protocol is faster than SLIP because it uses compression on the
+     TCP/IP headers (not on the data itself), but it has to be supported
+     on both ends. Ask your access provider if you are not sure and
+     answer Y, just in case. You will still be able to use plain SLIP. If
+     you plan to use SLiRP, the SLIP emulator (available from
+     <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
+     allows you to use SLIP over a regular dial up shell connection, you
+     definitely want to say Y here. The NET-3-HOWTO, available from
+     <http://www.tldp.org/docs.html#howto>, explains how to configure
+     CSLIP. This won't enlarge your kernel.
+
+config SLIP_SMART
+   bool "Keepalive and linefill"
+   depends on SLIP
+   ---help---
+     Adds additional capabilities to the SLIP driver to support the
+     RELCOM line fill and keepalive monitoring. Ideal on poor quality
+     analogue lines.
+
+config SLIP_MODE_SLIP6
+   bool "Six bit SLIP encapsulation"
+   depends on SLIP
+   ---help---
+     Just occasionally you may need to run IP over hostile serial
+     networks that don't pass all control characters or are only seven
+     bit. Saying Y here adds an extra mode you can use with SLIP:
+     "slip6". In this mode, SLIP will only send normal ASCII symbols over
+     the serial device. Naturally, this has to be supported at the other
+     end of the link as well. It's good enough, for example, to run IP
+     over the async ports of a Camtec JNT Pad. If unsure, say N.
+
+endif # SLIP
diff --git a/drivers/net/slip/Makefile b/drivers/net/slip/Makefile
new file mode 100644
index 0000000..e3ebc59
--- /dev/null
+++ b/drivers/net/slip/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SLIP network device drivers.
+#
+
+obj-$(CONFIG_SLIP) += slip.o
+obj-$(CONFIG_SLHC) += slhc.o
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
new file mode 100644
index 0000000..0a0a664
--- /dev/null
+++ b/drivers/net/slip/slhc.c
@@ -0,0 +1,742 @@
+/*
+ * Routines to compress and uncompress tcp packets (for transmission
+ * over low speed serial lines).
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ *
+ *
+ * modified for KA9Q Internet Software Package by
+ * Katie Stevens (dkstevens@ucdavis.edu)
+ * University of California, Davis
+ * Computing Services
+ * - 01-31-90  initial adaptation (from 1.19)
+ * PPP.05  02-15-90 [ks]
+ * PPP.08  05-02-90 [ks]   use PPP protocol field to signal compression
+ * PPP.15  09-90    [ks]   improve mbuf handling
+ * PPP.16  11-02    [karn] substantially rewritten to use NOS facilities
+ *
+ * - Feb 1991  Bill_Simpson@um.cc.umich.edu
+ *         variable number of conversation slots
+ *         allow zero or one slots
+ *         separate routines
+ *         status display
+ * - Jul 1994  Dmitry Gorodchanin
+ *         Fixes for memory leaks.
+ *      - Oct 1994      Dmitry Gorodchanin
+ *                      Modularization.
+ * - Jan 1995  Bjorn Ekwall
+ *         Use ip_fast_csum from ip.h
+ * - July 1995 Christos A. Polyzols
+ *         Spotted bug in tcp option checking
+ *
+ *
+ * This module is a difficult issue. It's clearly inet code but it's also clearly
+ * driver code belonging close to PPP and SLIP
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <net/slhc_vj.h>
+
+#ifdef CONFIG_INET
+/* Entire module is for IP only */
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/termios.h>
+#include <linux/in.h>
+#include <linux/fcntl.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+#include <asm/unaligned.h>
+
+static unsigned char *encode(unsigned char *cp, unsigned short n);
+static long decode(unsigned char **cpp);
+static unsigned char * put16(unsigned char *cp, unsigned short x);
+static unsigned short pull16(unsigned char **cpp);
+
+/* Initialize compression data structure
+ * slots must be in range 0 to 255 (zero meaning no compression)
+ */
+struct slcompress *
+slhc_init(int rslots, int tslots)
+{
+   register short i;
+   register struct cstate *ts;
+   struct slcompress *comp;
+
+   comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
+   if (! comp)
+       goto out_fail;
+
+   if ( rslots > 0  &&  rslots < 256 ) {
+       size_t rsize = rslots * sizeof(struct cstate);
+       comp->rstate = kzalloc(rsize, GFP_KERNEL);
+       if (! comp->rstate)
+           goto out_free;
+       comp->rslot_limit = rslots - 1;
+   }
+
+   if ( tslots > 0  &&  tslots < 256 ) {
+       size_t tsize = tslots * sizeof(struct cstate);
+       comp->tstate = kzalloc(tsize, GFP_KERNEL);
+       if (! comp->tstate)
+           goto out_free2;
+       comp->tslot_limit = tslots - 1;
+   }
+
+   comp->xmit_oldest = 0;
+   comp->xmit_current = 255;
+   comp->recv_current = 255;
+   /*
+    * don't accept any packets with implicit index until we get
+    * one with an explicit index.  Otherwise the uncompress code
+    * will try to use connection 255, which is almost certainly
+    * out of range
+    */
+   comp->flags |= SLF_TOSS;
+
+   if ( tslots > 0 ) {
+       ts = comp->tstate;
+       for(i = comp->tslot_limit; i > 0; --i){
+           ts[i].cs_this = i;
+           ts[i].next = &(ts[i - 1]);
+       }
+       ts[0].next = &(ts[comp->tslot_limit]);
+       ts[0].cs_this = 0;
+   }
+   return comp;
+
+out_free2:
+   kfree(comp->rstate);
+out_free:
+   kfree(comp);
+out_fail:
+   return NULL;
+}
+
+
+/* Free a compression data structure */
+void
+slhc_free(struct slcompress *comp)
+{
+   if ( comp == NULLSLCOMPR )
+       return;
+
+   if ( comp->tstate != NULLSLSTATE )
+       kfree( comp->tstate );
+
+   if ( comp->rstate != NULLSLSTATE )
+       kfree( comp->rstate );
+
+   kfree( comp );
+}
+
+
+/* Put a short in host order into a char array in network order */
+static inline unsigned char *
+put16(unsigned char *cp, unsigned short x)
+{
+   *cp++ = x >> 8;
+   *cp++ = x;
+
+   return cp;
+}
+
+
+/* Encode a number */
+static unsigned char *
+encode(unsigned char *cp, unsigned short n)
+{
+   if(n >= 256 || n == 0){
+       *cp++ = 0;
+       cp = put16(cp,n);
+   } else {
+       *cp++ = n;
+   }
+   return cp;
+}
+
+/* Pull a 16-bit integer in host order from buffer in network byte order */
+static unsigned short
+pull16(unsigned char **cpp)
+{
+   short rval;
+
+   rval = *(*cpp)++;
+   rval <<= 8;
+   rval |= *(*cpp)++;
+   return rval;
+}
+
+/* Decode a number */
+static long
+decode(unsigned char **cpp)
+{
+   register int x;
+
+   x = *(*cpp)++;
+   if(x == 0){
+       return pull16(cpp) & 0xffff;    /* pull16 returns -1 on error */
+   } else {
+       return x & 0xff;        /* -1 if PULLCHAR returned error */
+   }
+}
+
+/*
+ * icp and isize are the original packet.
+ * ocp is a place to put a copy if necessary.
+ * cpp is initially a pointer to icp.  If the copy is used,
+ *    change it to ocp.
+ */
+
+int
+slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
+   unsigned char *ocp, unsigned char **cpp, int compress_cid)
+{
+   register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
+   register struct cstate *lcs = ocs;
+   register struct cstate *cs = lcs->next;
+   register unsigned long deltaS, deltaA;
+   register short changes = 0;
+   int hlen;
+   unsigned char new_seq[16];
+   register unsigned char *cp = new_seq;
+   struct iphdr *ip;
+   struct tcphdr *th, *oth;
+   __sum16 csum;
+
+
+   /*
+    *  Don't play with runt packets.
+    */
+
+   if(isize<sizeof(struct iphdr))
+       return isize;
+
+   ip = (struct iphdr *) icp;
+
+   /* Bail if this packet isn't TCP, or is an IP fragment */
+   if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
+       /* Send as regular IP */
+       if(ip->protocol != IPPROTO_TCP)
+           comp->sls_o_nontcp++;
+       else
+           comp->sls_o_tcp++;
+       return isize;
+   }
+   /* Extract TCP header */
+
+   th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
+   hlen = ip->ihl*4 + th->doff*4;
+
+   /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
+    *  some other control bit is set). Also uncompressible if
+    *  it's a runt.
+    */
+   if(hlen > isize || th->syn || th->fin || th->rst ||
+       ! (th->ack)){
+       /* TCP connection stuff; send as regular IP */
+       comp->sls_o_tcp++;
+       return isize;
+   }
+   /*
+    * Packet is compressible -- we're going to send either a
+    * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
+    * we need to locate (or create) the connection state.
+    *
+    * States are kept in a circularly linked list with
+    * xmit_oldest pointing to the end of the list.  The
+    * list is kept in lru order by moving a state to the
+    * head of the list whenever it is referenced.  Since
+    * the list is short and, empirically, the connection
+    * we want is almost always near the front, we locate
+    * states via linear search.  If we don't find a state
+    * for the datagram, the oldest state is (re-)used.
+    */
+   for ( ; ; ) {
+       if( ip->saddr == cs->cs_ip.saddr
+        && ip->daddr == cs->cs_ip.daddr
+        && th->source == cs->cs_tcp.source
+        && th->dest == cs->cs_tcp.dest)
+           goto found;
+
+       /* if current equal oldest, at end of list */
+       if ( cs == ocs )
+           break;
+       lcs = cs;
+       cs = cs->next;
+       comp->sls_o_searches++;
+   }
+   /*
+    * Didn't find it -- re-use oldest cstate.  Send an
+    * uncompressed packet that tells the other side what
+    * connection number we're using for this conversation.
+    *
+    * Note that since the state list is circular, the oldest
+    * state points to the newest and we only need to set
+    * xmit_oldest to update the lru linkage.
+    */
+   comp->sls_o_misses++;
+   comp->xmit_oldest = lcs->cs_this;
+   goto uncompressed;
+
+found:
+   /*
+    * Found it -- move to the front on the connection list.
+    */
+   if(lcs == ocs) {
+       /* found at most recently used */
+   } else if (cs == ocs) {
+       /* found at least recently used */
+       comp->xmit_oldest = lcs->cs_this;
+   } else {
+       /* more than 2 elements */
+       lcs->next = cs->next;
+       cs->next = ocs->next;
+       ocs->next = cs;
+   }
+
+   /*
+    * Make sure that only what we expect to change changed.
+    * Check the following:
+    * IP protocol version, header length & type of service.
+    * The "Don't fragment" bit.
+    * The time-to-live field.
+    * The TCP header length.
+    * IP options, if any.
+    * TCP options, if any.
+    * If any of these things are different between the previous &
+    * current datagram, we send the current datagram `uncompressed'.
+    */
+   oth = &cs->cs_tcp;
+
+   if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
+    || ip->tos != cs->cs_ip.tos
+    || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
+    || ip->ttl != cs->cs_ip.ttl
+    || th->doff != cs->cs_tcp.doff
+    || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
+    || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
+       goto uncompressed;
+   }
+
+   /*
+    * Figure out which of the changing fields changed.  The
+    * receiver expects changes in the order: urgent, window,
+    * ack, seq (the order minimizes the number of temporaries
+    * needed in this section of code).
+    */
+   if(th->urg){
+       deltaS = ntohs(th->urg_ptr);
+       cp = encode(cp,deltaS);
+       changes |= NEW_U;
+   } else if(th->urg_ptr != oth->urg_ptr){
+       /* argh! URG not set but urp changed -- a sensible
+        * implementation should never do this but RFC793
+        * doesn't prohibit the change so we have to deal
+        * with it. */
+       goto uncompressed;
+   }
+   if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
+       cp = encode(cp,deltaS);
+       changes |= NEW_W;
+   }
+   if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
+       if(deltaA > 0x0000ffff)
+           goto uncompressed;
+       cp = encode(cp,deltaA);
+       changes |= NEW_A;
+   }
+   if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
+       if(deltaS > 0x0000ffff)
+           goto uncompressed;
+       cp = encode(cp,deltaS);
+       changes |= NEW_S;
+   }
+
+   switch(changes){
+   case 0: /* Nothing changed. If this packet contains data and the
+        * last one didn't, this is probably a data packet following
+        * an ack (normal on an interactive connection) and we send
+        * it compressed.  Otherwise it's probably a retransmit,
+        * retransmitted ack or window probe.  Send it uncompressed
+        * in case the other side missed the compressed version.
+        */
+       if(ip->tot_len != cs->cs_ip.tot_len &&
+          ntohs(cs->cs_ip.tot_len) == hlen)
+           break;
+       goto uncompressed;
+       break;
+   case SPECIAL_I:
+   case SPECIAL_D:
+       /* actual changes match one of our special case encodings --
+        * send packet uncompressed.
+        */
+       goto uncompressed;
+   case NEW_S|NEW_A:
+       if(deltaS == deltaA &&
+           deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
+           /* special case for echoed terminal traffic */
+           changes = SPECIAL_I;
+           cp = new_seq;
+       }
+       break;
+   case NEW_S:
+       if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
+           /* special case for data xfer */
+           changes = SPECIAL_D;
+           cp = new_seq;
+       }
+       break;
+   }
+   deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
+   if(deltaS != 1){
+       cp = encode(cp,deltaS);
+       changes |= NEW_I;
+   }
+   if(th->psh)
+       changes |= TCP_PUSH_BIT;
+   /* Grab the cksum before we overwrite it below.  Then update our
+    * state with this packet's header.
+    */
+   csum = th->check;
+   memcpy(&cs->cs_ip,ip,20);
+   memcpy(&cs->cs_tcp,th,20);
+   /* We want to use the original packet as our compressed packet.
+    * (cp - new_seq) is the number of bytes we need for compressed
+    * sequence numbers.  In addition we need one byte for the change
+    * mask, one for the connection id and two for the tcp checksum.
+    * So, (cp - new_seq) + 4 bytes of header are needed.
+    */
+   deltaS = cp - new_seq;
+   if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
+       cp = ocp;
+       *cpp = ocp;
+       *cp++ = changes | NEW_C;
+       *cp++ = cs->cs_this;
+       comp->xmit_current = cs->cs_this;
+   } else {
+       cp = ocp;
+       *cpp = ocp;
+       *cp++ = changes;
+   }
+   *(__sum16 *)cp = csum;
+   cp += 2;
+/* deltaS is now the size of the change section of the compressed header */
+   memcpy(cp,new_seq,deltaS);  /* Write list of deltas */
+   memcpy(cp+deltaS,icp+hlen,isize-hlen);
+   comp->sls_o_compressed++;
+   ocp[0] |= SL_TYPE_COMPRESSED_TCP;
+   return isize - hlen + deltaS + (cp - ocp);
+
+   /* Update connection state cs & send uncompressed packet (i.e.,
+    * a regular ip/tcp packet but with the 'conversation id' we hope
+    * to use on future compressed packets in the protocol field).
+    */
+uncompressed:
+   memcpy(&cs->cs_ip,ip,20);
+   memcpy(&cs->cs_tcp,th,20);
+   if (ip->ihl > 5)
+     memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
+   if (th->doff > 5)
+     memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
+   comp->xmit_current = cs->cs_this;
+   comp->sls_o_uncompressed++;
+   memcpy(ocp, icp, isize);
+   *cpp = ocp;
+   ocp[9] = cs->cs_this;
+   ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
+   return isize;
+}
+
+
+int
+slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
+{
+   register int changes;
+   long x;
+   register struct tcphdr *thp;
+   register struct iphdr *ip;
+   register struct cstate *cs;
+   int len, hdrlen;
+   unsigned char *cp = icp;
+
+   /* We've got a compressed packet; read the change byte */
+   comp->sls_i_compressed++;
+   if(isize < 3){
+       comp->sls_i_error++;
+       return 0;
+   }
+   changes = *cp++;
+   if(changes & NEW_C){
+       /* Make sure the state index is in range, then grab the state.
+        * If we have a good state index, clear the 'discard' flag.
+        */
+       x = *cp++;  /* Read conn index */
+       if(x < 0 || x > comp->rslot_limit)
+           goto bad;
+
+       comp->flags &=~ SLF_TOSS;
+       comp->recv_current = x;
+   } else {
+       /* this packet has an implicit state index.  If we've
+        * had a line error since the last time we got an
+        * explicit state index, we have to toss the packet. */
+       if(comp->flags & SLF_TOSS){
+           comp->sls_i_tossed++;
+           return 0;
+       }
+   }
+   cs = &comp->rstate[comp->recv_current];
+   thp = &cs->cs_tcp;
+   ip = &cs->cs_ip;
+
+   thp->check = *(__sum16 *)cp;
+   cp += 2;
+
+   thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
+/*
+ * we can use the same number for the length of the saved header and
+ * the current one, because the packet wouldn't have been sent
+ * as compressed unless the options were the same as the previous one
+ */
+
+   hdrlen = ip->ihl * 4 + thp->doff * 4;
+
+   switch(changes & SPECIALS_MASK){
+   case SPECIAL_I:     /* Echoed terminal traffic */
+       {
+       register short i;
+       i = ntohs(ip->tot_len) - hdrlen;
+       thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
+       thp->seq = htonl( ntohl(thp->seq) + i);
+       }
+       break;
+
+   case SPECIAL_D:         /* Unidirectional data */
+       thp->seq = htonl( ntohl(thp->seq) +
+                 ntohs(ip->tot_len) - hdrlen);
+       break;
+
+   default:
+       if(changes & NEW_U){
+           thp->urg = 1;
+           if((x = decode(&cp)) == -1) {
+               goto bad;
+           }
+           thp->urg_ptr = htons(x);
+       } else
+           thp->urg = 0;
+       if(changes & NEW_W){
+           if((x = decode(&cp)) == -1) {
+               goto bad;
+           }
+           thp->window = htons( ntohs(thp->window) + x);
+       }
+       if(changes & NEW_A){
+           if((x = decode(&cp)) == -1) {
+               goto bad;
+           }
+           thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
+       }
+       if(changes & NEW_S){
+           if((x = decode(&cp)) == -1) {
+               goto bad;
+           }
+           thp->seq = htonl( ntohl(thp->seq) + x);
+       }
+       break;
+   }
+   if(changes & NEW_I){
+       if((x = decode(&cp)) == -1) {
+           goto bad;
+       }
+       ip->id = htons (ntohs (ip->id) + x);
+   } else
+       ip->id = htons (ntohs (ip->id) + 1);
+
+   /*
+    * At this point, cp points to the first byte of data in the
+    * packet.  Put the reconstructed TCP and IP headers back on the
+    * packet.  Recalculate IP checksum (but not TCP checksum).
+    */
+
+   len = isize - (cp - icp);
+   if (len < 0)
+       goto bad;
+   len += hdrlen;
+   ip->tot_len = htons(len);
+   ip->check = 0;
+
+   memmove(icp + hdrlen, cp, len - hdrlen);
+
+   cp = icp;
+   memcpy(cp, ip, 20);
+   cp += 20;
+
+   if (ip->ihl > 5) {
+     memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
+     cp += (ip->ihl - 5) * 4;
+   }
+
+   put_unaligned(ip_fast_csum(icp, ip->ihl),
+             &((struct iphdr *)icp)->check);
+
+   memcpy(cp, thp, 20);
+   cp += 20;
+
+   if (thp->doff > 5) {
+     memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
+     cp += ((thp->doff) - 5) * 4;
+   }
+
+   return len;
+bad:
+   comp->sls_i_error++;
+   return slhc_toss( comp );
+}
+
+
+int
+slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
+{
+   register struct cstate *cs;
+   unsigned ihl;
+
+   unsigned char index;
+
+   if(isize < 20) {
+       /* The packet is shorter than a legal IP header */
+       comp->sls_i_runt++;
+       return slhc_toss( comp );
+   }
+   /* Peek at the IP header's IHL field to find its length */
+   ihl = icp[0] & 0xf;
+   if(ihl < 20 / 4){
+       /* The IP header length field is too small */
+       comp->sls_i_runt++;
+       return slhc_toss( comp );
+   }
+   index = icp[9];
+   icp[9] = IPPROTO_TCP;
+
+   if (ip_fast_csum(icp, ihl)) {
+       /* Bad IP header checksum; discard */
+       comp->sls_i_badcheck++;
+       return slhc_toss( comp );
+   }
+   if(index > comp->rslot_limit) {
+       comp->sls_i_error++;
+       return slhc_toss(comp);
+   }
+
+   /* Update local state */
+   cs = &comp->rstate[comp->recv_current = index];
+   comp->flags &=~ SLF_TOSS;
+   memcpy(&cs->cs_ip,icp,20);
+   memcpy(&cs->cs_tcp,icp + ihl*4,20);
+   if (ihl > 5)
+     memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
+   if (cs->cs_tcp.doff > 5)
+     memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
+   cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
+   /* Put headers back on packet
+    * Neither header checksum is recalculated
+    */
+   comp->sls_i_uncompressed++;
+   return isize;
+}
+
+int
+slhc_toss(struct slcompress *comp)
+{
+   if ( comp == NULLSLCOMPR )
+       return 0;
+
+   comp->flags |= SLF_TOSS;
+   return 0;
+}
+
+#else /* CONFIG_INET */
+
+int
+slhc_toss(struct slcompress *comp)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
+  return -EINVAL;
+}
+int
+slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
+  return -EINVAL;
+}
+int
+slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
+   unsigned char *ocp, unsigned char **cpp, int compress_cid)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
+  return -EINVAL;
+}
+
+int
+slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
+  return -EINVAL;
+}
+
+void
+slhc_free(struct slcompress *comp)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
+}
+struct slcompress *
+slhc_init(int rslots, int tslots)
+{
+  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
+  return NULL;
+}
+
+#endif /* CONFIG_INET */
+
+/* VJ header compression */
+EXPORT_SYMBOL(slhc_init);
+EXPORT_SYMBOL(slhc_free);
+EXPORT_SYMBOL(slhc_remember);
+EXPORT_SYMBOL(slhc_compress);
+EXPORT_SYMBOL(slhc_uncompress);
+EXPORT_SYMBOL(slhc_toss);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
new file mode 100644
index 0000000..ba08341
--- /dev/null
+++ b/drivers/net/slip/slip.c
@@ -0,0 +1,1444 @@
+/*
+ * slip.c  This module implements the SLIP protocol for kernel-based
+ *     devices like TTY.  It interfaces between a raw TTY, and the
+ *     kernel's INET protocol layers.
+ *
+ * Version:    @(#)slip.c  0.8.3   12/24/94
+ *
+ * Authors:    Laurence Culhane, <loz@holmes.demon.co.uk>
+ *     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * Fixes:
+ *     Alan Cox    :   Sanity checks and avoid tx overruns.
+ *                 Has a new sl->mtu field.
+ *     Alan Cox    :   Found cause of overrun. ifconfig sl0
+ *                 mtu upwards. Driver now spots this
+ *                 and grows/shrinks its buffers(hack!).
+ *                 Memory leak if you run out of memory
+ *                 setting up a slip driver fixed.
+ *     Matt Dillon :   Printable slip (borrowed from NET2E)
+ * Pauline Middelink   :   Slip driver fixes.
+ *     Alan Cox    :   Honours the old SL_COMPRESSED flag
+ *     Alan Cox    :   KISS AX.25 and AXUI IP support
+ *     Michael Riepe   :   Automatic CSLIP recognition added
+ *     Charles Hedrick :   CSLIP header length problem fix.
+ *     Alan Cox    :   Corrected non-IP cases of the above.
+ *     Alan Cox    :   Now uses hardware type as per FvK.
+ *     Alan Cox    :   Default to 192.168.0.0 (RFC 1597)
+ *     A.N.Kuznetsov   :   dev_tint() recursion fix.
+ * Dmitry Gorodchanin  :   SLIP memory leaks
+ *      Dmitry Gorodchanin      :       Code cleanup. Reduce tty driver
+ *                                      buffering from 4096 to 256 bytes.
+ *                                      Improving SLIP response time.
+ *                                      CONFIG_SLIP_MODE_SLIP6.
+ *                                      ifconfig sl? up & down now works
+ *                 correctly.
+ *                 Modularization.
+ *              Alan Cox        :       Oops - fix AX.25 buffer lengths
+ *      Dmitry Gorodchanin      :       Even more cleanups. Preserve CSLIP
+ *                                      statistics. Include CSLIP code only
+ *                                      if it really needed.
+ *     Alan Cox    :   Free slhc buffers in the right place.
+ *     Alan Cox    :   Allow for digipeated IP over AX.25
+ *     Matti Aarnio    :   Dynamic SLIP devices, with ideas taken
+ *                 from Jim Freeman's <jfree@caldera.com>
+ *                 dynamic PPP devices.  We do NOT kfree()
+ *                 device entries, just reg./unreg. them
+ *                 as they are needed.  We kfree() them
+ *                 at module cleanup.
+ *                 With MODULE-loading ``insmod'', user
+ *                 can issue parameter:  slip_maxdev=1024
+ *                 (Or how much he/she wants.. Default
+ *                 is 256)
+ * Stanislav Voronyi   :   Slip line checking, with ideas taken
+ *                 from multislip BSDI driver which was
+ *                 written by Igor Chechik, RELCOM Corp.
+ *                 Only algorithms have been ported to
+ *                 Linux SLIP driver.
+ * Vitaly E. Lavrov    :   Sane behaviour on tty hangup.
+ * Alexey Kuznetsov    :   Cleanup interfaces to tty & netdevice
+ *                 modules.
+ */
+
+#define SL_CHECK_TRANSMIT
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/if_slip.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include "slip.h"
+#ifdef CONFIG_INET
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/slhc_vj.h>
+#endif
+
+#define SLIP_VERSION   "0.8.4-NET3.019-NEWTTY"
+
+static struct net_device **slip_devs;
+
+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);
+static void slip_unesc(struct slip *sl, unsigned char c);
+#ifdef CONFIG_SLIP_MODE_SLIP6
+static int slip_esc6(unsigned char *p, unsigned char *d, int len);
+static void slip_unesc6(struct slip *sl, unsigned char c);
+#endif
+#ifdef CONFIG_SLIP_SMART
+static void sl_keepalive(unsigned long sls);
+static void sl_outfill(unsigned long sls);
+static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif
+
+/********************************
+*  Buffer administration routines:
+*  sl_alloc_bufs()
+*  sl_free_bufs()
+*  sl_realloc_bufs()
+*
+* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because
+*  sl_realloc_bufs provides strong atomicity and reallocation
+*  on actively running device.
+*********************************/
+
+/*
+   Allocate channel buffers.
+ */
+
+static int sl_alloc_bufs(struct slip *sl, int mtu)
+{
+   int err = -ENOBUFS;
+   unsigned long len;
+   char *rbuff = NULL;
+   char *xbuff = NULL;
+#ifdef SL_INCLUDE_CSLIP
+   char *cbuff = NULL;
+   struct slcompress *slcomp = NULL;
+#endif
+
+   /*
+    * Allocate the SLIP frame buffers:
+    *
+    * rbuff    Receive buffer.
+    * xbuff    Transmit buffer.
+    * cbuff        Temporary compression buffer.
+    */
+   len = mtu * 2;
+
+   /*
+    * allow for arrival of larger UDP packets, even if we say not to
+    * also fixes a bug in which SunOS sends 512-byte packets even with
+    * an MSS of 128
+    */
+   if (len < 576 * 2)
+       len = 576 * 2;
+   rbuff = kmalloc(len + 4, GFP_KERNEL);
+   if (rbuff == NULL)
+       goto err_exit;
+   xbuff = kmalloc(len + 4, GFP_KERNEL);
+   if (xbuff == NULL)
+       goto err_exit;
+#ifdef SL_INCLUDE_CSLIP
+   cbuff = kmalloc(len + 4, GFP_KERNEL);
+   if (cbuff == NULL)
+       goto err_exit;
+   slcomp = slhc_init(16, 16);
+   if (slcomp == NULL)
+       goto err_exit;
+#endif
+   spin_lock_bh(&sl->lock);
+   if (sl->tty == NULL) {
+       spin_unlock_bh(&sl->lock);
+       err = -ENODEV;
+       goto err_exit;
+   }
+   sl->mtu      = mtu;
+   sl->buffsize = len;
+   sl->rcount   = 0;
+   sl->xleft    = 0;
+   rbuff = xchg(&sl->rbuff, rbuff);
+   xbuff = xchg(&sl->xbuff, xbuff);
+#ifdef SL_INCLUDE_CSLIP
+   cbuff = xchg(&sl->cbuff, cbuff);
+   slcomp = xchg(&sl->slcomp, slcomp);
+#endif
+#ifdef CONFIG_SLIP_MODE_SLIP6
+   sl->xdata    = 0;
+   sl->xbits    = 0;
+#endif
+   spin_unlock_bh(&sl->lock);
+   err = 0;
+
+   /* Cleanup */
+err_exit:
+#ifdef SL_INCLUDE_CSLIP
+   kfree(cbuff);
+   slhc_free(slcomp);
+#endif
+   kfree(xbuff);
+   kfree(rbuff);
+   return err;
+}
+
+/* Free a SLIP channel buffers. */
+static void sl_free_bufs(struct slip *sl)
+{
+   /* Free all SLIP frame buffers. */
+   kfree(xchg(&sl->rbuff, NULL));
+   kfree(xchg(&sl->xbuff, NULL));
+#ifdef SL_INCLUDE_CSLIP
+   kfree(xchg(&sl->cbuff, NULL));
+   slhc_free(xchg(&sl->slcomp, NULL));
+#endif
+}
+
+/*
+   Reallocate slip channel buffers.
+ */
+
+static int sl_realloc_bufs(struct slip *sl, int mtu)
+{
+   int err = 0;
+   struct net_device *dev = sl->dev;
+   unsigned char *xbuff, *rbuff;
+#ifdef SL_INCLUDE_CSLIP
+   unsigned char *cbuff;
+#endif
+   int len = mtu * 2;
+
+/*
+ * allow for arrival of larger UDP packets, even if we say not to
+ * also fixes a bug in which SunOS sends 512-byte packets even with
+ * an MSS of 128
+ */
+   if (len < 576 * 2)
+       len = 576 * 2;
+
+   xbuff = kmalloc(len + 4, GFP_ATOMIC);
+   rbuff = kmalloc(len + 4, GFP_ATOMIC);
+#ifdef SL_INCLUDE_CSLIP
+   cbuff = kmalloc(len + 4, GFP_ATOMIC);
+#endif
+
+
+#ifdef SL_INCLUDE_CSLIP
+   if (xbuff == NULL || rbuff == NULL || cbuff == NULL)  {
+#else
+   if (xbuff == NULL || rbuff == NULL)  {
+#endif
+       if (mtu > sl->mtu) {
+           printk(KERN_WARNING "%s: unable to grow slip buffers, MTU change cancelled.n",
+                  dev->name);
+           err = -ENOBUFS;
+       }
+       goto done;
+   }
+   spin_lock_bh(&sl->lock);
+
+   err = -ENODEV;
+   if (sl->tty == NULL)
+       goto done_on_bh;
+
+   xbuff    = xchg(&sl->xbuff, xbuff);
+   rbuff    = xchg(&sl->rbuff, rbuff);
+#ifdef SL_INCLUDE_CSLIP
+   cbuff    = xchg(&sl->cbuff, cbuff);
+#endif
+   if (sl->xleft)  {
+       if (sl->xleft <= len)  {
+           memcpy(sl->xbuff, sl->xhead, sl->xleft);
+       } else  {
+           sl->xleft = 0;
+           dev->stats.tx_dropped++;
+       }
+   }
+   sl->xhead = sl->xbuff;
+
+   if (sl->rcount)  {
+       if (sl->rcount <= len) {
+           memcpy(sl->rbuff, rbuff, sl->rcount);
+       } else  {
+           sl->rcount = 0;
+           dev->stats.rx_over_errors++;
+           set_bit(SLF_ERROR, &sl->flags);
+       }
+   }
+   sl->mtu      = mtu;
+   dev->mtu      = mtu;
+   sl->buffsize = len;
+   err = 0;
+
+done_on_bh:
+   spin_unlock_bh(&sl->lock);
+
+done:
+   kfree(xbuff);
+   kfree(rbuff);
+#ifdef SL_INCLUDE_CSLIP
+   kfree(cbuff);
+#endif
+   return err;
+}
+
+
+/* Set the "sending" flag.  This must be atomic hence the set_bit. */
+static inline void sl_lock(struct slip *sl)
+{
+   netif_stop_queue(sl->dev);
+}
+
+
+/* Clear the "sending" flag.  This must be atomic, hence the ASM. */
+static inline void sl_unlock(struct slip *sl)
+{
+   netif_wake_queue(sl->dev);
+}
+
+/* Send one completely decapsulated IP datagram to the IP layer. */
+static void sl_bump(struct slip *sl)
+{
+   struct net_device *dev = sl->dev;
+   struct sk_buff *skb;
+   int count;
+
+   count = sl->rcount;
+#ifdef SL_INCLUDE_CSLIP
+   if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
+       unsigned char c = sl->rbuff[0];
+       if (c & SL_TYPE_COMPRESSED_TCP) {
+           /* ignore compressed packets when CSLIP is off */
+           if (!(sl->mode & SL_MODE_CSLIP)) {
+               printk(KERN_WARNING "%s: compressed packet ignoredn", dev->name);
+               return;
+           }
+           /* make sure we've reserved enough space for uncompress
+              to use */
+           if (count + 80 > sl->buffsize) {
+               dev->stats.rx_over_errors++;
+               return;
+           }
+           count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
+           if (count <= 0)
+               return;
+       } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
+           if (!(sl->mode & SL_MODE_CSLIP)) {
+               /* turn on header compression */
+               sl->mode |= SL_MODE_CSLIP;
+               sl->mode &= ~SL_MODE_ADAPTIVE;
+               printk(KERN_INFO "%s: header compression turned onn", dev->name);
+           }
+           sl->rbuff[0] &= 0x4f;
+           if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0)
+               return;
+       }
+   }
+#endif  /* SL_INCLUDE_CSLIP */
+
+   dev->stats.rx_bytes += count;
+
+   skb = dev_alloc_skb(count);
+   if (skb == NULL) {
+       printk(KERN_WARNING "%s: memory squeeze, dropping packet.n", dev->name);
+       dev->stats.rx_dropped++;
+       return;
+   }
+   skb->dev = dev;
+   memcpy(skb_put(skb, count), sl->rbuff, count);
+   skb_reset_mac_header(skb);
+   skb->protocol = htons(ETH_P_IP);
+   netif_rx_ni(skb);
+   dev->stats.rx_packets++;
+}
+
+/* Encapsulate one IP datagram and stuff into a TTY queue. */
+static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
+{
+   unsigned char *p;
+   int actual, count;
+
+   if (len > sl->mtu) {        /* Sigh, shouldn't occur BUT ... */
+       printk(KERN_WARNING "%s: truncating oversized transmit packet!n", sl->dev->name);
+       sl->dev->stats.tx_dropped++;
+       sl_unlock(sl);
+       return;
+   }
+
+   p = icp;
+#ifdef SL_INCLUDE_CSLIP
+   if (sl->mode & SL_MODE_CSLIP)
+       len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
+#endif
+#ifdef CONFIG_SLIP_MODE_SLIP6
+   if (sl->mode & SL_MODE_SLIP6)
+       count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
+   else
+#endif
+       count = slip_esc(p, (unsigned char *) sl->xbuff, len);
+
+   /* Order of next two lines is *very* important.
+    * When we are sending a little amount of data,
+    * the transfer may be completed inside the ops->write()
+    * routine, because it's running with interrupts enabled.
+    * In this case we *never* got WRITE_WAKEUP event,
+    * if we did not request it before write operation.
+    *       14 Oct 1994  Dmitry Gorodchanin.
+    */
+   set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+   actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
+#ifdef SL_CHECK_TRANSMIT
+   sl->dev->trans_start = jiffies;
+#endif
+   sl->xleft = count - actual;
+   sl->xhead = sl->xbuff + actual;
+#ifdef CONFIG_SLIP_SMART
+   /* VSV */
+   clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
+#endif
+}
+
+/*
+ * Called by the driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+static void slip_write_wakeup(struct tty_struct *tty)
+{
+   int actual;
+   struct slip *sl = tty->disc_data;
+
+   /* First make sure we're connected. */
+   if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
+       return;
+
+   if (sl->xleft <= 0)  {
+       /* Now serial buffer is almost free & we can start
+        * transmission of another packet */
+       sl->dev->stats.tx_packets++;
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       sl_unlock(sl);
+       return;
+   }
+
+   actual = tty->ops->write(tty, sl->xhead, sl->xleft);
+   sl->xleft -= actual;
+   sl->xhead += actual;
+}
+
+static void sl_tx_timeout(struct net_device *dev)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   spin_lock(&sl->lock);
+
+   if (netif_queue_stopped(dev)) {
+       if (!netif_running(dev))
+           goto out;
+
+       /* May be we must check transmitter timeout here ?
+        *      14 Oct 1994 Dmitry Gorodchanin.
+        */
+#ifdef SL_CHECK_TRANSMIT
+       if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ))  {
+           /* 20 sec timeout not reached */
+           goto out;
+       }
+       printk(KERN_WARNING "%s: transmit timed out, %s?n",
+           dev->name,
+           (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
+               "bad line quality" : "driver error");
+       sl->xleft = 0;
+       clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+       sl_unlock(sl);
+#endif
+   }
+out:
+   spin_unlock(&sl->lock);
+}
+
+
+/* Encapsulate an IP datagram and kick it into a TTY queue. */
+static netdev_tx_t
+sl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   spin_lock(&sl->lock);
+   if (!netif_running(dev)) {
+       spin_unlock(&sl->lock);
+       printk(KERN_WARNING "%s: xmit call when iface is downn", dev->name);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+   }
+   if (sl->tty == NULL) {
+       spin_unlock(&sl->lock);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+   }
+
+   sl_lock(sl);
+   dev->stats.tx_bytes += skb->len;
+   sl_encaps(sl, skb->data, skb->len);
+   spin_unlock(&sl->lock);
+
+   dev_kfree_skb(skb);
+   return NETDEV_TX_OK;
+}
+
+
+/******************************************
+ *   Routines looking at netdevice side.
+ ******************************************/
+
+/* Netdevice UP -> DOWN routine */
+
+static int
+sl_close(struct net_device *dev)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   spin_lock_bh(&sl->lock);
+   if (sl->tty)
+       /* TTY discipline is running. */
+       clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+   netif_stop_queue(dev);
+   sl->rcount   = 0;
+   sl->xleft    = 0;
+   spin_unlock_bh(&sl->lock);
+
+   return 0;
+}
+
+/* Netdevice DOWN -> UP routine */
+
+static int sl_open(struct net_device *dev)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   if (sl->tty == NULL)
+       return -ENODEV;
+
+   sl->flags &= (1 << SLF_INUSE);
+   netif_start_queue(dev);
+   return 0;
+}
+
+/* Netdevice change MTU request */
+
+static int sl_change_mtu(struct net_device *dev, int new_mtu)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   if (new_mtu < 68 || new_mtu > 65534)
+       return -EINVAL;
+
+   if (new_mtu != dev->mtu)
+       return sl_realloc_bufs(sl, new_mtu);
+   return 0;
+}
+
+/* Netdevice get statistics request */
+
+static struct rtnl_link_stats64 *
+sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+   struct net_device_stats *devstats = &dev->stats;
+#ifdef SL_INCLUDE_CSLIP
+   struct slip *sl = netdev_priv(dev);
+   struct slcompress *comp = sl->slcomp;
+#endif
+   stats->rx_packets     = devstats->rx_packets;
+   stats->tx_packets     = devstats->tx_packets;
+   stats->rx_bytes       = devstats->rx_bytes;
+   stats->tx_bytes       = devstats->tx_bytes;
+   stats->rx_dropped     = devstats->rx_dropped;
+   stats->tx_dropped     = devstats->tx_dropped;
+   stats->tx_errors      = devstats->tx_errors;
+   stats->rx_errors      = devstats->rx_errors;
+   stats->rx_over_errors = devstats->rx_over_errors;
+
+#ifdef SL_INCLUDE_CSLIP
+   if (comp) {
+       /* Generic compressed statistics */
+       stats->rx_compressed   = comp->sls_i_compressed;
+       stats->tx_compressed   = comp->sls_o_compressed;
+
+       /* Are we really still needs this? */
+       stats->rx_fifo_errors += comp->sls_i_compressed;
+       stats->rx_dropped     += comp->sls_i_tossed;
+       stats->tx_fifo_errors += comp->sls_o_compressed;
+       stats->collisions     += comp->sls_o_misses;
+   }
+#endif
+   return stats;
+}
+
+/* Netdevice register callback */
+
+static int sl_init(struct net_device *dev)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   /*
+    *  Finish setting up the DEVICE info.
+    */
+
+   dev->mtu        = sl->mtu;
+   dev->type       = ARPHRD_SLIP + sl->mode;
+#ifdef SL_CHECK_TRANSMIT
+   dev->watchdog_timeo = 20*HZ;
+#endif
+   return 0;
+}
+
+
+static void sl_uninit(struct net_device *dev)
+{
+   struct slip *sl = netdev_priv(dev);
+
+   sl_free_bufs(sl);
+}
+
+/* Hook the destructor so we can free slip devices at the right point in time */
+static void sl_free_netdev(struct net_device *dev)
+{
+   int i = dev->base_addr;
+   free_netdev(dev);
+   slip_devs[i] = NULL;
+}
+
+static const struct net_device_ops sl_netdev_ops = {
+   .ndo_init       = sl_init,
+   .ndo_uninit     = sl_uninit,
+   .ndo_open       = sl_open,
+   .ndo_stop       = sl_close,
+   .ndo_start_xmit     = sl_xmit,
+   .ndo_get_stats64        = sl_get_stats64,
+   .ndo_change_mtu     = sl_change_mtu,
+   .ndo_tx_timeout     = sl_tx_timeout,
+#ifdef CONFIG_SLIP_SMART
+   .ndo_do_ioctl       = sl_ioctl,
+#endif
+};
+
+
+static void sl_setup(struct net_device *dev)
+{
+   dev->netdev_ops     = &sl_netdev_ops;
+   dev->destructor     = sl_free_netdev;
+
+   dev->hard_header_len    = 0;
+   dev->addr_len       = 0;
+   dev->tx_queue_len   = 10;
+
+   /* New-style flags. */
+   dev->flags      = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
+}
+
+/******************************************
+  Routines looking at TTY side.
+ ******************************************/
+
+
+/*
+ * 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. 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 = tty->disc_data;
+
+   if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
+       return;
+
+   /* Read the characters out of the buffer */
+   while (count--) {
+       if (fp && *fp++) {
+           if (!test_and_set_bit(SLF_ERROR, &sl->flags))
+               sl->dev->stats.rx_errors++;
+           cp++;
+           continue;
+       }
+#ifdef CONFIG_SLIP_MODE_SLIP6
+       if (sl->mode & SL_MODE_SLIP6)
+           slip_unesc6(sl, *cp++);
+       else
+#endif
+           slip_unesc(sl, *cp++);
+   }
+}
+
+/************************************
+ *  slip_open helper routines.
+ ************************************/
+
+/* Collect hanged up channels */
+static void sl_sync(void)
+{
+   int i;
+   struct net_device *dev;
+   struct slip   *sl;
+
+   for (i = 0; i < slip_maxdev; i++) {
+       dev = slip_devs[i];
+       if (dev == NULL)
+           break;
+
+       sl = netdev_priv(dev);
+       if (sl->tty || sl->leased)
+           continue;
+       if (dev->flags & IFF_UP)
+           dev_close(dev);
+   }
+}
+
+
+/* Find a free SLIP channel, and link in this `tty' line. */
+static struct slip *sl_alloc(dev_t line)
+{
+   int i;
+   char name[IFNAMSIZ];
+   struct net_device *dev = NULL;
+   struct slip       *sl;
+
+   for (i = 0; i < slip_maxdev; i++) {
+       dev = slip_devs[i];
+       if (dev == NULL)
+           break;
+   }
+   /* Sorry, too many, all slots in use */
+   if (i >= slip_maxdev)
+       return NULL;
+
+   sprintf(name, "sl%d", i);
+   dev = alloc_netdev(sizeof(*sl), name, sl_setup);
+   if (!dev)
+       return NULL;
+
+   dev->base_addr  = i;
+   sl = netdev_priv(dev);
+
+   /* Initialize channel control data */
+   sl->magic       = SLIP_MAGIC;
+   sl->dev         = dev;
+   spin_lock_init(&sl->lock);
+   sl->mode        = SL_MODE_DEFAULT;
+#ifdef CONFIG_SLIP_SMART
+   /* initialize timer_list struct */
+   init_timer(&sl->keepalive_timer);
+   sl->keepalive_timer.data = (unsigned long)sl;
+   sl->keepalive_timer.function = sl_keepalive;
+   init_timer(&sl->outfill_timer);
+   sl->outfill_timer.data = (unsigned long)sl;
+   sl->outfill_timer.function = sl_outfill;
+#endif
+   slip_devs[i] = dev;
+   return sl;
+}
+
+/*
+ * Open the high-level part of the SLIP channel.
+ * This function is called by the TTY module when the
+ * 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)
+{
+   struct slip *sl;
+   int err;
+
+   if (!capable(CAP_NET_ADMIN))
+       return -EPERM;
+
+   if (tty->ops->write == NULL)
+       return -EOPNOTSUPP;
+
+   /* RTnetlink lock is misused here to serialize concurrent
+      opens of slip channels. There are better ways, but it is
+      the simplest one.
+    */
+   rtnl_lock();
+
+   /* Collect hanged up channels. */
+   sl_sync();
+
+   sl = tty->disc_data;
+
+   err = -EEXIST;
+   /* First make sure we're not already connected. */
+   if (sl && sl->magic == SLIP_MAGIC)
+       goto err_exit;
+
+   /* OK.  Find a free SLIP channel to use. */
+   err = -ENFILE;
+   sl = sl_alloc(tty_devnum(tty));
+   if (sl == NULL)
+       goto err_exit;
+
+   sl->tty = tty;
+   tty->disc_data = sl;
+   sl->pid = current->pid;
+
+   if (!test_bit(SLF_INUSE, &sl->flags)) {
+       /* Perform the low-level SLIP initialization. */
+       err = sl_alloc_bufs(sl, SL_MTU);
+       if (err)
+           goto err_free_chan;
+
+       set_bit(SLF_INUSE, &sl->flags);
+
+       err = register_netdevice(sl->dev);
+       if (err)
+           goto err_free_bufs;
+   }
+
+#ifdef CONFIG_SLIP_SMART
+   if (sl->keepalive) {
+       sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ;
+       add_timer(&sl->keepalive_timer);
+   }
+   if (sl->outfill) {
+       sl->outfill_timer.expires = jiffies + sl->outfill * HZ;
+       add_timer(&sl->outfill_timer);
+   }
+#endif
+
+   /* Done.  We have linked the TTY line to a channel. */
+   rtnl_unlock();
+   tty->receive_room = 65536;  /* We don't flow control */
+
+   /* TTY layer expects 0 on success */
+   return 0;
+
+err_free_bufs:
+   sl_free_bufs(sl);
+
+err_free_chan:
+   sl->tty = NULL;
+   tty->disc_data = NULL;
+   clear_bit(SLF_INUSE, &sl->flags);
+
+err_exit:
+   rtnl_unlock();
+
+   /* Count references from TTY module */
+   return err;
+}
+
+/*
+ * Close down a SLIP channel.
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
+ *
+ * We also use this method fo a hangup event
+ */
+
+static void slip_close(struct tty_struct *tty)
+{
+   struct slip *sl = tty->disc_data;
+
+   /* First make sure we're connected. */
+   if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)
+       return;
+
+   tty->disc_data = NULL;
+   sl->tty = NULL;
+
+   /* VSV = very important to remove timers */
+#ifdef CONFIG_SLIP_SMART
+   del_timer_sync(&sl->keepalive_timer);
+   del_timer_sync(&sl->outfill_timer);
+#endif
+   /* Flush network side */
+   unregister_netdev(sl->dev);
+   /* This will complete via sl_free_netdev */
+}
+
+static int slip_hangup(struct tty_struct *tty)
+{
+   slip_close(tty);
+   return 0;
+}
+ /************************************************************************
+  *            STANDARD SLIP ENCAPSULATION          *
+  ************************************************************************/
+
+static int slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+   unsigned char *ptr = d;
+   unsigned char c;
+
+   /*
+    * Send an initial END character to flush out any
+    * data that may have accumulated in the receiver
+    * due to line noise.
+    */
+
+   *ptr++ = END;
+
+   /*
+    * For each byte in the packet, send the appropriate
+    * character sequence, according to the SLIP protocol.
+    */
+
+   while (len-- > 0) {
+       switch (c = *s++) {
+       case END:
+           *ptr++ = ESC;
+           *ptr++ = ESC_END;
+           break;
+       case ESC:
+           *ptr++ = ESC;
+           *ptr++ = ESC_ESC;
+           break;
+       default:
+           *ptr++ = c;
+           break;
+       }
+   }
+   *ptr++ = END;
+   return ptr - d;
+}
+
+static void slip_unesc(struct slip *sl, unsigned char s)
+{
+
+   switch (s) {
+   case END:
+#ifdef CONFIG_SLIP_SMART
+       /* drop keeptest bit = VSV */
+       if (test_bit(SLF_KEEPTEST, &sl->flags))
+           clear_bit(SLF_KEEPTEST, &sl->flags);
+#endif
+
+       if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
+           (sl->rcount > 2))
+           sl_bump(sl);
+       clear_bit(SLF_ESCAPE, &sl->flags);
+       sl->rcount = 0;
+       return;
+
+   case ESC:
+       set_bit(SLF_ESCAPE, &sl->flags);
+       return;
+   case ESC_ESC:
+       if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
+           s = ESC;
+       break;
+   case ESC_END:
+       if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
+           s = END;
+       break;
+   }
+   if (!test_bit(SLF_ERROR, &sl->flags))  {
+       if (sl->rcount < sl->buffsize)  {
+           sl->rbuff[sl->rcount++] = s;
+           return;
+       }
+       sl->dev->stats.rx_over_errors++;
+       set_bit(SLF_ERROR, &sl->flags);
+   }
+}
+
+
+#ifdef CONFIG_SLIP_MODE_SLIP6
+/************************************************************************
+ *          6 BIT SLIP ENCAPSULATION           *
+ ************************************************************************/
+
+static int slip_esc6(unsigned char *s, unsigned char *d, int len)
+{
+   unsigned char *ptr = d;
+   unsigned char c;
+   int i;
+   unsigned short v = 0;
+   short bits = 0;
+
+   /*
+    * Send an initial END character to flush out any
+    * data that may have accumulated in the receiver
+    * due to line noise.
+    */
+
+   *ptr++ = 0x70;
+
+   /*
+    * Encode the packet into printable ascii characters
+    */
+
+   for (i = 0; i < len; ++i) {
+       v = (v << 8) | s[i];
+       bits += 8;
+       while (bits >= 6) {
+           bits -= 6;
+           c = 0x30 + ((v >> bits) & 0x3F);
+           *ptr++ = c;
+       }
+   }
+   if (bits) {
+       c = 0x30 + ((v << (6 - bits)) & 0x3F);
+       *ptr++ = c;
+   }
+   *ptr++ = 0x70;
+   return ptr - d;
+}
+
+static void slip_unesc6(struct slip *sl, unsigned char s)
+{
+   unsigned char c;
+
+   if (s == 0x70) {
+#ifdef CONFIG_SLIP_SMART
+       /* drop keeptest bit = VSV */
+       if (test_bit(SLF_KEEPTEST, &sl->flags))
+           clear_bit(SLF_KEEPTEST, &sl->flags);
+#endif
+
+       if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
+           (sl->rcount > 2))
+           sl_bump(sl);
+       sl->rcount = 0;
+       sl->xbits = 0;
+       sl->xdata = 0;
+   } else if (s >= 0x30 && s < 0x70) {
+       sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
+       sl->xbits += 6;
+       if (sl->xbits >= 8) {
+           sl->xbits -= 8;
+           c = (unsigned char)(sl->xdata >> sl->xbits);
+           if (!test_bit(SLF_ERROR, &sl->flags))  {
+               if (sl->rcount < sl->buffsize)  {
+                   sl->rbuff[sl->rcount++] = c;
+                   return;
+               }
+               sl->dev->stats.rx_over_errors++;
+               set_bit(SLF_ERROR, &sl->flags);
+           }
+       }
+   }
+}
+#endif /* CONFIG_SLIP_MODE_SLIP6 */
+
+/* Perform I/O control on an active SLIP channel. */
+static int slip_ioctl(struct tty_struct *tty, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+   struct slip *sl = tty->disc_data;
+   unsigned int tmp;
+   int __user *p = (int __user *)arg;
+
+   /* First make sure we're connected. */
+   if (!sl || sl->magic != SLIP_MAGIC)
+       return -EINVAL;
+
+   switch (cmd) {
+   case SIOCGIFNAME:
+       tmp = strlen(sl->dev->name) + 1;
+       if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
+           return -EFAULT;
+       return 0;
+
+   case SIOCGIFENCAP:
+       if (put_user(sl->mode, p))
+           return -EFAULT;
+       return 0;
+
+   case SIOCSIFENCAP:
+       if (get_user(tmp, p))
+           return -EFAULT;
+#ifndef SL_INCLUDE_CSLIP
+       if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))
+           return -EINVAL;
+#else
+       if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
+           (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))
+           /* return -EINVAL; */
+           tmp &= ~SL_MODE_ADAPTIVE;
+#endif
+#ifndef CONFIG_SLIP_MODE_SLIP6
+       if (tmp & SL_MODE_SLIP6)
+           return -EINVAL;
+#endif
+       sl->mode = tmp;
+       sl->dev->type = ARPHRD_SLIP + sl->mode;
+       return 0;
+
+   case SIOCSIFHWADDR:
+       return -EINVAL;
+
+#ifdef CONFIG_SLIP_SMART
+   /* VSV changes start here */
+   case SIOCSKEEPALIVE:
+       if (get_user(tmp, p))
+           return -EFAULT;
+       if (tmp > 255) /* max for unchar */
+           return -EINVAL;
+
+       spin_lock_bh(&sl->lock);
+       if (!sl->tty) {
+           spin_unlock_bh(&sl->lock);
+           return -ENODEV;
+       }
+       sl->keepalive = (u8)tmp;
+       if (sl->keepalive != 0) {
+           mod_timer(&sl->keepalive_timer,
+                   jiffies + sl->keepalive * HZ);
+           set_bit(SLF_KEEPTEST, &sl->flags);
+       } else
+           del_timer(&sl->keepalive_timer);
+       spin_unlock_bh(&sl->lock);
+       return 0;
+
+   case SIOCGKEEPALIVE:
+       if (put_user(sl->keepalive, p))
+           return -EFAULT;
+       return 0;
+
+   case SIOCSOUTFILL:
+       if (get_user(tmp, p))
+           return -EFAULT;
+       if (tmp > 255) /* max for unchar */
+           return -EINVAL;
+       spin_lock_bh(&sl->lock);
+       if (!sl->tty) {
+           spin_unlock_bh(&sl->lock);
+           return -ENODEV;
+       }
+       sl->outfill = (u8)tmp;
+       if (sl->outfill != 0) {
+           mod_timer(&sl->outfill_timer,
+                       jiffies + sl->outfill * HZ);
+           set_bit(SLF_OUTWAIT, &sl->flags);
+       } else
+           del_timer(&sl->outfill_timer);
+       spin_unlock_bh(&sl->lock);
+       return 0;
+
+   case SIOCGOUTFILL:
+       if (put_user(sl->outfill, p))
+           return -EFAULT;
+       return 0;
+   /* VSV changes end */
+#endif
+   default:
+       return tty_mode_ioctl(tty, file, cmd, arg);
+   }
+}
+
+#ifdef CONFIG_COMPAT
+static long slip_compat_ioctl(struct tty_struct *tty, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+   switch (cmd) {
+   case SIOCGIFNAME:
+   case SIOCGIFENCAP:
+   case SIOCSIFENCAP:
+   case SIOCSIFHWADDR:
+   case SIOCSKEEPALIVE:
+   case SIOCGKEEPALIVE:
+   case SIOCSOUTFILL:
+   case SIOCGOUTFILL:
+       return slip_ioctl(tty, file, cmd,
+                 (unsigned long)compat_ptr(arg));
+   }
+
+   return -ENOIOCTLCMD;
+}
+#endif
+
+/* VSV changes start here */
+#ifdef CONFIG_SLIP_SMART
+/* function do_ioctl called from net/core/dev.c
+   to allow get/set outfill/keepalive parameter
+   by ifconfig                                 */
+
+static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+   struct slip *sl = netdev_priv(dev);
+   unsigned long *p = (unsigned long *)&rq->ifr_ifru;
+
+   if (sl == NULL)     /* Allocation failed ?? */
+       return -ENODEV;
+
+   spin_lock_bh(&sl->lock);
+
+   if (!sl->tty) {
+       spin_unlock_bh(&sl->lock);
+       return -ENODEV;
+   }
+
+   switch (cmd) {
+   case SIOCSKEEPALIVE:
+       /* max for unchar */
+       if ((unsigned)*p > 255) {
+           spin_unlock_bh(&sl->lock);
+           return -EINVAL;
+       }
+       sl->keepalive = (u8)*p;
+       if (sl->keepalive != 0) {
+           sl->keepalive_timer.expires =
+                       jiffies + sl->keepalive * HZ;
+           mod_timer(&sl->keepalive_timer,
+                       jiffies + sl->keepalive * HZ);
+           set_bit(SLF_KEEPTEST, &sl->flags);
+       } else
+           del_timer(&sl->keepalive_timer);
+       break;
+
+   case SIOCGKEEPALIVE:
+       *p = sl->keepalive;
+       break;
+
+   case SIOCSOUTFILL:
+       if ((unsigned)*p > 255) { /* max for unchar */
+           spin_unlock_bh(&sl->lock);
+           return -EINVAL;
+       }
+       sl->outfill = (u8)*p;
+       if (sl->outfill != 0) {
+           mod_timer(&sl->outfill_timer,
+                       jiffies + sl->outfill * HZ);
+           set_bit(SLF_OUTWAIT, &sl->flags);
+       } else
+           del_timer(&sl->outfill_timer);
+       break;
+
+   case SIOCGOUTFILL:
+       *p = sl->outfill;
+       break;
+
+   case SIOCSLEASE:
+       /* Resolve race condition, when ioctl'ing hanged up
+          and opened by another process device.
+        */
+       if (sl->tty != current->signal->tty &&
+                       sl->pid != current->pid) {
+           spin_unlock_bh(&sl->lock);
+           return -EPERM;
+       }
+       sl->leased = 0;
+       if (*p)
+           sl->leased = 1;
+       break;
+
+   case SIOCGLEASE:
+       *p = sl->leased;
+   }
+   spin_unlock_bh(&sl->lock);
+   return 0;
+}
+#endif
+/* VSV changes end */
+
+static struct tty_ldisc_ops sl_ldisc = {
+   .owner      = THIS_MODULE,
+   .magic      = TTY_LDISC_MAGIC,
+   .name       = "slip",
+   .open       = slip_open,
+   .close      = slip_close,
+   .hangup     = slip_hangup,
+   .ioctl      = slip_ioctl,
+#ifdef CONFIG_COMPAT
+   .compat_ioctl   = slip_compat_ioctl,
+#endif
+   .receive_buf    = slip_receive_buf,
+   .write_wakeup   = slip_write_wakeup,
+};
+
+static int __init slip_init(void)
+{
+   int status;
+
+   if (slip_maxdev < 4)
+       slip_maxdev = 4; /* Sanity */
+
+   printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"
+#ifdef CONFIG_SLIP_MODE_SLIP6
+          " (6 bit encapsulation enabled)"
+#endif
+          ".n",
+          SLIP_VERSION, slip_maxdev);
+#if defined(SL_INCLUDE_CSLIP)
+   printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.n");
+#endif
+#ifdef CONFIG_SLIP_SMART
+   printk(KERN_INFO "SLIP linefill/keepalive option.n");
+#endif
+
+   slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev,
+                               GFP_KERNEL);
+   if (!slip_devs) {
+       printk(KERN_ERR "SLIP: Can't allocate slip devices array.n");
+       return -ENOMEM;
+   }
+
+   /* Fill in our line protocol discipline, and register it */
+   status = tty_register_ldisc(N_SLIP, &sl_ldisc);
+   if (status != 0) {
+       printk(KERN_ERR "SLIP: can't register line discipline (err = %d)n", status);
+       kfree(slip_devs);
+   }
+   return status;
+}
+
+static void __exit slip_exit(void)
+{
+   int i;
+   struct net_device *dev;
+   struct slip *sl;
+   unsigned long timeout = jiffies + HZ;
+   int busy = 0;
+
+   if (slip_devs == NULL)
+       return;
+
+   /* First of all: check for active disciplines and hangup them.
+    */
+   do {
+       if (busy)
+           msleep_interruptible(100);
+
+       busy = 0;
+       for (i = 0; i < slip_maxdev; i++) {
+           dev = slip_devs[i];
+           if (!dev)
+               continue;
+           sl = netdev_priv(dev);
+           spin_lock_bh(&sl->lock);
+           if (sl->tty) {
+               busy++;
+               tty_hangup(sl->tty);
+           }
+           spin_unlock_bh(&sl->lock);
+       }
+   } while (busy && time_before(jiffies, timeout));
+
+   /* FIXME: hangup is async so we should wait when doing this second
+      phase */
+
+   for (i = 0; i < slip_maxdev; i++) {
+       dev = slip_devs[i];
+       if (!dev)
+           continue;
+       slip_devs[i] = NULL;
+
+       sl = netdev_priv(dev);
+       if (sl->tty) {
+           printk(KERN_ERR "%s: tty discipline still runningn",
+                  dev->name);
+           /* Intentionally leak the control block. */
+           dev->destructor = NULL;
+       }
+
+       unregister_netdev(dev);
+   }
+
+   kfree(slip_devs);
+   slip_devs = NULL;
+
+   i = tty_unregister_ldisc(N_SLIP);
+   if (i != 0)
+       printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)n", i);
+}
+
+module_init(slip_init);
+module_exit(slip_exit);
+
+#ifdef CONFIG_SLIP_SMART
+/*
+ * This is start of the code for multislip style line checking
+ * added by Stanislav Voronyi. All changes before marked VSV
+ */
+
+static void sl_outfill(unsigned long sls)
+{
+   struct slip *sl = (struct slip *)sls;
+
+   spin_lock(&sl->lock);
+
+   if (sl->tty == NULL)
+       goto out;
+
+   if (sl->outfill) {
+       if (test_bit(SLF_OUTWAIT, &sl->flags)) {
+           /* no packets were transmitted, do outfill */
+#ifdef CONFIG_SLIP_MODE_SLIP6
+           unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;
+#else
+           unsigned char s = END;
+#endif
+           /* put END into tty queue. Is it right ??? */
+           if (!netif_queue_stopped(sl->dev)) {
+               /* if device busy no outfill */
+               sl->tty->ops->write(sl->tty, &s, 1);
+           }
+       } else
+           set_bit(SLF_OUTWAIT, &sl->flags);
+
+       mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
+   }
+out:
+   spin_unlock(&sl->lock);
+}
+
+static void sl_keepalive(unsigned long sls)
+{
+   struct slip *sl = (struct slip *)sls;
+
+   spin_lock(&sl->lock);
+
+   if (sl->tty == NULL)
+       goto out;
+
+   if (sl->keepalive) {
+       if (test_bit(SLF_KEEPTEST, &sl->flags)) {
+           /* keepalive still high :(, we must hangup */
+           if (sl->outfill)
+               /* outfill timer must be deleted too */
+               (void)del_timer(&sl->outfill_timer);
+           printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.n", sl->dev->name);
+           /* this must hangup tty & close slip */
+           tty_hangup(sl->tty);
+           /* I think we need not something else */
+           goto out;
+       } else
+           set_bit(SLF_KEEPTEST, &sl->flags);
+
+       mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
+   }
+out:
+   spin_unlock(&sl->lock);
+}
+
+#endif
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_SLIP);
diff --git a/drivers/net/slip/slip.h b/drivers/net/slip/slip.h
new file mode 100644
index 0000000..67673cf
--- /dev/null
+++ b/drivers/net/slip/slip.h
@@ -0,0 +1,101 @@
+/*
+ * slip.h  Define the SLIP device driver interface and constants.
+ *
+ * NOTE:   THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY
+ *     AS SOON AS POSSIBLE!
+ *
+ * Version:    @(#)slip.h  1.2.0   03/28/93
+ *
+ * Fixes:
+ *     Alan Cox    :   Added slip mtu field.
+ *     Matt Dillon :   Printable slip (borrowed from net2e)
+ *     Alan Cox    :   Added SL_SLIP_LOTS
+ * Dmitry Gorodchanin  :   A lot of changes in the 'struct slip'
+ * Dmitry Gorodchanin  :   Added CSLIP statistics.
+ * Stanislav Voronyi   :   Make line checking as created by
+ *                 Igor Chechik, RELCOM Corp.
+ * Craig Schlenter     :   Fixed #define bug that caused
+ *                 CSLIP telnets to hang in 1.3.61-6
+ *
+ * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ */
+#ifndef _LINUX_SLIP_H
+#define _LINUX_SLIP_H
+
+
+#if defined(CONFIG_INET) && defined(CONFIG_SLIP_COMPRESSED)
+# define SL_INCLUDE_CSLIP
+#endif
+
+#ifdef SL_INCLUDE_CSLIP
+# define SL_MODE_DEFAULT SL_MODE_ADAPTIVE
+#else
+# define SL_MODE_DEFAULT SL_MODE_SLIP
+#endif
+
+/* SLIP configuration. */
+#define SL_NRUNIT  256     /* MAX number of SLIP channels;
+                      This can be overridden with
+                      insmod -oslip_maxdev=nnn */
+#define SL_MTU     296     /* 296; I am used to 600- FvK   */
+
+/* SLIP protocol characters. */
+#define END             0300       /* indicates end of frame   */
+#define ESC             0333       /* indicates byte stuffing  */
+#define ESC_END         0334       /* ESC ESC_END means END 'data' */
+#define ESC_ESC         0335       /* ESC ESC_ESC means ESC 'data' */
+
+
+struct slip {
+  int          magic;
+
+  /* Various fields. */
+  struct tty_struct    *tty;       /* ptr to TTY structure     */
+  struct net_device    *dev;       /* easy for intr handling   */
+  spinlock_t       lock;
+
+#ifdef SL_INCLUDE_CSLIP
+  struct slcompress    *slcomp;    /* for header compression   */
+  unsigned char        *cbuff;     /* compression buffer       */
+#endif
+
+  /* These are pointers to the malloc()ed frame buffers. */
+  unsigned char        *rbuff;     /* receiver buffer      */
+  int                   rcount;         /* received chars counter       */
+  unsigned char        *xbuff;     /* transmitter buffer       */
+  unsigned char         *xhead;         /* pointer to next byte to XMIT */
+  int                   xleft;          /* bytes left in XMIT queue     */
+  int          mtu;        /* Our mtu (to spot changes!)   */
+  int                   buffsize;       /* Max buffers sizes            */
+
+#ifdef CONFIG_SLIP_MODE_SLIP6
+  int          xdata, xbits;   /* 6 bit slip controls      */
+#endif
+
+  unsigned long        flags;      /* Flag values/ mode etc    */
+#define SLF_INUSE  0       /* Channel in use               */
+#define SLF_ESCAPE 1               /* ESC received                 */
+#define SLF_ERROR  2               /* Parity, etc. error           */
+#define SLF_KEEPTEST   3       /* Keepalive test flag      */
+#define SLF_OUTWAIT    4       /* is outpacket was flag    */
+
+  unsigned char        mode;       /* SLIP mode            */
+  unsigned char        leased;
+  pid_t            pid;
+#define SL_MODE_SLIP   0
+#define SL_MODE_CSLIP  1
+#define SL_MODE_SLIP6  2       /* Matt Dillon's printable slip */
+#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP)
+#define SL_MODE_AX25   4
+#define SL_MODE_ADAPTIVE 8
+#ifdef CONFIG_SLIP_SMART
+  unsigned char        outfill;    /* # of sec between outfill packet */
+  unsigned char        keepalive;  /* keepalive seconds        */
+  struct timer_list    outfill_timer;
+  struct timer_list    keepalive_timer;
+#endif
+};
+
+#define SLIP_MAGIC 0x5302
+
+#endif /* _LINUX_SLIP.H */

Leave a Reply

Your email address will not be published. Required fields are marked *