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

Cache object: c878e45df672d26ba4992c76c11de669


[ 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.