get rid for ifa->ifa_ft; new routing messages for adding/deleting
[unix-history] / usr / src / sys / net / if_sl.c
index 9174150..c0ed4b5 100644 (file)
@@ -1,20 +1,10 @@
 /*
 /*
- * Copyright (c) 1987, 1989 Regents of the University of California.
+ * Copyright (c) 1987, 1989, 1992 Regents of the University of California.
  * All rights reserved.
  *
  * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)if_sl.c     7.16 (Berkeley) %G%
+ *     @(#)if_sl.c     7.26 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
  * interrupts and network activity; thus, splimp must be >= spltty.
  */
 
  * interrupts and network activity; thus, splimp must be >= spltty.
  */
 
-/* $Header: if_sl.c,v 1.7 89/05/31 02:24:52 van Exp $ */
-/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
-
 #include "sl.h"
 #if NSL > 0
 
 #include "param.h"
 #include "sl.h"
 #if NSL > 0
 
 #include "param.h"
-#include "dir.h"
-#include "user.h"
+#include "proc.h"
 #include "mbuf.h"
 #include "buf.h"
 #include "dk.h"
 #include "mbuf.h"
 #include "buf.h"
 #include "dk.h"
 #include "tty.h"
 #include "kernel.h"
 #include "conf.h"
 #include "tty.h"
 #include "kernel.h"
 #include "conf.h"
-#include "errno.h"
+#include "machine/cpu.h"
 
 #include "if.h"
 
 #include "if.h"
+#include "if_types.h"
 #include "netisr.h"
 #include "route.h"
 #include "netisr.h"
 #include "route.h"
+
 #if INET
 #if INET
-#include "../netinet/in.h"
-#include "../netinet/in_systm.h"
-#include "../netinet/in_var.h"
-#include "../netinet/ip.h"
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#else
+Huh? Slip without inet?
 #endif
 
 #endif
 
-#include "machine/mtpr.h"
-
 #include "slcompress.h"
 #include "if_slvar.h"
 
 /*
 #include "slcompress.h"
 #include "if_slvar.h"
 
 /*
- * SLMTU is a hard limit on input packet size.  To simplify the code
+ * SLMAX is a hard limit on input packet size.  To simplify the code
  * and improve performance, we require that packets fit in an mbuf
  * and improve performance, we require that packets fit in an mbuf
- * cluster, that there be enough extra room for the ifnet pointer that
- * IP input requires and, if we get a compressed packet, there's
- * enough extra room to expand the header into a max length tcp/ip
- * header (128 bytes).  So, SLMTU can be at most
- *     MCLBYTES - sizeof(struct ifnet *) - 128 
+ * cluster, and if we get a compressed packet, there's enough extra
+ * room to expand the header into a max length tcp/ip header (128
+ * bytes).  So, SLMAX can be at most
+ *     MCLBYTES - 128
  *
  *
- * To insure we get good interactive response, the MTU wants to be
- * the smallest size that amortizes the header cost.  (Remember
- * that even with type-of-service queuing, we have to wait for any
- * in-progress packet to finish.  I.e., we wait, on the average,
- * 1/2 * mtu / cps, where cps is the line speed in characters per
- * second.  E.g., 533ms wait for a 1024 byte MTU on a 9600 baud
- * line.  The average compressed header size is 6-8 bytes so any
- * MTU > 90 bytes will give us 90% of the line bandwidth.  A 100ms
- * wait is tolerable (500ms is not), so want an MTU around 256.
- * (Since TCP will send 212 byte segments (to allow for 40 byte
- * headers), the typical packet size on the wire will be around 220
- * bytes).  In 4.3tahoe+ systems, we can set an MTU in a route
- * so we do that & leave the interface MTU relatively high (so we
- * don't IP fragment when acting as a gateway to someone using a
- * stupid MTU).
+ * SLMTU is a hard limit on output packet size.  To insure good
+ * interactive response, SLMTU wants to be the smallest size that
+ * amortizes the header cost.  (Remember that even with
+ * type-of-service queuing, we have to wait for any in-progress
+ * packet to finish.  I.e., we wait, on the average, 1/2 * mtu /
+ * cps, where cps is the line speed in characters per second.
+ * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line.  The
+ * average compressed header size is 6-8 bytes so any MTU > 90
+ * bytes will give us 90% of the line bandwidth.  A 100ms wait is
+ * tolerable (500ms is not), so want an MTU around 296.  (Since TCP
+ * will send 256 byte segments (to allow for 40 byte headers), the
+ * typical packet size on the wire will be around 260 bytes).  In
+ * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
+ * leave the interface MTU relatively high (so we don't IP fragment
+ * when acting as a gateway to someone using a stupid MTU).
+ *
+ * Similar considerations apply to SLIP_HIWAT:  It's the amount of
+ * data that will be queued 'downstream' of us (i.e., in clists
+ * waiting to be picked up by the tty output interrupt).  If we
+ * queue a lot of data downstream, it's immune to our t.o.s. queuing.
+ * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
+ * telnet/ftp will see a 1 sec wait, independent of the mtu (the
+ * wait is dependent on the ftp window size but that's typically
+ * 1k - 4k).  So, we want SLIP_HIWAT just big enough to amortize
+ * the cost (in idle time on the wire) of the tty driver running
+ * off the end of its clists & having to call back slstart for a
+ * new packet.  For a tty interface with any buffering at all, this
+ * cost will be zero.  Even with a totally brain dead interface (like
+ * the one on a typical workstation), the cost will be <= 1 character
+ * time.  So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
+ * at most 1% while maintaining good interactive response.
  */
  */
