checkpoint at first working tp4 connection; before gnodes
[unix-history] / usr / src / sys / net / if_sl.c
index 8f3cd32..88ede68 100644 (file)
@@ -1,4 +1,21 @@
-/*     @(#)if_sl.c     5.2 (Berkeley) %G% */
+/*
+ * Copyright (c) 1987 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)if_sl.c     7.11 (Berkeley) %G%
+ */
 
 /*
  * Serial Line interface
 
 /*
  * Serial Line interface
  * rick@seismo.ARPA
  * seismo!rick
  *
  * rick@seismo.ARPA
  * seismo!rick
  *
- * Some things done here could obviously be done in a better way,
- * but they were done this way to minimize the number of files
- * that had to be changed to accomodate this device.
- *
  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
- * N.B.: this belongs in netinet, not vaxif, the way it stands now.
+ * N.B.: this belongs in netinet, not net, the way it stands now.
  * Should have a link-layer type designation, but wouldn't be
  * backwards-compatible.
  *
  * Converted to 4.3BSD Beta by Chris Torek.
  * Should have a link-layer type designation, but wouldn't be
  * backwards-compatible.
  *
  * Converted to 4.3BSD Beta by Chris Torek.
+ * Other changes made at Berkeley, based in part on code by Kirk Smith.
  */
 
 /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
  */
 
 /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
 #include "param.h"
 #include "mbuf.h"
 #include "buf.h"
 #include "param.h"
 #include "mbuf.h"
 #include "buf.h"
+#include "dk.h"
 #include "socket.h"
 #include "ioctl.h"
 #include "socket.h"
 #include "ioctl.h"
+#include "file.h"
 #include "tty.h"
 #include "errno.h"
 
 #include "tty.h"
 #include "errno.h"
 
-#include "../net/if.h"
-#include "../net/netisr.h"
-#include "../net/route.h"
+#include "if.h"
+#include "netisr.h"
+#include "route.h"
+#if INET
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip.h"
-#include "../netinet/ip_var.h"
+#endif
 
 
-#ifdef vax
-#include "../vax/mtpr.h"
-#endif vax
+#include "../machine/mtpr.h"
 
 /*
 
 /*
- * N.B.: SLMTU is now a hard limit on input packet size.  Some limit
- * is required, lest we use up all mbufs in the case of deleterious data
- * dribbling down the line.
+ * N.B.: SLMTU is now a hard limit on input packet size.
+ * SLMTU must be <= MCLBYTES - sizeof(struct ifnet *).
  */
 #define        SLMTU   1006
  */
 #define        SLMTU   1006
