]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
slip: Move the SLIP drivers
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 3 Aug 2011 10:17:13 +0000 (03:17 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 27 Aug 2011 07:58:36 +0000 (00:58 -0700)
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>
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/slhc.c [deleted file]
drivers/net/slip.c [deleted file]
drivers/net/slip.h [deleted file]
drivers/net/slip/Kconfig [new file with mode: 0644]
drivers/net/slip/Makefile [new file with mode: 0644]
drivers/net/slip/slhc.c [new file with mode: 0644]
drivers/net/slip/slip.c [new file with mode: 0644]
drivers/net/slip/slip.h [new file with mode: 0644]

index 3f72686e18041de2b3b8accbba550612fc0c1d6a..b3206c9222e62fa827f82a9625936a27f6ba6c52 100644 (file)
@@ -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
index 52dae95d4ea6b49d1562ceb95b5778a2093904c6..e6a183efc71ec2bc6965249f5905cf2328948f1f 100644 (file)
@@ -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 (file)
index 0a0a664..0000000
+++ /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 (file)
index ba08341..0000000
+++ /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 ignored\n", 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 on\n", 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 down\n", 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 running\n",
-                              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 (file)
index 67673cf..0000000
+++ /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 (file)
index 0000000..211b160
--- /dev/null
@@ -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 (file)
index 0000000..e3ebc59
--- /dev/null
@@ -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 (file)
index 0000000..0a0a664
--- /dev/null
@@ -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 (file)
index 0000000..ba08341
--- /dev/null
@@ -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 ignored\n", 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 on\n", 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 down\n", 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 running\n",
+                              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 (file)
index 0000000..67673cf
--- /dev/null
@@ -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 */