-#define        SLMTU   576
-#define BUFOFFSET (128+sizeof(struct ifnet **))
-#define        SLIP_HIWAT      1024    /* don't start a new packet if HIWAT on queue */
+#define BUFOFFSET      128
+#define        SLMAX           (MCLBYTES - BUFOFFSET)
+#define        SLBUFSIZE       (SLMAX + BUFOFFSET)
+#define        SLMTU           296
+#define        SLIP_HIWAT      roundup(50,CBSIZE)
 #define        CLISTRESERVE    1024    /* Can't let clists get too low */
 #define        CLISTRESERVE    1024    /* Can't let clists get too low */
+
 /*
  * SLIP ABORT ESCAPE MECHANISM:
  *     (inspired by HAYES modem escape arrangement)
  *     1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
 /*
  * SLIP ABORT ESCAPE MECHANISM:
  *     (inspired by HAYES modem escape arrangement)
  *     1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
- *     signals a "soft" exit from slip mode by usermode process
+ *     within window time signals a "soft" exit from slip mode by remote end
+ *     if the IFF_DEBUG flag is on.
  */
  */
-
 #define        ABT_ESC         '\033'  /* can't be t_intr - distant host must know it*/
 #define        ABT_ESC         '\033'  /* can't be t_intr - distant host must know it*/
-#define ABT_WAIT       1       /* in seconds - idle before an escape & after */
-#define ABT_RECYCLE    (5*2+2) /* in seconds - time window processing abort */
-
-#define ABT_SOFT       3       /* count of escapes */
-
-/*
- * The following disgusting hack gets around the problem that IP TOS
- * can't be set in BSD/Sun OS yet.  We want to put "interactive"
- * traffic on a high priority queue.  To decide if traffic is
- * interactive, we check that a) it is TCP and b) one of it's ports
- * if telnet, rlogin or ftp control.
- */
-static u_short interactive_ports[8] = {
-       0,      513,    0,      0,
-       0,      21,     0,      23,
-};
-#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
+#define ABT_IDLE       1       /* in seconds - idle before an escape */
+#define ABT_COUNT      3       /* count of escapes for abort */
+#define ABT_WINDOW     (ABT_COUNT*2+2) /* in seconds - time to count */
 
 struct sl_softc sl_softc[NSL];
 
 
 struct sl_softc sl_softc[NSL];
 
@@ -148,6 +140,7 @@ struct sl_softc sl_softc[NSL];
 #define t_sc T_LINEP
 
 int sloutput(), slioctl(), ttrstrt();
 #define t_sc T_LINEP
 
 int sloutput(), slioctl(), ttrstrt();