+#define        SLIP_HIWAT      1000    /* don't start a new packet if HIWAT on queue */
+#define        CLISTRESERVE    1000    /* Can't let clists get too low */
 
 struct sl_softc {
        struct  ifnet sc_if;    /* network-visible interface */
 
 struct sl_softc {
        struct  ifnet sc_if;    /* network-visible interface */
@@ -62,12 +79,11 @@ struct sl_softc {
        short   sc_ilen;        /* length of input-packet-so-far */
        struct  tty *sc_ttyp;   /* pointer to tty structure */
        char    *sc_mp;         /* pointer to next available buf char */
        short   sc_ilen;        /* length of input-packet-so-far */
        struct  tty *sc_ttyp;   /* pointer to tty structure */
        char    *sc_mp;         /* pointer to next available buf char */
-       char    sc_buf[SLMTU];  /* input buffer */
+       char    *sc_buf;        /* input buffer */
 } sl_softc[NSL];
 
 /* flags */
 #define        SC_ESCAPED      0x0001  /* saw a FRAME_ESCAPE */
 } sl_softc[NSL];
 
 /* flags */
 #define        SC_ESCAPED      0x0001  /* saw a FRAME_ESCAPE */
-#define        SC_OACTIVE      0x0002  /* output tty is active */
 
 #define FRAME_END              0300            /* Frame End */
 #define FRAME_ESCAPE           0333            /* Frame Esc */
 
 #define FRAME_END              0300            /* Frame End */
 #define FRAME_ESCAPE           0333            /* Frame Esc */
@@ -102,6 +118,7 @@ slattach()
  * Line specific open routine.
  * Attach the given tty to the first available sl unit.
  */
  * Line specific open routine.
  * Attach the given tty to the first available sl unit.
  */
+/* ARGSUSED */
 slopen(dev, tp)
        dev_t dev;
        register struct tty *tp;
 slopen(dev, tp)
        dev_t dev;
        register struct tty *tp;
@@ -109,20 +126,24 @@ slopen(dev, tp)
        register struct sl_softc *sc;
        register int nsl;
 
        register struct sl_softc *sc;
        register int nsl;
 
-       if (tp->t_sc != NULL)
+       if (!suser())
+               return (EPERM);
+       if (tp->t_line == SLIPDISC)
                return (EBUSY);
 
        for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++)
                if (sc->sc_ttyp == NULL) {
                        sc->sc_flags = 0;
                        sc->sc_ilen = 0;
                return (EBUSY);
 
        for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++)
                if (sc->sc_ttyp == NULL) {
                        sc->sc_flags = 0;
                        sc->sc_ilen = 0;
-                       sc->sc_mp = sc->sc_buf;
+                       if (slinit(sc) == 0)
+                               return (ENOBUFS);
                        tp->t_sc = (caddr_t)sc;
                        sc->sc_ttyp = tp;
                        tp->t_sc = (caddr_t)sc;
                        sc->sc_ttyp = tp;
+                       ttyflush(tp, FREAD | FWRITE);
                        return (0);
                }
 
                        return (0);
                }
 
-       return (ENOSPC);
+       return (ENXIO);
 }
 
 /*
 }
 
 /*
@@ -144,6 +165,8 @@ 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_buf);
+               sc->sc_buf = 0;
        }
        splx(s);
 }
        }
        splx(s);
 }
@@ -152,6 +175,7 @@ slclose(tp)
  * Line specific (tty) ioctl routine.
  * Provide a way to get the sl unit number.
  */
  * Line specific (tty) ioctl routine.
  * Provide a way to get the sl unit number.
  */
+/* ARGSUSED */
 sltioctl(tp, cmd, data, flag)
        struct tty *tp;
        caddr_t data;
 sltioctl(tp, cmd, data, flag)
        struct tty *tp;
        caddr_t data;
@@ -191,16 +215,20 @@ sloutput(ifp, m, dst)
                m_freem(m);
                return (ENETDOWN);      /* sort of */
        }
                m_freem(m);
                return (ENETDOWN);      /* sort of */
        }
+       if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
+               m_freem(m);
+               return (EHOSTUNREACH);
+       }
        s = splimp();
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
                splx(s);
                m_freem(m);
        s = splimp();
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
                splx(s);
                m_freem(m);
-               sc->sc_if.if_collisions++;
+               sc->sc_if.if_oerrors++;
                return (ENOBUFS);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
                return (ENOBUFS);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
-       if ((sc->sc_flags & SC_OACTIVE) == 0) {
+       if (sc->sc_ttyp->t_outq.c_cc == 0) {
                splx(s);
                slstart(sc->sc_ttyp);
        } else
                splx(s);
                slstart(sc->sc_ttyp);
        } else
