The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_sl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: b7c735ed4beebe906472fba7666aad50


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.