+extern struct timeval time;
 
 /*
  * Called from boot code to establish sl interfaces.
 
 /*
  * Called from boot code to establish sl interfaces.
@@ -161,7 +154,8 @@ slattach()
                sc->sc_if.if_name = "sl";
                sc->sc_if.if_unit = i++;
                sc->sc_if.if_mtu = SLMTU;
                sc->sc_if.if_name = "sl";
                sc->sc_if.if_unit = i++;
                sc->sc_if.if_mtu = SLMTU;
-               sc->sc_if.if_flags = IFF_POINTOPOINT;
+               sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP;
+               sc->sc_if.if_type = IFT_SLIP;
                sc->sc_if.if_ioctl = slioctl;
                sc->sc_if.if_output = sloutput;
                sc->sc_if.if_snd.ifq_maxlen = 50;
                sc->sc_if.if_ioctl = slioctl;
                sc->sc_if.if_output = sloutput;
                sc->sc_if.if_snd.ifq_maxlen = 50;
@@ -179,14 +173,14 @@ slinit(sc)
        if (sc->sc_ep == (u_char *) 0) {
                MCLALLOC(p, M_WAIT);
                if (p)
        if (sc->sc_ep == (u_char *) 0) {
                MCLALLOC(p, M_WAIT);
                if (p)
-                       sc->sc_ep = (u_char *)p + (BUFOFFSET + SLMTU);
+                       sc->sc_ep = (u_char *)p + SLBUFSIZE;
                else {
                        printf("sl%d: can't allocate buffer\n", sc - sl_softc);
                        sc->sc_if.if_flags &= ~IFF_UP;
                        return (0);
                }
        }
                else {
                        printf("sl%d: can't allocate buffer\n", sc - sl_softc);
                        sc->sc_if.if_flags &= ~IFF_UP;
                        return (0);
                }
        }
-       sc->sc_buf = sc->sc_ep - SLMTU;
+       sc->sc_buf = sc->sc_ep - SLMAX;
        sc->sc_mp = sc->sc_buf;
        sl_compress_init(&sc->sc_comp);
        return (1);
        sc->sc_mp = sc->sc_buf;
        sl_compress_init(&sc->sc_comp);
        return (1);
@@ -201,15 +195,16 @@ slopen(dev, tp)
        dev_t dev;
        register struct tty *tp;
 {
        dev_t dev;
        register struct tty *tp;
 {
+       struct proc *p = curproc;               /* XXX */
        register struct sl_softc *sc;
        register int nsl;
        int error;
 
        register struct sl_softc *sc;
        register int nsl;
        int error;
 
-       if (error = suser(u.u_cred, &u.u_acflag))
+       if (error = suser(p->p_ucred, &p->p_acflag))
                return (error);
 
        if (tp->t_line == SLIPDISC)
                return (error);
 
        if (tp->t_line == SLIPDISC)
-               return (EBUSY);
+               return (0);
 
        for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++)
                if (sc->sc_ttyp == NULL) {
 
        for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++)
                if (sc->sc_ttyp == NULL) {
@@ -217,6 +212,7 @@ slopen(dev, tp)
                                return (ENOBUFS);
                        tp->t_sc = (caddr_t)sc;
                        sc->sc_ttyp = tp;
                                return (ENOBUFS);
                        tp->t_sc = (caddr_t)sc;
                        sc->sc_ttyp = tp;
+                       sc->sc_if.if_baudrate = tp->t_ospeed;
                        ttyflush(tp, FREAD | FWRITE);
                        return (0);
                }
                        ttyflush(tp, FREAD | FWRITE);
                        return (0);
                }
@@ -242,7 +238,7 @@ slclose(tp)
                if_down(&sc->sc_if);
                sc->sc_ttyp = NULL;
                tp->t_sc = NULL;
                if_down(&sc->sc_if);
                sc->sc_ttyp = NULL;
                tp->t_sc = NULL;
