root/net/if_sl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. slattach
  2. sl_clone_create
  3. sl_clone_destroy
  4. slinit
  5. slopen
  6. slclose
  7. sltioctl
  8. sloutput
  9. slstart
  10. sl_btom
  11. slinput
  12. slioctl

    1 /*      $OpenBSD: if_sl.c,v 1.32 2006/03/25 22:41:47 djm Exp $  */
    2 /*      $NetBSD: if_sl.c,v 1.39.4.1 1996/06/02 16:26:31 thorpej Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1987, 1989, 1992, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)if_sl.c     8.6 (Berkeley) 2/1/94
   33  */
   34 
   35 /*
   36  * Serial Line interface
   37  *
   38  * Rick Adams
   39  * Center for Seismic Studies
   40  * 1300 N 17th Street, Suite 1450
   41  * Arlington, Virginia 22209
   42  * (703)276-7900
   43  * rick@seismo.ARPA
   44  * seismo!rick
   45  *
   46  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
   47  * N.B.: this belongs in netinet, not net, the way it stands now.
   48  * Should have a link-layer type designation, but wouldn't be
   49  * backwards-compatible.
   50  *
   51  * Converted to 4.3BSD Beta by Chris Torek.
   52  * Other changes made at Berkeley, based in part on code by Kirk Smith.
   53  * W. Jolitz added slip abort.
   54  *
   55  * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov).
   56  * Added priority queuing for "interactive" traffic; hooks for TCP
   57  * header compression; ICMP filtering (at 2400 baud, some cretin
   58  * pinging you can use up all your bandwidth).  Made low clist behavior
   59  * more robust and slightly less likely to hang serial line.
   60  * Sped up a bunch of things.
   61  */
   62 
   63 #include "bpfilter.h"
   64 
   65 #include <sys/param.h>
   66 #include <sys/proc.h>
   67 #include <sys/mbuf.h>
   68 #include <sys/dkstat.h>
   69 #include <sys/socket.h>
   70 #include <sys/ioctl.h>
   71 #include <sys/file.h>
   72 #include <sys/tty.h>
   73 #include <sys/kernel.h>
   74 #include <sys/conf.h>
   75 #if defined(__NetBSD__) || defined(__OpenBSD__)
   76 #include <sys/systm.h>
   77 #endif
   78 
   79 #include <machine/cpu.h>
   80 
   81 #include <net/if.h>
   82 #include <net/if_types.h>
   83 #include <net/netisr.h>
   84 #include <net/route.h>
   85 
   86 #if INET
   87 #include <netinet/in.h>
   88 #include <netinet/in_systm.h>
   89 #include <netinet/in_var.h>
   90 #include <netinet/ip.h>
   91 #else
   92 #error Huh? Slip without inet?
   93 #endif
   94 
   95 #include <net/slcompress.h>
   96 #include <net/if_slvar.h>
   97 #include <net/slip.h>
   98 
   99 #if NBPFILTER > 0
  100 #include <sys/time.h>
  101 #include <net/bpf.h>
  102 #endif
  103 
  104 /*
  105  * SLMAX is a hard limit on input packet size.  To simplify the code
  106  * and improve performance, we require that packets fit in an mbuf
  107  * cluster, and if we get a compressed packet, there's enough extra
  108  * room to expand the header into a max length tcp/ip header (128
  109  * bytes).  So, SLMAX can be at most
  110  *      MCLBYTES - 128
  111  *
  112  * SLMTU is a hard limit on output packet size.  To insure good
  113  * interactive response, SLMTU wants to be the smallest size that
  114  * amortizes the header cost.  (Remember that even with
  115  * type-of-service queuing, we have to wait for any in-progress
  116  * packet to finish.  I.e., we wait, on the average, 1/2 * mtu /
  117  * cps, where cps is the line speed in characters per second.
  118  * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line.  The
  119  * average compressed header size is 6-8 bytes so any MTU > 90
  120  * bytes will give us 90% of the line bandwidth.  A 100ms wait is
  121  * tolerable (500ms is not), so want an MTU around 296.  (Since TCP
  122  * will send 256 byte segments (to allow for 40 byte headers), the
  123  * typical packet size on the wire will be around 260 bytes).  In
  124  * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
  125  * leave the interface MTU relatively high (so we don't IP fragment
  126  * when acting as a gateway to someone using a stupid MTU).
  127  *
  128  * Similar considerations apply to SLIP_HIWAT:  It's the amount of
  129  * data that will be queued 'downstream' of us (i.e., in clists
  130  * waiting to be picked up by the tty output interrupt).  If we
  131  * queue a lot of data downstream, it's immune to our t.o.s. queuing.
  132  * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
  133  * telnet/ftp will see a 1 sec wait, independent of the mtu (the
  134  * wait is dependent on the ftp window size but that's typically
  135  * 1k - 4k).  So, we want SLIP_HIWAT just big enough to amortize
  136  * the cost (in idle time on the wire) of the tty driver running
  137  * off the end of its clists & having to call back slstart for a
  138  * new packet.  For a tty interface with any buffering at all, this
  139  * cost will be zero.  Even with a totally brain dead interface (like
  140  * the one on a typical workstation), the cost will be <= 1 character
  141  * time.  So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
  142  * at most 1% while maintaining good interactive response.
  143  */
  144 #if NBPFILTER > 0
  145 #define BUFOFFSET       (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
  146 #else
  147 #define BUFOFFSET       (128+sizeof(struct ifnet **))
  148 #endif
  149 #define SLMAX           (MCLBYTES - BUFOFFSET)
  150 #define SLBUFSIZE       (SLMAX + BUFOFFSET)
  151 #ifndef SLMTU
  152 #define SLMTU           296
  153 #endif
  154 #if (SLMTU < 3)
  155 #error Huh?  SLMTU way too small.
  156 #endif
  157 #define SLIP_HIWAT      roundup(50,CBSIZE)
  158 #if !(defined(__NetBSD__) || defined(__OpenBSD__))              /* XXX - cgd */
  159 #define CLISTRESERVE    1024    /* Can't let clists get too low */
  160 #endif  /* !NetBSD */
  161 
  162 /*
  163  * SLIP ABORT ESCAPE MECHANISM:
  164  *      (inspired by HAYES modem escape arrangement)
  165  *      1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
  166  *      within window time signals a "soft" exit from slip mode by remote end
  167  *      if the IFF_DEBUG flag is on.
  168  */
  169 #define ABT_ESC         '\033'  /* can't be t_intr - distant host must know it*/
  170 #define ABT_IDLE        1       /* in seconds - idle before an escape */
  171 #define ABT_COUNT       3       /* count of escapes for abort */
  172 #define ABT_WINDOW      (ABT_COUNT*2+2) /* in seconds - time to count */
  173 
  174 
  175 #define FRAME_END               0xc0            /* Frame End */
  176 #define FRAME_ESCAPE            0xdb            /* Frame Esc */
  177 #define TRANS_FRAME_END         0xdc            /* transposed frame end */
  178 #define TRANS_FRAME_ESCAPE      0xdd            /* transposed frame esc */
  179 
  180 static int slinit(struct sl_softc *);
  181 static struct mbuf *sl_btom(struct sl_softc *, int);
  182 
  183 int     sl_clone_create(struct if_clone *, int);
  184 int     sl_clone_destroy(struct ifnet *);
  185 
  186 LIST_HEAD(, sl_softc) sl_softc_list;
  187 struct if_clone sl_cloner =
  188     IF_CLONE_INITIALIZER("sl", sl_clone_create, sl_clone_destroy);
  189 
  190 /*
  191  * Called from boot code to establish sl interfaces.
  192  */
  193 void
  194 slattach(n)
  195         int n;
  196 {
  197         LIST_INIT(&sl_softc_list);
  198         if_clone_attach(&sl_cloner);
  199 }
  200 
  201 int
  202 sl_clone_create(ifc, unit)
  203         struct if_clone *ifc;
  204         int unit;
  205 {
  206         struct sl_softc *sc;
  207         int s;
  208 
  209         sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
  210         if (!sc)
  211                 return (ENOMEM);
  212         bzero(sc, sizeof(*sc));
  213 
  214         sc->sc_unit = unit;     /* XXX */
  215         snprintf(sc->sc_if.if_xname, sizeof sc->sc_if.if_xname, "%s%d",
  216             ifc->ifc_name, unit);
  217         sc->sc_if.if_softc = sc;
  218         sc->sc_if.if_mtu = SLMTU;
  219         sc->sc_if.if_flags =
  220             IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
  221         sc->sc_if.if_type = IFT_SLIP;
  222         sc->sc_if.if_ioctl = slioctl;
  223         sc->sc_if.if_output = sloutput;
  224         IFQ_SET_MAXLEN(&sc->sc_if.if_snd, 50);
  225         sc->sc_fastq.ifq_maxlen = 32;
  226         IFQ_SET_READY(&sc->sc_if.if_snd);
  227         if_attach(&sc->sc_if);
  228         if_alloc_sadl(&sc->sc_if);
  229 #if NBPFILTER > 0
  230         bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
  231 #endif
  232         s = splnet();
  233         LIST_INSERT_HEAD(&sl_softc_list, sc, sc_list);
  234         splx(s);
  235 
  236         return (0);
  237 }
  238 
  239 int
  240 sl_clone_destroy(ifp)
  241         struct ifnet *ifp;
  242 {
  243         struct sl_softc *sc = ifp->if_softc;
  244         int s;
  245 
  246         if (sc->sc_ttyp != NULL)
  247                 return (EBUSY);
  248 
  249         s = splnet();
  250         LIST_REMOVE(sc, sc_list);
  251         splx(s);
  252 
  253         if_detach(ifp);
  254 
  255         free(sc, M_DEVBUF);
  256         return (0);
  257 }
  258 
  259 static int
  260 slinit(sc)
  261         struct sl_softc *sc;
  262 {
  263         if (sc->sc_ep == (u_char *) 0) {
  264                 MGETHDR(sc->sc_mbuf, M_WAIT, MT_DATA);
  265                 if (sc->sc_mbuf)
  266                         MCLGET(sc->sc_mbuf, M_WAIT);
  267                 if (sc->sc_mbuf == NULL || sc->sc_mbuf->m_ext.ext_buf == NULL) {
  268                         printf("sl%d: can't allocate buffer\n", sc->sc_unit);
  269                         sc->sc_if.if_flags &= ~IFF_UP;
  270                         return (0);
  271                 }
  272         }
  273         sc->sc_ep = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  274             sc->sc_mbuf->m_ext.ext_size;
  275         sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  276             BUFOFFSET;
  277 
  278         sl_compress_init(&sc->sc_comp);
  279 
  280         return (1);
  281 }
  282 
  283 /*
  284  * Line specific open routine.
  285  * Attach the given tty to the first available sl unit.
  286  */
  287 /* ARGSUSED */
  288 int
  289 slopen(dev, tp)
  290         dev_t dev;
  291         struct tty *tp;
  292 {
  293         struct proc *p = curproc;               /* XXX */
  294         struct sl_softc *sc;
  295         int error, s;
  296 
  297         if ((error = suser(p, 0)) != 0)
  298                 return (error);
  299 
  300         if (tp->t_line == SLIPDISC)
  301                 return (0);
  302 
  303         LIST_FOREACH(sc, &sl_softc_list, sc_list)
  304                 if (sc->sc_ttyp == NULL) {
  305                         if (slinit(sc) == 0)
  306                                 return (ENOBUFS);
  307                         tp->t_sc = (caddr_t)sc;
  308                         sc->sc_ttyp = tp;
  309                         sc->sc_if.if_baudrate = tp->t_ospeed;
  310                         s = spltty();
  311                         tp->t_state |= TS_ISOPEN | TS_XCLUDE;
  312                         splx(s);
  313                         ttyflush(tp, FREAD | FWRITE);
  314 #if defined(__NetBSD__) || defined(__OpenBSD__)
  315                         /*
  316                          * make sure tty output queue is large enough
  317                          * to hold a full-sized packet (including frame
  318                          * end, and a possible extra frame end).  full-sized
  319                          * packet occupies a max of 2*SLMTU bytes (because
  320                          * of possible escapes), and add two on for frame
  321                          * ends.
  322                          */
  323                         s = spltty();
  324                         if (tp->t_outq.c_cn < 2*SLMTU+2) {
  325                                 sc->sc_oldbufsize = tp->t_outq.c_cn;
  326                                 sc->sc_oldbufquot = tp->t_outq.c_cq != 0;
  327 
  328                                 clfree(&tp->t_outq);
  329                                 error = clalloc(&tp->t_outq, 3*SLMTU, 0);
  330                                 if (error) {
  331                                         splx(s);
  332                                         return (error);
  333                                 }
  334                         } else
  335                                 sc->sc_oldbufsize = sc->sc_oldbufquot = 0;
  336                         splx(s);
  337 #endif /* NetBSD */
  338                         return (0);
  339                 }
  340         return (ENXIO);
  341 }
  342 
  343 /*
  344  * Line specific close routine.
  345  * Detach the tty from the sl unit.
  346  */
  347 void
  348 slclose(tp)
  349         struct tty *tp;
  350 {
  351         struct sl_softc *sc;
  352         int s;
  353 
  354         ttywflush(tp);
  355         tp->t_line = 0;
  356         sc = (struct sl_softc *)tp->t_sc;
  357         if (sc != NULL) {
  358                 s = spltty();
  359 
  360                 if_down(&sc->sc_if);
  361                 sc->sc_ttyp = NULL;
  362                 tp->t_sc = NULL;
  363 
  364                 m_freem(sc->sc_mbuf);
  365                 sc->sc_mbuf = NULL;
  366                 sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL;
  367 
  368 #if defined(__NetBSD__) || defined(__OpenBSD__)
  369                 /* if necessary, install a new outq buffer of the appropriate size */
  370                 if (sc->sc_oldbufsize != 0) {
  371                         clfree(&tp->t_outq);
  372                         clalloc(&tp->t_outq, sc->sc_oldbufsize, sc->sc_oldbufquot);
  373                 }
  374 #endif
  375                 splx(s);
  376         }
  377 }
  378 
  379 /*
  380  * Line specific (tty) ioctl routine.
  381  * Provide a way to get the sl unit number.
  382  */
  383 /* ARGSUSED */
  384 int
  385 sltioctl(tp, cmd, data, flag)
  386         struct tty *tp;
  387         u_long cmd;
  388         caddr_t data;
  389         int flag;
  390 {
  391         struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
  392 
  393         switch (cmd) {
  394         case SLIOCGUNIT:
  395                 *(int *)data = sc->sc_unit;     /* XXX */
  396                 break;
  397 
  398         default:
  399                 return (-1);
  400         }
  401         return (0);
  402 }
  403 
  404 /*
  405  * Queue a packet.  Start transmission if not active.
  406  * Compression happens in slstart; if we do it here, IP TOS
  407  * will cause us to not compress "background" packets, because
  408  * ordering gets trashed.  It can be done for all packets in slstart.
  409  */
  410 int
  411 sloutput(ifp, m, dst, rtp)
  412         struct ifnet *ifp;
  413         struct mbuf *m;
  414         struct sockaddr *dst;
  415         struct rtentry *rtp;
  416 {
  417         struct sl_softc *sc = ifp->if_softc;
  418         struct ip *ip;
  419         int s, error;
  420 
  421         /*
  422          * `Cannot happen' (see slioctl).  Someday we will extend
  423          * the line protocol to support other address families.
  424          */
  425         if (dst->sa_family != AF_INET) {
  426                 printf("%s: af%d not supported\n", sc->sc_if.if_xname,
  427                         dst->sa_family);
  428                 m_freem(m);
  429                 sc->sc_if.if_noproto++;
  430                 return (EAFNOSUPPORT);
  431         }
  432 
  433         if (sc->sc_ttyp == NULL) {
  434                 m_freem(m);
  435                 return (ENETDOWN);      /* sort of */
  436         }
  437         if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
  438             (sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
  439                 m_freem(m);
  440                 return (EHOSTUNREACH);
  441         }
  442         ip = mtod(m, struct ip *);
  443         if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
  444                 m_freem(m);
  445                 return (ENETRESET);             /* XXX ? */
  446         }
  447         s = spltty();
  448         if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
  449                 struct timeval tv, tm;
  450 
  451                 getmicrotime(&tm);
  452                 /* if output's been stalled for too long, and restart */
  453                 timersub(&tm, &sc->sc_lastpacket, &tv);
  454                 if (tv.tv_sec > 0) {
  455                         sc->sc_otimeout++;
  456                         slstart(sc->sc_ttyp);
  457                 }
  458         }
  459 
  460         (void) splnet();
  461         IFQ_ENQUEUE(&sc->sc_if.if_snd, m, NULL, error);
  462         if (error) {
  463                 splx(s);
  464                 sc->sc_if.if_oerrors++;
  465                 return (error);
  466         }
  467 
  468         (void) spltty();
  469         getmicrotime(&sc->sc_lastpacket);
  470         if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0)
  471                 slstart(sc->sc_ttyp);
  472         splx(s);
  473         return (0);
  474 }
  475 
  476 /*
  477  * Start output on interface.  Get another datagram
  478  * to send from the interface queue and map it to
  479  * the interface before starting output.
  480  */
  481 void
  482 slstart(tp)
  483         struct tty *tp;
  484 {
  485         struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
  486         struct mbuf *m;
  487         u_char *cp;
  488         struct ip *ip;
  489         int s;
  490         struct mbuf *m2;
  491 #if NBPFILTER > 0
  492         u_char bpfbuf[SLMTU + SLIP_HDRLEN];
  493         int len = 0;
  494 #endif
  495 #if !(defined(__NetBSD__) || defined(__OpenBSD__))      /* XXX - cgd */
  496         extern int cfreecount;
  497 #endif
  498 
  499         for (;;) {
  500                 /*
  501                  * If there is more in the output queue, just send it now.
  502                  * We are being called in lieu of ttstart and must do what
  503                  * it would.
  504                  */
  505                 if (tp->t_outq.c_cc != 0) {
  506                         (*tp->t_oproc)(tp);
  507                         if (tp->t_outq.c_cc > SLIP_HIWAT)
  508                                 return;
  509                 }
  510                 /*
  511                  * This happens briefly when the line shuts down.
  512                  */
  513                 if (sc == NULL)
  514                         return;
  515 
  516 #if defined(__NetBSD__) || defined(__OpenBSD__)         /* XXX - cgd */
  517                 /*
  518                  * Do not remove the packet from the IP queue if it
  519                  * doesn't look like the packet will fit into the
  520                  * current serial output queue, with a packet full of
  521                  * escapes this could be as bad as SLMTU*2+2.
  522                  */
  523                 if (tp->t_outq.c_cn - tp->t_outq.c_cc < 2*SLMTU+2)
  524                         return;
  525 #endif /* NetBSD */
  526 
  527                 /*
  528                  * Get a packet and send it to the interface.
  529                  */
  530                 s = splnet();
  531                 IF_DEQUEUE(&sc->sc_fastq, m);
  532                 if (m)
  533                         sc->sc_if.if_omcasts++;         /* XXX */
  534                 else
  535                         IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
  536                 splx(s);
  537                 if (m == NULL)
  538                         return;
  539 
  540                 /*
  541                  * We do the header compression here rather than in sloutput
  542                  * because the packets will be out of order if we are using TOS
  543                  * queueing, and the connection id compression will get
  544                  * munged when this happens.
  545                  */
  546 #if NBPFILTER > 0
  547                 if (sc->sc_bpf) {
  548                         /*
  549                          * We need to save the TCP/IP header before it's
  550                          * compressed.  To avoid complicated code, we just
  551                          * copy the entire packet into a stack buffer (since
  552                          * this is a serial line, packets should be short
  553                          * and/or the copy should be negligible cost compared
  554                          * to the packet transmission time).
  555                          */
  556                         struct mbuf *m1 = m;
  557                         u_char *cp = bpfbuf + SLIP_HDRLEN;
  558 
  559                         len = 0;
  560                         do {
  561                                 int mlen = m1->m_len;
  562 
  563                                 bcopy(mtod(m1, caddr_t), cp, mlen);
  564                                 cp += mlen;
  565                                 len += mlen;
  566                         } while ((m1 = m1->m_next) != NULL);
  567                 }
  568 #endif
  569                 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
  570                         if (sc->sc_if.if_flags & SC_COMPRESS)
  571                                 *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
  572                                     &sc->sc_comp, 1);
  573                 }
  574 #if NBPFILTER > 0
  575                 if (sc->sc_bpf) {
  576                         /*
  577                          * Put the SLIP pseudo-"link header" in place.  The
  578                          * compressed header is now at the beginning of the
  579                          * mbuf.
  580                          */
  581                         bpfbuf[SLX_DIR] = SLIPDIR_OUT;
  582                         bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN);
  583                         bpf_tap(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN,
  584                             BPF_DIRECTION_OUT);
  585                 }
  586 #endif
  587                 getmicrotime(&sc->sc_lastpacket);
  588 
  589 #if !(defined(__NetBSD__) || defined(__OpenBSD__))              /* XXX - cgd */
  590                 /*
  591                  * If system is getting low on clists, just flush our
  592                  * output queue (if the stuff was important, it'll get
  593                  * retransmitted).
  594                  */
  595                 if (cfreecount < CLISTRESERVE + SLMTU) {
  596                         m_freem(m);
  597                         sc->sc_if.if_collisions++;
  598                         continue;
  599                 }
  600 #endif /* !__NetBSD__ */
  601                 /*
  602                  * The extra FRAME_END will start up a new packet, and thus
  603                  * will flush any accumulated garbage.  We do this whenever
  604                  * the line may have been idle for some time.
  605                  */
  606                 if (tp->t_outq.c_cc == 0) {
  607                         ++sc->sc_if.if_obytes;
  608                         (void) putc(FRAME_END, &tp->t_outq);
  609                 }
  610 
  611                 while (m) {
  612                         u_char *ep;
  613 
  614                         cp = mtod(m, u_char *); ep = cp + m->m_len;
  615                         while (cp < ep) {
  616                                 /*
  617                                  * Find out how many bytes in the string we can
  618                                  * handle without doing something special.
  619                                  */
  620                                 u_char *bp = cp;
  621 
  622                                 while (cp < ep) {
  623                                         switch (*cp++) {
  624                                         case FRAME_ESCAPE:
  625                                         case FRAME_END:
  626                                                 --cp;
  627                                                 goto out;
  628                                         }
  629                                 }
  630                                 out:
  631                                 if (cp > bp) {
  632                                         /*
  633                                          * Put n characters at once
  634                                          * into the tty output queue.
  635                                          */
  636 #if defined(__NetBSD__) || defined(__OpenBSD__)         /* XXX - cgd */
  637                                         if (b_to_q((u_char *)bp, cp - bp,
  638 #else
  639                                         if (b_to_q((char *)bp, cp - bp,
  640 #endif
  641                                             &tp->t_outq))
  642                                                 break;
  643                                         sc->sc_if.if_obytes += cp - bp;
  644                                 }
  645                                 /*
  646                                  * If there are characters left in the mbuf,
  647                                  * the first one must be special..
  648                                  * Put it out in a different form.
  649                                  */
  650                                 if (cp < ep) {
  651                                         if (putc(FRAME_ESCAPE, &tp->t_outq))
  652                                                 break;
  653                                         if (putc(*cp++ == FRAME_ESCAPE ?
  654                                            TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
  655                                            &tp->t_outq)) {
  656                                                 (void) unputc(&tp->t_outq);
  657                                                 break;
  658                                         }
  659                                         sc->sc_if.if_obytes += 2;
  660                                 }
  661                         }
  662                         MFREE(m, m2);
  663                         m = m2;
  664                 }
  665 
  666                 if (putc(FRAME_END, &tp->t_outq)) {
  667                         /*
  668                          * Not enough room.  Remove a char to make room
  669                          * and end the packet normally.
  670                          * If you get many collisions (more than one or two
  671                          * a day) you probably do not have enough clists
  672                          * and you should increase "nclist" in param.c.
  673                          */
  674                         (void) unputc(&tp->t_outq);
  675                         (void) putc(FRAME_END, &tp->t_outq);
  676                         sc->sc_if.if_collisions++;
  677                 } else {
  678                         ++sc->sc_if.if_obytes;
  679                         sc->sc_if.if_opackets++;
  680                 }
  681         }
  682 }
  683 
  684 /*
  685  * Copy data buffer to mbuf chain; add ifnet pointer.
  686  */
  687 static struct mbuf *
  688 sl_btom(sc, len)
  689         struct sl_softc *sc;
  690         int len;
  691 {
  692         struct mbuf *m;
  693 
  694         /*
  695          * Allocate a new input buffer and swap.
  696          */
  697         m = sc->sc_mbuf;
  698         MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA);
  699         if (sc->sc_mbuf == NULL) {
  700                 sc->sc_mbuf = m;
  701                 return (NULL);
  702         }
  703         MCLGET(sc->sc_mbuf, M_DONTWAIT);
  704         if ((sc->sc_mbuf->m_flags & M_EXT) == 0) {
  705                 /*
  706                  * we couldn't get a cluster - if memory's this
  707                  * low, it's time to start dropping packets.
  708                  */
  709                 m_freem(sc->sc_mbuf);
  710                 sc->sc_mbuf = m;
  711                 return (NULL);
  712         }
  713         sc->sc_ep = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  714                 sc->sc_mbuf->m_ext.ext_size;
  715         
  716         m->m_data = sc->sc_pktstart;
  717 
  718         m->m_len = len;
  719         m->m_pkthdr.len = len;
  720         m->m_pkthdr.rcvif = &sc->sc_if;
  721         return (m);
  722 }
  723 
  724 /*
  725  * tty interface receiver interrupt.
  726  */
  727 void
  728 slinput(c, tp)
  729         int c;
  730         struct tty *tp;
  731 {
  732         struct sl_softc *sc;
  733         struct mbuf *m;
  734         int len;
  735         int s;
  736 #if NBPFILTER > 0
  737         u_char chdr[CHDR_LEN];
  738 #endif
  739 
  740         tk_nin++;
  741         sc = (struct sl_softc *)tp->t_sc;
  742         if (sc == NULL)
  743                 return;
  744         if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 &&
  745             (tp->t_cflag & CLOCAL) == 0)) {
  746                 sc->sc_flags |= SC_ERROR;
  747                 return;
  748         }
  749         c &= TTY_CHARMASK;
  750 
  751         ++sc->sc_if.if_ibytes;
  752 
  753         if (sc->sc_if.if_flags & IFF_DEBUG) {
  754                 if (c == ABT_ESC) {
  755                         /*
  756                          * If we have a previous abort, see whether
  757                          * this one is within the time limit.
  758                          */
  759                         if (sc->sc_abortcount &&
  760                             time_second >= sc->sc_starttime + ABT_WINDOW)
  761                                 sc->sc_abortcount = 0;
  762                         /*
  763                          * If we see an abort after "idle" time, count it;
  764                          * record when the first abort escape arrived.
  765                          */
  766                         if (time_second >= sc->sc_lasttime + ABT_IDLE) {
  767                                 if (++sc->sc_abortcount == 1)
  768                                         sc->sc_starttime = time_second;
  769                                 if (sc->sc_abortcount >= ABT_COUNT) {
  770                                         slclose(tp);
  771                                         return;
  772                                 }
  773                         }
  774                 } else
  775                         sc->sc_abortcount = 0;
  776                 sc->sc_lasttime = time_second;
  777         }
  778 
  779         switch (c) {
  780 
  781         case TRANS_FRAME_ESCAPE:
  782                 if (sc->sc_escape)
  783                         c = FRAME_ESCAPE;
  784                 break;
  785 
  786         case TRANS_FRAME_END:
  787                 if (sc->sc_escape)
  788                         c = FRAME_END;
  789                 break;
  790 
  791         case FRAME_ESCAPE:
  792                 sc->sc_escape = 1;
  793                 return;
  794 
  795         case FRAME_END:
  796                 if(sc->sc_flags & SC_ERROR) {
  797                         sc->sc_flags &= ~SC_ERROR;
  798                         goto newpack;
  799                 }
  800                 len = sc->sc_mp - sc->sc_pktstart;
  801                 if (len < 3)
  802                         /* less than min length packet - ignore */
  803                         goto newpack;
  804 
  805 #if NBPFILTER > 0
  806                 if (sc->sc_bpf) {
  807                         /*
  808                          * Save the compressed header, so we
  809                          * can tack it on later.  Note that we
  810                          * will end up copying garbage in some
  811                          * cases but this is okay.  We remember
  812                          * where the buffer started so we can
  813                          * compute the new header length.
  814                          */
  815                         bcopy(sc->sc_pktstart, chdr, CHDR_LEN);
  816                 }
  817 #endif
  818 
  819                 if ((c = (*sc->sc_pktstart & 0xf0)) != (IPVERSION << 4)) {
  820                         if (c & 0x80)
  821                                 c = TYPE_COMPRESSED_TCP;
  822                         else if (c == TYPE_UNCOMPRESSED_TCP)
  823                                 *sc->sc_pktstart &= 0x4f; /* XXX */
  824                         /*
  825                          * We've got something that's not an IP packet.
  826                          * If compression is enabled, try to decompress it.
  827                          * Otherwise, if `auto-enable' compression is on and
  828                          * it's a reasonable packet, decompress it and then
  829                          * enable compression.  Otherwise, drop it.
  830                          */
  831                         if (sc->sc_if.if_flags & SC_COMPRESS) {
  832                                 len = sl_uncompress_tcp(&sc->sc_pktstart, len,
  833                                                         (u_int)c, &sc->sc_comp);
  834                                 if (len <= 0)
  835                                         goto error;
  836                         } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
  837                             c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
  838                                 len = sl_uncompress_tcp(&sc->sc_pktstart, len,
  839                                                         (u_int)c, &sc->sc_comp);
  840                                 if (len <= 0)
  841                                         goto error;
  842                                 sc->sc_if.if_flags |= SC_COMPRESS;
  843                         } else
  844                                 goto error;
  845                 }
  846 
  847                 m = sl_btom(sc, len);
  848                 if (m == NULL)
  849                         goto error;
  850 
  851 #if NBPFILTER > 0
  852                 if (sc->sc_bpf) {
  853                         /*
  854                          * Put the SLIP pseudo-"link header" in place.
  855                          * Note this M_PREPEND() should bever fail,
  856                          * since we know we always have enough space
  857                          * in the input buffer.
  858                          */
  859                         u_char *hp;
  860 
  861                         M_PREPEND(m, SLIP_HDRLEN, M_DONTWAIT);
  862                         if (m == NULL)
  863                                 goto error;
  864 
  865                         hp = mtod(m, u_char *);
  866                         hp[SLX_DIR] = SLIPDIR_IN;
  867                         memcpy(&hp[SLX_CHDR], chdr, CHDR_LEN);
  868 
  869                         s = splnet();
  870                         bpf_mtap(sc->sc_bpf, m, BPF_DIRECTION_IN);
  871                         splx(s);
  872 
  873                         m_adj(m, SLIP_HDRLEN);
  874                 }
  875 #endif
  876 
  877                 sc->sc_if.if_ipackets++;
  878                 getmicrotime(&sc->sc_lastpacket);
  879                 s = splnet();
  880                 if (IF_QFULL(&ipintrq)) {
  881                         IF_DROP(&ipintrq);
  882                         sc->sc_if.if_ierrors++;
  883                         sc->sc_if.if_iqdrops++;
  884                         m_freem(m);
  885                         if (!ipintrq.ifq_congestion)
  886                                 if_congestion(&ipintrq);
  887                 } else {
  888                         IF_ENQUEUE(&ipintrq, m);
  889                         schednetisr(NETISR_IP);
  890                 }
  891                 splx(s);
  892                 goto newpack;
  893         }
  894         if (sc->sc_mp < sc->sc_ep) {
  895                 *sc->sc_mp++ = c;
  896                 sc->sc_escape = 0;
  897                 return;
  898         }
  899 
  900         /* can't put lower; would miss an extra frame */
  901         sc->sc_flags |= SC_ERROR;
  902 
  903 error:
  904         sc->sc_if.if_ierrors++;
  905 newpack:
  906         sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  907             BUFOFFSET;
  908         sc->sc_escape = 0;
  909 }
  910 
  911 /*
  912  * Process an ioctl request.
  913  */
  914 int
  915 slioctl(ifp, cmd, data)
  916         struct ifnet *ifp;
  917         u_long cmd;
  918         caddr_t data;
  919 {
  920         struct sl_softc *sc = ifp->if_softc;
  921         struct ifaddr *ifa = (struct ifaddr *)data;
  922         struct ifreq *ifr;
  923         int s = splnet(), error = 0;
  924         struct sl_stats *slsp;
  925 
  926         switch (cmd) {
  927 
  928         case SIOCSIFADDR:
  929                 if (ifa->ifa_addr->sa_family == AF_INET)
  930                         ifp->if_flags |= IFF_UP;
  931                 else
  932                         error = EAFNOSUPPORT;
  933                 break;
  934 
  935         case SIOCSIFDSTADDR:
  936                 if (ifa->ifa_addr->sa_family != AF_INET)
  937                         error = EAFNOSUPPORT;
  938                 break;
  939 
  940         case SIOCADDMULTI:
  941         case SIOCDELMULTI:
  942                 ifr = (struct ifreq *)data;
  943                 if (ifr == 0) {
  944                         error = EAFNOSUPPORT;           /* XXX */
  945                         break;
  946                 }
  947                 switch (ifr->ifr_addr.sa_family) {
  948 
  949 #ifdef INET
  950                 case AF_INET:
  951                         break;
  952 #endif
  953 
  954                 default:
  955                         error = EAFNOSUPPORT;
  956                         break;
  957                 }
  958                 break;
  959 
  960         case SIOCGSLSTATS:
  961                 slsp = &((struct ifslstatsreq *) data)->stats;
  962                 bzero(slsp, sizeof(*slsp));
  963                 /* slsp->sl = sc->sc_stats; */
  964                 slsp->sl.sl_ibytes = sc->sc_if.if_ibytes;
  965                 slsp->sl.sl_obytes = sc->sc_if.if_obytes;
  966                 slsp->sl.sl_ipackets = sc->sc_if.if_ipackets;
  967                 slsp->sl.sl_opackets = sc->sc_if.if_opackets;
  968 #ifdef INET
  969                 slsp->vj.vjs_packets = sc->sc_comp.sls_packets;
  970                 slsp->vj.vjs_compressed = sc->sc_comp.sls_compressed;
  971                 slsp->vj.vjs_searches = sc->sc_comp.sls_searches;
  972                 slsp->vj.vjs_misses = sc->sc_comp.sls_misses;
  973                 slsp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin;
  974                 slsp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin;
  975                 slsp->vj.vjs_errorin = sc->sc_comp.sls_errorin;
  976                 slsp->vj.vjs_tossed = sc->sc_comp.sls_tossed;
  977 #endif /* INET */
  978                 break;
  979 
  980         default:
  981                 error = EINVAL;
  982         }
  983         splx(s);
  984         return (error);
  985 }

/* [<][>][^][v][top][bottom][index][help] */