@@ -218,137 +246,183 @@ slstart(tp)
 {
        register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
        register struct mbuf *m;
 {
        register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
        register struct mbuf *m;
-       register int c, len;
-       register u_char *mcp;
-       int flush;
+       register int len;
+       register u_char *cp;
+       int nd, np, n, s;
+       struct mbuf *m2;
+       extern int cfreecount;
 
 
-       /*
-        * If there is more in the output queue, just send it now.
-        * We are being called in lieu of ttstart and must do what
-        * it would.
-        */
-       if (tp->t_outq.c_cc > 0) {
-               ttstart(tp);
-               return;
-       }
+       for (;;) {
+               /*
+                * If there is more in the output queue, just send it now.
+                * We are being called in lieu of ttstart and must do what
+                * it would.
+                */
+               if (tp->t_outq.c_cc > 0)
+                       ttstart(tp);
+               if (tp->t_outq.c_cc > SLIP_HIWAT)
+                       return;
 
 
-       /*
-        * This happens briefly when the line shuts down.
-        */
-       if (sc == NULL)
-               return;
+               /*
+                * This happens briefly when the line shuts down.
+                */
+               if (sc == NULL)
+                       return;
 
 
-       /*
-        * Get a packet and map it to the interface.
-        */
-       c = splimp();
-       IF_DEQUEUE(&sc->sc_if.if_snd, m);
-       if (m == NULL) {
-               sc->sc_flags &= ~SC_OACTIVE;
-               splx(c);
-               return;
-       }
-       flush = !(sc->sc_flags & SC_OACTIVE);
-       sc->sc_flags |= SC_OACTIVE;
-       splx(c);
+               /*
+                * If system is getting low on clists
+                * and we have something running already, stop here.
+                */
+               if (cfreecount < CLISTRESERVE + SLMTU && tp->t_outq.c_cc)
+                       return;
 
 
-       /*
-        * 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 (flush)
-               (void) putc(FRAME_END, &tp->t_outq);
-
-       while (m != NULL) {
-               len = m->m_len;
-               mcp = mtod(m, u_char *);
-               while (--len >= 0) {
-                       c = *mcp++;
-                       if (c == FRAME_ESCAPE || c == FRAME_END) {
-                               if (putc(FRAME_ESCAPE, &tp->t_outq))
-                                       goto full;
-                               c = c == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE :
-                                                       TRANS_FRAME_END;
-                               if (putc(c, &tp->t_outq)) {
-                                       (void) unputc(&tp->t_outq);
-                                       goto full;
+               /*
+                * Get a packet and send it to the interface.
+                */
+               s = splimp();
+               IF_DEQUEUE(&sc->sc_if.if_snd, m);
+               splx(s);
+               if (m == NULL)
+                       return;
+
+               /*
+                * 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)
+                       (void) putc(FRAME_END, &tp->t_outq);
+
+               while (m) {
+                       cp = mtod(m, u_char *);
+                       len = m->m_len;
+                       while (len > 0) {
+                               /*
+                                * Find out how many bytes in the string we can
+                                * handle without doing something special.
+                                */
+                               nd = locc(FRAME_ESCAPE, len, cp);
+                               np = locc(FRAME_END, len, cp);
+                               n = len - MAX(nd, np);
+                               if (n) {
+                                       /*
+                                        * Put n characters at once
+                                        * into the tty output queue.
+                                        */
+                                       if (b_to_q((char *)cp, n, &tp->t_outq))
+                                               break;
+                                       len -= n;
+                                       cp += n;
                                }
                                }
-                       } else
-                               if (putc(c, &tp->t_outq))
-                                       goto full;
+                               /*
+                                * If there are characters left in the mbuf,
+                                * the first one must be special..
+                                * Put it out in a different form.
+                                */
+                               if (len) {
+                                       if (putc(FRAME_ESCAPE, &tp->t_outq))
+                                               break;
+                                       if (putc(*cp == FRAME_ESCAPE ?
+                                          TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
+                                          &tp->t_outq)) {
+                                               (void) unputc(&tp->t_outq);
+                                               break;
+                                       }
+                                       cp++;
+                                       len--;
+                               }
+                       }
+                       MFREE(m, m2);
+                       m = m2;
                }
                }
-               m = m_free(m);
+
+               if (putc(FRAME_END, &tp->t_outq)) {
+                       /*
+                        * Not enough room.  Remove a char to make room
+                        * and end the packet normally.
+                        * If you get many collisions (more than one or two
+                        * a day) you probably do not have enough clists
+                        * and you should increase "nclist" in param.c.
+                        */
+                       (void) unputc(&tp->t_outq);
+                       (void) putc(FRAME_END, &tp->t_outq);
+                       sc->sc_if.if_collisions++;
+               } else
+                       sc->sc_if.if_opackets++;
        }
        }