-               MCLFREE((struct mbuf *)(sc->sc_ep - (SLMTU + BUFOFFSET)));
+               MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE));
                sc->sc_ep = 0;
                sc->sc_mp = 0;
                sc->sc_buf = 0;
                sc->sc_ep = 0;
                sc->sc_mp = 0;
                sc->sc_buf = 0;
@@ -263,23 +259,10 @@ sltioctl(tp, cmd, data, flag)
        int s;
 
        switch (cmd) {
        int s;
 
        switch (cmd) {
-       case TIOCGETD:                          /* XXX */
-       case SLIOGUNIT:
+       case SLIOCGUNIT:
                *(int *)data = sc->sc_if.if_unit;
                break;
 
                *(int *)data = sc->sc_if.if_unit;
                break;
 
-       case SLIOCGFLAGS:
-               *(int *)data = sc->sc_flags;
-               break;
-
-       case SLIOCSFLAGS:
-#define        SC_MASK (SC_COMPRESS|SC_NOICMP)
-               s = splimp();
-               sc->sc_flags =
-                   (sc->sc_flags &~ SC_MASK) | ((*(int *)data) & SC_MASK);
-               splx(s);
-               break;
-
        default:
                return (-1);
        }
        default:
                return (-1);
        }
@@ -290,13 +273,14 @@ sltioctl(tp, cmd, data, flag)
  * Queue a packet.  Start transmission if not active.
  */
 sloutput(ifp, m, dst)
  * Queue a packet.  Start transmission if not active.
  */
 sloutput(ifp, m, dst)
-       register struct ifnet *ifp;
+       struct ifnet *ifp;
        register struct mbuf *m;
        struct sockaddr *dst;
 {
        register struct mbuf *m;
        struct sockaddr *dst;
 {
-       register struct sl_softc *sc;
+       register struct sl_softc *sc = &sl_softc[ifp->if_unit];
        register struct ip *ip;
        register struct ifqueue *ifq;
        register struct ip *ip;
        register struct ifqueue *ifq;
+       register int p;
        int s;
 
        /*
        int s;
 
        /*
@@ -304,13 +288,13 @@ sloutput(ifp, m, dst)
         * the line protocol to support other address families.
         */
        if (dst->sa_family != AF_INET) {
         * the line protocol to support other address families.
         */
        if (dst->sa_family != AF_INET) {
-               printf("sl%d: af%d not supported\n", ifp->if_unit,
+               printf("sl%d: af%d not supported\n", sc->sc_if.if_unit,
                        dst->sa_family);
                m_freem(m);
                        dst->sa_family);
                m_freem(m);
+               sc->sc_if.if_noproto++;
                return (EAFNOSUPPORT);
        }
 
                return (EAFNOSUPPORT);
        }
 
-       sc = &sl_softc[ifp->if_unit];
        if (sc->sc_ttyp == NULL) {
                m_freem(m);
                return (ENETDOWN);      /* sort of */
        if (sc->sc_ttyp == NULL) {
                m_freem(m);
                return (ENETDOWN);      /* sort of */
@@ -319,27 +303,28 @@ sloutput(ifp, m, dst)
                m_freem(m);
                return (EHOSTUNREACH);
        }
                m_freem(m);
                return (EHOSTUNREACH);
        }
-       ifq = &ifp->if_snd;
+       ifq = &sc->sc_if.if_snd;
+       if (ip->ip_tos & IPTOS_LOWDELAY) {
+               ifq = &sc->sc_fastq;
+               p = 1;
+       } else
+               p = 0;
+
        if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
        if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
-               register int p = ((int *)ip)[ip->ip_hl];
-
-               if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
-                       ifq = &sc->sc_fastq;
-
-               if (sc->sc_flags & SC_COMPRESS) {
-                       /* if two copies of sl_compress_tcp are running
-                        * for the same line, the compression state can
-                        * get screwed up.  We're assuming that sloutput
-                        * was invoked at splnet so this isn't possible
-                        * (this assumption is correct for 4.xbsd, x<=4).
-                        * In a multi-threaded kernel, a lockout might
-                        * be needed here. */
-                       p = sl_compress_tcp(m, ip, &sc->sc_comp);
+               if (sc->sc_if.if_flags & SC_COMPRESS) {
+                       /*
+                        * The last parameter turns off connection id
+                        * compression for background traffic:  Since
+                        * fastq traffic can jump ahead of the background
+                        * traffic, we don't know what order packets will
+                        * go on the line.
+                        */
+                       p = sl_compress_tcp(m, ip, &sc->sc_comp, p);
                        *mtod(m, u_char *) |= p;
                }
                        *mtod(m, u_char *) |= p;
                }
-       } else if (sc->sc_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
+       } else if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
                m_freem(m);
                m_freem(m);
-               return (0);
+               return (ENETRESET);             /* XXX ? */
        }
        s = splimp();
        if (IF_QFULL(ifq)) {
        }
        s = splimp();
        if (IF_QFULL(ifq)) {
@@ -350,11 +335,10 @@ sloutput(ifp, m, dst)
                return (ENOBUFS);
        }
        IF_ENQUEUE(ifq, m);
                return (ENOBUFS);
        }
        IF_ENQUEUE(ifq, m);
