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

Cache object: 26ef7470568c2c078e5a5efc1780d2e4


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