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

Cache object: 77694b3cd6019589c0f7f86f37b625d1


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