-       if (sc->sc_ttyp->t_outq.c_cc == 0) {
-               splx(s);
+       sc->sc_if.if_lastchange = time;
+       if (sc->sc_ttyp->t_outq.c_cc == 0)
                slstart(sc->sc_ttyp);
                slstart(sc->sc_ttyp);
-       } else
-               splx(s);
+       splx(s);
        return (0);
 }
 
        return (0);
 }
 
@@ -395,11 +379,15 @@ slstart(tp)
                 */
                s = splimp();
                IF_DEQUEUE(&sc->sc_fastq, m);
                 */
                s = splimp();
                IF_DEQUEUE(&sc->sc_fastq, m);
-               if (m == NULL)
+               if (m)
+                       sc->sc_if.if_omcasts++;         /* XXX */
+               else
                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
                splx(s);
                if (m == NULL)
                        return;
                        IF_DEQUEUE(&sc->sc_if.if_snd, m);
                splx(s);
                if (m == NULL)
                        return;
+               sc->sc_if.if_lastchange = time;
+
                /*
                 * If system is getting low on clists, just flush our
                 * output queue (if the stuff was important, it'll get
                /*
                 * If system is getting low on clists, just flush our
                 * output queue (if the stuff was important, it'll get
@@ -410,14 +398,13 @@ slstart(tp)
                        sc->sc_if.if_collisions++;
                        continue;
                }
                        sc->sc_if.if_collisions++;
                        continue;
                }
-
                /*
                 * The extra FRAME_END will start up a new packet, and thus
                 * will flush any accumulated garbage.  We do this whenever
                 * the line may have been idle for some time.
                 */
                if (tp->t_outq.c_cc == 0) {
                /*
                 * The extra FRAME_END will start up a new packet, and thus
                 * will flush any accumulated garbage.  We do this whenever
                 * the line may have been idle for some time.
                 */
                if (tp->t_outq.c_cc == 0) {
-                       ++sc->sc_bytessent;
+                       ++sc->sc_if.if_obytes;
                        (void) putc(FRAME_END, &tp->t_outq);
                }
 
                        (void) putc(FRAME_END, &tp->t_outq);
                }
 
@@ -448,7 +435,7 @@ slstart(tp)
                                         */
                                        if (b_to_q((char *)bp, cp - bp, &tp->t_outq))
                                                break;
                                         */
                                        if (b_to_q((char *)bp, cp - bp, &tp->t_outq))
                                                break;