+}
 
 
-       if (putc(FRAME_END, &tp->t_outq)) {
-full:
-               /*
-                * If you get many oerrors (more than one or two a day)
-                * you probably do not have enough clists and you should 
-                * increase "nclist" in param.c.
-                */
-               (void) unputc(&tp->t_outq);     /* make room */
-               putc(FRAME_END, &tp->t_outq);   /* end the packet */
-               sc->sc_if.if_oerrors++;
-       } else
-               sc->sc_if.if_opackets++;
+slinit(sc)
+       register struct sl_softc *sc;
+{
+       register caddr_t p;
 
 
-       /*
-        * Start transmission.  Note that slstart, not ttstart, will be
-        * called when the transmission completes, be that after a single
-        * piece of what we have mapped, or be it after the entire thing
-        * has been sent.  That is why we need to check the output queue
-        * count at the top.
-        */
-       ttstart(tp);
+       if (sc->sc_buf == (char *) 0) {
+               MCLALLOC(p, M_WAIT);
+               if (p) {
+                       sc->sc_buf = p;
+                       sc->sc_mp = p;
+               } else {
+                       printf("sl%d: can't allocate buffer\n", sc - sl_softc);
+                       sc->sc_if.if_flags &= ~IFF_UP;
+                       return (0);
+               }
+       }
+       return (1);
 }
 
 /*
  * Copy data buffer to mbuf chain; add ifnet pointer ifp.
  */
 struct mbuf *
 }
 
 /*
  * Copy data buffer to mbuf chain; add ifnet pointer ifp.
  */
 struct mbuf *
-sl_btom(addr, len, ifp)
-       register caddr_t addr;
+sl_btom(sc, len, ifp)
+       struct sl_softc *sc;
        register int len;
        struct ifnet *ifp;
 {
        register int len;
        struct ifnet *ifp;
 {
+       register caddr_t cp;
        register struct mbuf *m, **mp;
        register struct mbuf *m, **mp;
-       register int count;
+       register unsigned count;
        struct mbuf *top = NULL;
 
        struct mbuf *top = NULL;
 
+       cp = sc->sc_buf + sizeof(struct ifnet *);
        mp = &top;
        while (len > 0) {
        mp = &top;
        while (len > 0) {
-               MGET(m, M_DONTWAIT, MT_DATA);
+               if (top == NULL) {
+                       MGETHDR(m, M_DONTWAIT, MT_DATA);
+               } else {
+                       MGET(m, M_DONTWAIT, MT_DATA);
+               }
                if ((*mp = m) == NULL) {
                        m_freem(top);
                        return (NULL);
                }
                if ((*mp = m) == NULL) {
                        m_freem(top);
                        return (NULL);
                }
-               if (ifp) {
-                       m->m_off += sizeof(ifp);
-                       count = MIN(len, MLEN - sizeof(ifp));
-               } else {
-                       if (len >= NBPG) {
-                               struct mbuf *p;
-
-                               MCLGET(p, 1);
-                               if (p != NULL) {
-                                       count = MIN(len, CLBYTES);
-                                       m->m_off = (int)p - (int)m;
-                               } else
-                                       count = MIN(len, MLEN);
-                       } else
-                               count = MIN(len, MLEN);
+               if (top == NULL) {
+                       m->m_pkthdr.rcvif = ifp;
+                       m->m_pkthdr.len = len;
+                       m->m_len = MHLEN;
+               } else
+                       m->m_len = MLEN;
+               /*
+                * If we have at least MINCLSIZE bytes,
+                * allocate a new page.  Swap the current
+                * buffer page with the new one.
+                */
+               if (len >= MINCLSIZE) {
+                       MCLGET(m, M_DONTWAIT);
+                       if (m->m_flags & M_EXT) {
+                               cp = mtod(m, char *);
+                               m->m_data = sc->sc_buf;
+                               sc->sc_buf = cp;
+                               count = MIN(len, MCLBYTES);
+                               goto nocopy;
+                       }
                }
                }
-               bcopy(addr, mtod(m, caddr_t), count);
+               count = MIN(len, m->m_len);
+               bcopy(cp, mtod(m, caddr_t), count);
+nocopy:
                m->m_len = count;
                m->m_len = count;
-               if (ifp) {
-                       m->m_off -= sizeof(ifp);
-                       m->m_len += sizeof(ifp);
-                       *mtod(m, struct ifnet **) = ifp;
-                       ifp = NULL;
-               }
-               addr += count;
+               cp += count;
                len -= count;
                mp = &m->m_next;
        }
                len -= count;
                mp = &m->m_next;
        }
@@ -366,6 +440,7 @@ slinput(c, tp)
        register struct mbuf *m;
        int s;
 
        register struct mbuf *m;
        int s;
 
+       tk_nin++;
        sc = (struct sl_softc *)tp->t_sc;
        if (sc == NULL)
                return;
        sc = (struct sl_softc *)tp->t_sc;
        if (sc == NULL)
                return;
@@ -385,7 +460,7 @@ slinput(c, tp)
 
                default:
                        sc->sc_if.if_ierrors++;
 
                default:
                        sc->sc_if.if_ierrors++;
-                       sc->sc_mp = sc->sc_buf;
+                       sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
                        sc->sc_ilen = 0;
                        return;
                }
                        sc->sc_ilen = 0;
                        return;
                }