-                                       sc->sc_bytessent += cp - bp;
+                                       sc->sc_if.if_obytes += cp - bp;
                                }
                                /*
                                 * If there are characters left in the mbuf,
                                }
                                /*
                                 * If there are characters left in the mbuf,
@@ -464,7 +451,7 @@ slstart(tp)
                                                (void) unputc(&tp->t_outq);
                                                break;
                                        }
                                                (void) unputc(&tp->t_outq);
                                                break;
                                        }
-                                       sc->sc_bytessent += 2;
+                                       sc->sc_if.if_obytes += 2;
                                }
                        }
                        MFREE(m, m2);
                                }
                        }
                        MFREE(m, m2);
@@ -483,7 +470,7 @@ slstart(tp)
                        (void) putc(FRAME_END, &tp->t_outq);
                        sc->sc_if.if_collisions++;
                } else {
                        (void) putc(FRAME_END, &tp->t_outq);
                        sc->sc_if.if_collisions++;
                } else {
-                       ++sc->sc_bytessent;
+                       ++sc->sc_if.if_obytes;
                        sc->sc_if.if_opackets++;
                }
        }
                        sc->sc_if.if_opackets++;
                }
        }
@@ -497,7 +484,6 @@ sl_btom(sc, len)
        register struct sl_softc *sc;
        register int len;
 {
        register struct sl_softc *sc;
        register int len;
 {
-       register u_char *cp;
        register struct mbuf *m;
 
        MGETHDR(m, M_DONTWAIT, MT_DATA);
        register struct mbuf *m;
 
        MGETHDR(m, M_DONTWAIT, MT_DATA);
@@ -505,25 +491,27 @@ sl_btom(sc, len)
                return (NULL);
 
        /*
                return (NULL);
 
        /*
-        * If we have more than MLEN bytes, it's cheaper to
+        * If we have more than MHLEN bytes, it's cheaper to
         * queue the cluster we just filled & allocate a new one
         * for the input buffer.  Otherwise, fill the mbuf we
         * allocated above.  Note that code in the input routine
         * guarantees that packet will fit in a cluster.
         */
         * queue the cluster we just filled & allocate a new one
         * for the input buffer.  Otherwise, fill the mbuf we
         * allocated above.  Note that code in the input routine
         * guarantees that packet will fit in a cluster.
         */
-       cp = sc->sc_buf;
        if (len >= MHLEN) {
                MCLGET(m, M_DONTWAIT);
                if ((m->m_flags & M_EXT) == 0) {
        if (len >= MHLEN) {
                MCLGET(m, M_DONTWAIT);
                if ((m->m_flags & M_EXT) == 0) {
-                       /* we couldn't get a cluster - if memory's this
-                        * low, it's time to start dropping packets. */
-                       m_freem(m);
+                       /*
+                        * we couldn't get a cluster - if memory's this
+                        * low, it's time to start dropping packets.
+                        */
+                       (void) m_free(m);
                        return (NULL);
                }
                        return (NULL);
                }
-               sc->sc_ep = mtod(m, u_char *) + (BUFOFFSET + SLMTU);
-               m->m_data = (caddr_t)cp;
+               sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE;
+               m->m_data = (caddr_t)sc->sc_buf;
+               m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET);
        } else
        } else
-               bcopy((caddr_t)cp, mtod(m, caddr_t), len);
+               bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len);
 
        m->m_len = len;
        m->m_pkthdr.len = len;
 
        m->m_len = len;
        m->m_pkthdr.len = len;
@@ -550,32 +538,33 @@ slinput(c, tp)
        if (!(tp->t_state&TS_CARR_ON))  /* XXX */
                return;
 
        if (!(tp->t_state&TS_CARR_ON))  /* XXX */
                return;
 
-       ++sc->sc_bytesrcvd;
+       ++sc->sc_if.if_ibytes;
        c &= 0xff;                      /* XXX */
 
 #ifdef ABT_ESC
        c &= 0xff;                      /* XXX */
 
 #ifdef ABT_ESC
-       if (sc->sc_flags & SC_ABORT) {
-               /* if we see an abort after "idle" time, count it */
-               if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) {
-                       sc->sc_abortcount++;
-                       /* record when the first abort escape arrived */
-                       if (sc->sc_abortcount == 1)
-                               sc->sc_starttime = time.tv_sec;
-               }
-               /*
-                * if we have an abort, see that we have not run out of time,
-                * or that we have an "idle" time after the complete escape
-                * sequence
-                */
-               if (sc->sc_abortcount) {
-                       if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE)
+       if (sc->sc_if.if_flags & IFF_DEBUG) {
+               if (c == ABT_ESC) {
+                       /*
+                        * If we have a previous abort, see whether
+                        * this one is within the time limit.
+                        */
+                       if (sc->sc_abortcount &&
+                           time.tv_sec >= sc->sc_starttime + ABT_WINDOW)
                                sc->sc_abortcount = 0;
                                sc->sc_abortcount = 0;
-                       if (sc->sc_abortcount >= ABT_SOFT &&
-                           time.tv_sec >= sc->sc_lasttime + ABT_WAIT) {
-                               slclose(tp);
-                               return;
+                       /*
+                        * If we see an abort after "idle" time, count it;
+                        * record when the first abort escape arrived.
+                        */
+                       if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) {
+                               if (++sc->sc_abortcount == 1)
+                                       sc->sc_starttime = time.tv_sec;
+                               if (sc->sc_abortcount >= ABT_COUNT) {
+                                       slclose(tp);
+                                       return;
+                               }
                        }
                        }
-               }
+               } else
+                       sc->sc_abortcount = 0;
                sc->sc_lasttime = time.tv_sec;
        }
 #endif
                sc->sc_lasttime = time.tv_sec;
        }
 #endif
@@ -607,9 +596,26 @@ slinput(c, tp)
                                c = TYPE_COMPRESSED_TCP;
                        else if (c == TYPE_UNCOMPRESSED_TCP)
                                *sc->sc_buf &= 0x4f; /* XXX */
                                c = TYPE_COMPRESSED_TCP;
                        else if (c == TYPE_UNCOMPRESSED_TCP)
                                *sc->sc_buf &= 0x4f; /* XXX */
-                       len = sl_uncompress_tcp(&sc->sc_buf, len, (u_int)c,
-                                               &sc->sc_comp);
-                       if (len <= 0)
+                       /*
+                        * We've got something that's not an IP packet.
+                        * If compression is enabled, try to decompress it.
+                        * Otherwise, if `auto-enable' compression is on and
+                        * it's a reasonable packet, decompress it and then
+                        * enable compression.  Otherwise, drop it.
+                        */
+                       if (sc->sc_if.if_flags & SC_COMPRESS) {
+                               len = sl_uncompress_tcp(&sc->sc_buf, len,
+                                                       (u_int)c, &sc->sc_comp);
+                               if (len <= 0)
+                                       goto error;
+                       } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
+                           c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
+                               len = sl_uncompress_tcp(&sc->sc_buf, len,
+                                                       (u_int)c, &sc->sc_comp);
+                               if (len <= 0)
+                                       goto error;
+                               sc->sc_if.if_flags |= SC_COMPRESS;
+                       } else
                                goto error;
                }
                m = sl_btom(sc, len);
                                goto error;
                }
                m = sl_btom(sc, len);
@@ -617,10 +623,12 @@ slinput(c, tp)
                        goto error;
 
                sc->sc_if.if_ipackets++;
                        goto error;
 
                sc->sc_if.if_ipackets++;
+               sc->sc_if.if_lastchange = time;
                s = splimp();
                if (IF_QFULL(&ipintrq)) {
                        IF_DROP(&ipintrq);
                        sc->sc_if.if_ierrors++;
                s = splimp();
                if (IF_QFULL(&ipintrq)) {
                        IF_DROP(&ipintrq);
                        sc->sc_if.if_ierrors++;
+                       sc->sc_if.if_iqdrops++;
                        m_freem(m);
                } else {
                        IF_ENQUEUE(&ipintrq, m);
                        m_freem(m);
                } else {
                        IF_ENQUEUE(&ipintrq, m);
@@ -637,7 +645,7 @@ slinput(c, tp)
 error:
        sc->sc_if.if_ierrors++;
 newpack:
 error:
        sc->sc_if.if_ierrors++;
 newpack:
-       sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMTU;
+       sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
        sc->sc_escape = 0;
 }
 
        sc->sc_escape = 0;
 }