@@ -395,12 +470,12 @@ slinput(c, tp)
                case FRAME_END:
                        if (sc->sc_ilen == 0)   /* ignore */
                                return;
                case FRAME_END:
                        if (sc->sc_ilen == 0)   /* ignore */
                                return;
-                       m = sl_btom(sc->sc_buf, sc->sc_ilen, &sc->sc_if);
+                       m = sl_btom(sc, sc->sc_ilen, &sc->sc_if);
                        if (m == NULL) {
                                sc->sc_if.if_ierrors++;
                                return;
                        }
                        if (m == NULL) {
                                sc->sc_if.if_ierrors++;
                                return;
                        }
-                       sc->sc_mp = sc->sc_buf;
+                       sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
                        sc->sc_ilen = 0;
                        sc->sc_if.if_ipackets++;
                        s = splimp();
                        sc->sc_ilen = 0;
                        sc->sc_if.if_ipackets++;
                        s = splimp();
@@ -420,9 +495,9 @@ slinput(c, tp)
                        return;
                }
        }
                        return;
                }
        }
-       if (++sc->sc_ilen >= SLMTU) {
+       if (++sc->sc_ilen > SLMTU) {
                sc->sc_if.if_ierrors++;
                sc->sc_if.if_ierrors++;
-               sc->sc_mp = sc->sc_buf;
+               sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
                sc->sc_ilen = 0;
                return;
        }
                sc->sc_ilen = 0;
                return;
        }
@@ -443,14 +518,14 @@ slioctl(ifp, cmd, data)
        switch (cmd) {
 
        case SIOCSIFADDR:
        switch (cmd) {
 
        case SIOCSIFADDR:
-               if (ifa->ifa_addr.sa_family == AF_INET)
+               if (ifa->ifa_addr->sa_family == AF_INET)
                        ifp->if_flags |= IFF_UP;
                else
                        error = EAFNOSUPPORT;
                break;
 
        case SIOCSIFDSTADDR:
                        ifp->if_flags |= IFF_UP;
                else
                        error = EAFNOSUPPORT;
                break;
 
        case SIOCSIFDSTADDR:
-               if (ifa->ifa_addr.sa_family != AF_INET)
+               if (ifa->ifa_addr->sa_family != AF_INET)
                        error = EAFNOSUPPORT;
                break;
 
                        error = EAFNOSUPPORT;
                break;