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.102 2006/11/16 01:33:40 christos 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.102 2006/11/16 01:33:40 christos Exp $");
   64 
   65 #include "opt_inet.h"
   66 #include "bpfilter.h"
   67 
   68 #include <sys/param.h>
   69 #include <sys/proc.h>
   70 #include <sys/malloc.h>
   71 #include <sys/mbuf.h>
   72 #include <sys/buf.h>
   73 #include <sys/dkstat.h>
   74 #include <sys/socket.h>
   75 #include <sys/ioctl.h>
   76 #include <sys/file.h>
   77 #include <sys/conf.h>
   78 #include <sys/tty.h>
   79 #include <sys/kernel.h>
   80 #if __NetBSD__
   81 #include <sys/systm.h>
   82 #include <sys/kauth.h>
   83 #endif
   84 
   85 #include <machine/cpu.h>
   86 #include <machine/intr.h>
   87 
   88 #include <net/if.h>
   89 #include <net/if_types.h>
   90 #include <net/netisr.h>
   91 #include <net/route.h>
   92 
   93 #ifdef INET
   94 #include <netinet/in.h>
   95 #include <netinet/in_systm.h>
   96 #include <netinet/in_var.h>
   97 #include <netinet/ip.h>
   98 #endif
   99 
  100 #include <net/slcompress.h>
  101 #include <net/if_slvar.h>
  102 #include <net/slip.h>
  103 #include <net/ppp_defs.h>
  104 #include <net/if_ppp.h>
  105 
  106 #if NBPFILTER > 0
  107 #include <sys/time.h>
  108 #include <net/bpf.h>
  109 #endif
  110 
  111 /*
  112  * SLMAX is a hard limit on input packet size.  To simplify the code
  113  * and improve performance, we require that packets fit in an mbuf
  114  * cluster, and if we get a compressed packet, there's enough extra
  115  * room to expand the header into a max length tcp/ip header (128
  116  * bytes).  So, SLMAX can be at most
  117  *      MCLBYTES - 128
  118  *
  119  * SLMTU is a hard limit on output packet size.  To insure good
  120  * interactive response, SLMTU wants to be the smallest size that
  121  * amortizes the header cost.  (Remember that even with
  122  * type-of-service queuing, we have to wait for any in-progress
  123  * packet to finish.  I.e., we wait, on the average, 1/2 * mtu /
  124  * cps, where cps is the line speed in characters per second.
  125  * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line.  The
  126  * average compressed header size is 6-8 bytes so any MTU > 90
  127  * bytes will give us 90% of the line bandwidth.  A 100ms wait is
  128  * tolerable (500ms is not), so want an MTU around 296.  (Since TCP
  129  * will send 256 byte segments (to allow for 40 byte headers), the
  130  * typical packet size on the wire will be around 260 bytes).  In
  131  * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
  132  * leave the interface MTU relatively high (so we don't IP fragment
  133  * when acting as a gateway to someone using a stupid MTU).
  134  *
  135  * Similar considerations apply to SLIP_HIWAT:  It's the amount of
  136  * data that will be queued 'downstream' of us (i.e., in clists
  137  * waiting to be picked up by the tty output interrupt).  If we
  138  * queue a lot of data downstream, it's immune to 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 #define BUFOFFSET       (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
  152 #define SLMAX           (MCLBYTES - BUFOFFSET)
  153 #define SLBUFSIZE       (SLMAX + BUFOFFSET)
  154 #ifndef SLMTU
  155 #define SLMTU           296
  156 #endif
  157 #if (SLMTU < 3)
  158 #error SLMTU way too small.
  159 #endif
  160 #define SLIP_HIWAT      roundup(50,CBSIZE)
  161 #ifndef __NetBSD__                                      /* XXX - cgd */
  162 #define CLISTRESERVE    1024    /* Can't let clists get too low */
  163 #endif  /* !__NetBSD__ */
  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 int              sl_clone_create(struct if_clone *, int);
  178 static int              sl_clone_destroy(struct ifnet *);
  179 
  180 static LIST_HEAD(, sl_softc) sl_softc_list;
  181 
  182 struct if_clone sl_cloner =
  183     IF_CLONE_INITIALIZER("sl", sl_clone_create, sl_clone_destroy);
  184 
  185 #define FRAME_END               0xc0            /* Frame End */
  186 #define FRAME_ESCAPE            0xdb            /* Frame Esc */
  187 #define TRANS_FRAME_END         0xdc            /* transposed frame end */
  188 #define TRANS_FRAME_ESCAPE      0xdd            /* transposed frame esc */
  189 
  190 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
  191 void    slnetisr(void);
  192 #endif
  193 static void     slintr(void *);
  194 
  195 static int      slinit(struct sl_softc *);
  196 static struct mbuf *sl_btom(struct sl_softc *, int);
  197 
  198 static int      slclose(struct tty *, int);
  199 static int      slinput(int, struct tty *);
  200 static int      slioctl(struct ifnet *, u_long, caddr_t);
  201 static int      slopen(dev_t, struct tty *);
  202 static int      sloutput(struct ifnet *, struct mbuf *, struct sockaddr *,
  203                          struct rtentry *);
  204 static int      slstart(struct tty *);
  205 static int      sltioctl(struct tty *, u_long, caddr_t, int, struct lwp *);
  206 
  207 static struct linesw slip_disc = {
  208         .l_name = "slip",
  209         .l_open = slopen,
  210         .l_close = slclose,
  211         .l_read = ttyerrio,
  212         .l_write = ttyerrio,
  213         .l_ioctl = sltioctl,
  214         .l_rint = slinput,
  215         .l_start = slstart,
  216         .l_modem = nullmodem,
  217         .l_poll = ttyerrpoll
  218 };
  219 
  220 void    slattach(void);
  221 
  222 void
  223 slattach(void)
  224 {
  225 
  226         if (ttyldisc_attach(&slip_disc) != 0)
  227                 panic("slattach");
  228         LIST_INIT(&sl_softc_list);
  229         if_clone_attach(&sl_cloner);
  230 }
  231 
  232 static int
  233 sl_clone_create(struct if_clone *ifc, int unit)
  234 {
  235         struct sl_softc *sc;
  236 
  237         MALLOC(sc, struct sl_softc *, sizeof(*sc), M_DEVBUF, M_WAIT|M_ZERO);
  238         sc->sc_unit = unit;
  239         (void)snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname),
  240             "%s%d", ifc->ifc_name, unit);
  241         sc->sc_if.if_softc = sc;
  242         sc->sc_if.if_mtu = SLMTU;
  243         sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
  244         sc->sc_if.if_type = IFT_SLIP;
  245         sc->sc_if.if_ioctl = slioctl;
  246         sc->sc_if.if_output = sloutput;
  247         sc->sc_if.if_dlt = DLT_SLIP;
  248         sc->sc_fastq.ifq_maxlen = 32;
  249         IFQ_SET_READY(&sc->sc_if.if_snd);
  250         if_attach(&sc->sc_if);
  251         if_alloc_sadl(&sc->sc_if);
  252 #if NBPFILTER > 0
  253         bpfattach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
  254 #endif
  255         LIST_INSERT_HEAD(&sl_softc_list, sc, sc_iflist);
  256         return 0;
  257 }
  258 
  259 static int
  260 sl_clone_destroy(struct ifnet *ifp)
  261 {
  262         struct sl_softc *sc = (struct sl_softc *)ifp->if_softc;
  263 
  264         if (sc->sc_ttyp != NULL)
  265                 return EBUSY;   /* Not removing it */
  266 
  267         LIST_REMOVE(sc, sc_iflist);
  268 
  269 #if NBPFILTER > 0
  270         bpfdetach(ifp);
  271 #endif
  272         if_detach(ifp);
  273 
  274         FREE(sc, M_DEVBUF);
  275         return 0;
  276 }
  277 
  278 static int
  279 slinit(struct sl_softc *sc)
  280 {
  281 
  282         if (sc->sc_mbuf == NULL) {
  283                 sc->sc_mbuf = m_gethdr(M_WAIT, MT_DATA);
  284                 m_clget(sc->sc_mbuf, M_WAIT);
  285         }
  286         sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
  287             sc->sc_mbuf->m_ext.ext_size;
  288         sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
  289             BUFOFFSET;
  290 
  291 #ifdef INET
  292         sl_compress_init(&sc->sc_comp);
  293 #endif
  294 
  295         return 1;
  296 }
  297 
  298 /*
  299  * Line specific open routine.
  300  * Attach the given tty to the first available sl unit.
  301  */
  302 /* ARGSUSED */
  303 static int
  304 slopen(dev_t dev, struct tty *tp)
  305 {
  306         struct lwp *l = curlwp;         /* XXX */
  307         struct sl_softc *sc;
  308         int error;
  309         int s;
  310 
  311         if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  312             &l->l_acflag)) != 0)
  313                 return error;
  314 
  315         if (tp->t_linesw == &slip_disc)
  316                 return 0;
  317 
  318         LIST_FOREACH(sc, &sl_softc_list, sc_iflist)
  319                 if (sc->sc_ttyp == NULL) {
  320 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  321                         sc->sc_si = softintr_establish(IPL_SOFTNET,
  322                             slintr, sc);
  323                         if (sc->sc_si == NULL)
  324                                 return ENOMEM;
  325 #endif
  326                         if (slinit(sc) == 0) {
  327 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  328                                 softintr_disestablish(sc->sc_si);
  329 #endif
  330                                 return ENOBUFS;
  331                         }
  332                         tp->t_sc = (caddr_t)sc;
  333                         sc->sc_ttyp = tp;
  334                         sc->sc_if.if_baudrate = tp->t_ospeed;
  335                         s = spltty();
  336                         tp->t_state |= TS_ISOPEN | TS_XCLUDE;
  337                         splx(s);
  338                         ttyflush(tp, FREAD | FWRITE);
  339 #ifdef __NetBSD__
  340                         /*
  341                          * make sure tty output queue is large enough
  342                          * to hold a full-sized packet (including frame
  343                          * end, and a possible extra frame end).  full-sized
  344                          * packet occupies a max of 2*SLMAX bytes (because
  345                          * of possible escapes), and add two on for frame
  346                          * ends.
  347                          */
  348                         s = spltty();
  349                         if (tp->t_outq.c_cn < 2 * SLMAX + 2) {
  350                                 sc->sc_oldbufsize = tp->t_outq.c_cn;
  351                                 sc->sc_oldbufquot = tp->t_outq.c_cq != 0;
  352 
  353                                 clfree(&tp->t_outq);
  354                                 error = clalloc(&tp->t_outq, 2 * SLMAX + 2, 0);
  355                                 if (error) {
  356                                         splx(s);
  357 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  358                                         softintr_disestablish(sc->sc_si);
  359 #endif
  360                                         /*
  361                                          * clalloc() might return -1 which
  362                                          * is no good, so we need to return
  363                                          * something else.
  364                                          */
  365                                         return ENOMEM; /* XXX ?! */
  366                                 }
  367                         } else
  368                                 sc->sc_oldbufsize = sc->sc_oldbufquot = 0;
  369                         splx(s);
  370 #endif /* __NetBSD__ */
  371                         return 0;
  372                 }
  373         return ENXIO;
  374 }
  375 
  376 /*
  377  * Line specific close routine.
  378  * Detach the tty from the sl unit.
  379  */
  380 static int
  381 slclose(struct tty *tp, int flag)
  382 {
  383         struct sl_softc *sc;
  384         int s;
  385 
  386         ttywflush(tp);
  387         sc = tp->t_sc;
  388 
  389         if (sc != NULL) {
  390 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  391                 softintr_disestablish(sc->sc_si);
  392 #endif
  393                 s = splnet();
  394                 if_down(&sc->sc_if);
  395                 IF_PURGE(&sc->sc_fastq);
  396                 splx(s);
  397 
  398                 s = spltty();
  399                 ttyldisc_release(tp->t_linesw);
  400                 tp->t_linesw = ttyldisc_default();
  401                 tp->t_state = 0;
  402 
  403                 sc->sc_ttyp = NULL;
  404                 tp->t_sc = NULL;
  405 
  406                 m_freem(sc->sc_mbuf);
  407                 sc->sc_mbuf = NULL;
  408                 sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL;
  409                 IF_PURGE(&sc->sc_inq);
  410 
  411                 /*
  412                  * If necessary, install a new outq buffer of the
  413                  * appropriate size.
  414                  */
  415                 if (sc->sc_oldbufsize != 0) {
  416                         clfree(&tp->t_outq);
  417                         clalloc(&tp->t_outq, sc->sc_oldbufsize,
  418                             sc->sc_oldbufquot);
  419                 }
  420                 splx(s);
  421         }
  422 
  423         return 0;
  424 }
  425 
  426 /*
  427  * Line specific (tty) ioctl routine.
  428  * Provide a way to get the sl unit number.
  429  */
  430 /* ARGSUSED */
  431 static int
  432 sltioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
  433     struct lwp *l)
  434 {
  435         struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
  436 
  437         switch (cmd) {
  438         case SLIOCGUNIT:
  439                 *(int *)data = sc->sc_unit;     /* XXX */
  440                 break;
  441 
  442         default:
  443                 return EPASSTHROUGH;
  444         }
  445         return 0;
  446 }
  447 
  448 /*
  449  * Queue a packet.  Start transmission if not active.
  450  * Compression happens in slintr(); if we do it here, IP TOS
  451  * will cause us to not compress "background" packets, because
  452  * ordering gets trashed.  It can be done for all packets in slintr().
  453  */
  454 static int
  455 sloutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  456     struct rtentry *rtp)
  457 {
  458         struct sl_softc *sc = ifp->if_softc;
  459         struct ip *ip;
  460         struct ifqueue *ifq = NULL;
  461         int s, error;
  462         ALTQ_DECL(struct altq_pktattr pktattr;)
  463 
  464         IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
  465 
  466         /*
  467          * `Cannot happen' (see slioctl).  Someday we will extend
  468          * the line protocol to support other address families.
  469          */
  470         if (dst->sa_family != AF_INET) {
  471                 printf("%s: af%d not supported\n", sc->sc_if.if_xname,
  472                     dst->sa_family);
  473                 m_freem(m);
  474                 sc->sc_if.if_noproto++;
  475                 return EAFNOSUPPORT;
  476         }
  477 
  478         if (sc->sc_ttyp == NULL) {
  479                 m_freem(m);
  480                 return ENETDOWN;        /* sort of */
  481         }
  482         if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
  483             (sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
  484                 m_freem(m);
  485                 printf("%s: no carrier and not local\n", sc->sc_if.if_xname);
  486                 return EHOSTUNREACH;
  487         }
  488         ip = mtod(m, struct ip *);
  489 #ifdef INET
  490         if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
  491                 m_freem(m);
  492                 return ENETRESET;               /* XXX ? */
  493         }
  494 #endif
  495 
  496         s = spltty();
  497         if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
  498                 struct bintime bt;
  499 
  500                 /* if output's been stalled for too long, and restart */
  501                 getbinuptime(&bt);
  502                 bintime_sub(&bt, &sc->sc_lastpacket);
  503                 if (bt.sec > 0) {
  504                         sc->sc_otimeout++;
  505                         slstart(sc->sc_ttyp);
  506                 }
  507         }
  508         splx(s);
  509 
  510         s = splnet();
  511 #ifdef INET
  512         if ((ip->ip_tos & IPTOS_LOWDELAY) != 0)
  513                 ifq = &sc->sc_fastq;
  514 #endif
  515         if ((error = ifq_enqueue2(ifp, ifq, m ALTQ_COMMA
  516             ALTQ_DECL(&pktattr))) != 0) {
  517                 splx(s);
  518                 return error;
  519         }
  520         getbinuptime(&sc->sc_lastpacket);
  521         splx(s);
  522 
  523         s = spltty();
  524         if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0)
  525                 slstart(sc->sc_ttyp);
  526         splx(s);
  527 
  528         return 0;
  529 }
  530 
  531 /*
  532  * Start output on interface.  Get another datagram
  533  * to send from the interface queue and map it to
  534  * the interface before starting output.
  535  */
  536 static int
  537 slstart(struct tty *tp)
  538 {
  539         struct sl_softc *sc = tp->t_sc;
  540 
  541         /*
  542          * If there is more in the output queue, just send it now.
  543          * We are being called in lieu of ttstart and must do what
  544          * it would.
  545          */
  546         if (tp->t_outq.c_cc != 0) {
  547                 (*tp->t_oproc)(tp);
  548                 if (tp->t_outq.c_cc > SLIP_HIWAT)
  549                         return 0;
  550         }
  551 
  552         /*
  553          * This happens briefly when the line shuts down.
  554          */
  555         if (sc == NULL)
  556                 return 0;
  557 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  558         softintr_schedule(sc->sc_si);
  559 #else
  560     {
  561         int s = splhigh();
  562         schednetisr(NETISR_SLIP);
  563         splx(s);
  564     }
  565 #endif
  566         return 0;
  567 }
  568 
  569 /*
  570  * Copy data buffer to mbuf chain; add ifnet pointer.
  571  */
  572 static struct mbuf *
  573 sl_btom(struct sl_softc *sc, int len)
  574 {
  575         struct mbuf *m;
  576 
  577         /*
  578          * Allocate a new input buffer and swap.
  579          */
  580         m = sc->sc_mbuf;
  581         MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA);
  582         if (sc->sc_mbuf == NULL) {
  583                 sc->sc_mbuf = m;
  584                 return NULL;
  585         }
  586         MCLGET(sc->sc_mbuf, M_DONTWAIT);
  587         if ((sc->sc_mbuf->m_flags & M_EXT) == 0) {
  588                 m_freem(sc->sc_mbuf);
  589                 sc->sc_mbuf = m;
  590                 return NULL;
  591         }
  592         sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
  593             sc->sc_mbuf->m_ext.ext_size;
  594 
  595         m->m_data = sc->sc_pktstart;
  596 
  597         m->m_pkthdr.len = m->m_len = len;
  598         m->m_pkthdr.rcvif = &sc->sc_if;
  599         return m;
  600 }
  601 
  602 /*
  603  * tty interface receiver interrupt.
  604  */
  605 static int
  606 slinput(int c, struct tty *tp)
  607 {
  608         struct sl_softc *sc;
  609         struct mbuf *m;
  610         int len;
  611 
  612         tk_nin++;
  613         sc = (struct sl_softc *)tp->t_sc;
  614         if (sc == NULL)
  615                 return 0;
  616         if ((c & TTY_ERRORMASK) || ((tp->t_state & TS_CARR_ON) == 0 &&
  617             (tp->t_cflag & CLOCAL) == 0)) {
  618                 sc->sc_flags |= SC_ERROR;
  619                 return 0;
  620         }
  621         c &= TTY_CHARMASK;
  622 
  623         ++sc->sc_if.if_ibytes;
  624 
  625         if (sc->sc_if.if_flags & IFF_DEBUG) {
  626                 if (c == ABT_ESC) {
  627                         /*
  628                          * If we have a previous abort, see whether
  629                          * this one is within the time limit.
  630                          */
  631                         if (sc->sc_abortcount &&
  632                             time_second >= sc->sc_starttime + ABT_WINDOW)
  633                                 sc->sc_abortcount = 0;
  634                         /*
  635                          * If we see an abort after "idle" time, count it;
  636                          * record when the first abort escape arrived.
  637                          */
  638                         if (time_second >= sc->sc_lasttime + ABT_IDLE) {
  639                                 if (++sc->sc_abortcount == 1)
  640                                         sc->sc_starttime = time_second;
  641                                 if (sc->sc_abortcount >= ABT_COUNT) {
  642                                         slclose(tp, 0);
  643                                         return 0;
  644                                 }
  645                         }
  646                 } else
  647                         sc->sc_abortcount = 0;
  648                 sc->sc_lasttime = time_second;
  649         }
  650 
  651         switch (c) {
  652 
  653         case TRANS_FRAME_ESCAPE:
  654                 if (sc->sc_escape)
  655                         c = FRAME_ESCAPE;
  656                 break;
  657 
  658         case TRANS_FRAME_END:
  659                 if (sc->sc_escape)
  660                         c = FRAME_END;
  661                 break;
  662 
  663         case FRAME_ESCAPE:
  664                 sc->sc_escape = 1;
  665                 return 0;
  666 
  667         case FRAME_END:
  668                 if (sc->sc_flags & SC_ERROR) {
  669                         sc->sc_flags &= ~SC_ERROR;
  670                         goto newpack;
  671                 }
  672                 len = sc->sc_mp - sc->sc_pktstart;
  673                 if (len < 3)
  674                         /* less than min length packet - ignore */
  675                         goto newpack;
  676 
  677                 m = sl_btom(sc, len);
  678                 if (m == NULL)
  679                         goto error;
  680 
  681                 IF_ENQUEUE(&sc->sc_inq, m);
  682 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  683                 softintr_schedule(sc->sc_si);
  684 #else
  685             {
  686                 int s = splhigh();
  687                 schednetisr(NETISR_SLIP);
  688                 splx(s);
  689             }
  690 #endif
  691                 goto newpack;
  692         }
  693         if (sc->sc_mp < sc->sc_ep) {
  694                 *sc->sc_mp++ = c;
  695                 sc->sc_escape = 0;
  696                 return 0;
  697         }
  698 
  699         /* can't put lower; would miss an extra frame */
  700         sc->sc_flags |= SC_ERROR;
  701 
  702 error:
  703         sc->sc_if.if_ierrors++;
  704 newpack:
  705         sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
  706             BUFOFFSET;
  707         sc->sc_escape = 0;
  708 
  709         return 0;
  710 }
  711 
  712 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
  713 void
  714 slnetisr(void)
  715 {
  716         struct sl_softc *sc;
  717 
  718         LIST_FOREACH(sc, &sl_softc_list, sc_iflist) {
  719                 if (sc->sc_ttyp == NULL)
  720                         continue;
  721                 slintr(sc);
  722         }
  723 }
  724 #endif
  725 
  726 static void
  727 slintr(void *arg)
  728 {
  729         struct sl_softc *sc = arg;
  730         struct tty *tp = sc->sc_ttyp;
  731         struct mbuf *m;
  732         int s, len;
  733         u_char *pktstart;
  734 #ifdef INET
  735         u_char c;
  736 #endif
  737 #if NBPFILTER > 0
  738         u_char chdr[CHDR_LEN];
  739 #endif
  740 
  741         KASSERT(tp != NULL);
  742 
  743         /*
  744          * Output processing loop.
  745          */
  746         for (;;) {
  747 #ifdef INET
  748                 struct ip *ip;
  749 #endif
  750                 struct mbuf *m2;
  751 #if NBPFILTER > 0
  752                 struct mbuf *bpf_m;
  753 #endif
  754 
  755                 /*
  756                  * Do not remove the packet from the queue if it
  757                  * doesn't look like it will fit into the current
  758                  * serial output queue.  With a packet full of
  759                  * escapes, this could be as bad as MTU*2+2.
  760                  */
  761                 s = spltty();
  762                 if (tp->t_outq.c_cn - tp->t_outq.c_cc <
  763                     2 * sc->sc_if.if_mtu + 2) {
  764                         splx(s);
  765                         break;
  766                 }
  767                 splx(s);
  768 
  769                 /*
  770                  * Get a packet and send it to the interface.
  771                  */
  772                 s = splnet();
  773                 IF_DEQUEUE(&sc->sc_fastq, m);
  774                 if (m)
  775                         sc->sc_if.if_omcasts++; /* XXX */
  776                 else
  777                         IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
  778                 splx(s);
  779 
  780                 if (m == NULL)
  781                         break;
  782 
  783                 /*
  784                  * We do the header compression here rather than in
  785                  * sloutput() because the packets will be out of order
  786                  * if we are using TOS queueing, and the connection
  787                  * ID compression will get munged when this happens.
  788                  */
  789 #if NBPFILTER > 0
  790                 if (sc->sc_if.if_bpf) {
  791                         /*
  792                          * We need to save the TCP/IP header before
  793                          * it's compressed.  To avoid complicated
  794                          * code, we just make a deep copy of the
  795                          * entire packet (since this is a serial
  796                          * line, packets should be short and/or the
  797                          * copy should be negligible cost compared
  798                          * to the packet transmission time).
  799                          */
  800                         bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT);
  801                 } else
  802                         bpf_m = NULL;
  803 #endif
  804 #ifdef INET
  805                 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
  806                         if (sc->sc_if.if_flags & SC_COMPRESS)
  807                                 *mtod(m, u_char *) |=
  808                                     sl_compress_tcp(m, ip, &sc->sc_comp, 1);
  809                 }
  810 #endif
  811 #if NBPFILTER > 0
  812                 if (sc->sc_if.if_bpf && bpf_m != NULL)
  813                         bpf_mtap_sl_out(sc->sc_if.if_bpf, mtod(m, u_char *),
  814                             bpf_m);
  815 #endif
  816                 getbinuptime(&sc->sc_lastpacket);
  817 
  818                 s = spltty();
  819 
  820                 /*
  821                  * The extra FRAME_END will start up a new packet,
  822                  * and thus will flush any accumulated garbage.  We
  823                  * do this whenever the line may have been idle for
  824                  * some time.
  825                  */
  826                 if (tp->t_outq.c_cc == 0) {
  827                         sc->sc_if.if_obytes++;
  828                         (void)putc(FRAME_END, &tp->t_outq);
  829                 }
  830 
  831                 while (m) {
  832                         u_char *bp, *cp, *ep;
  833 
  834                         bp = cp = mtod(m, u_char *);
  835                         ep = cp + m->m_len;
  836                         while (cp < ep) {
  837                                 /*
  838                                  * Find out how many bytes in the
  839                                  * string we can handle without
  840                                  * doing something special.
  841                                  */
  842                                 while (cp < ep) {
  843                                         switch (*cp++) {
  844                                         case FRAME_ESCAPE:
  845                                         case FRAME_END:
  846                                                 cp--;
  847                                                 goto out;
  848                                         }
  849                                 }
  850                                 out:
  851                                 if (cp > bp) {
  852                                         /*
  853                                          * Put N characters at once
  854                                          * into the tty output queue.
  855                                          */
  856                                         if (b_to_q(bp, cp - bp, &tp->t_outq))
  857                                                 break;
  858                                         sc->sc_if.if_obytes += cp - bp;
  859                                 }
  860                                 /*
  861                                  * If there are characters left in
  862                                  * the mbuf, the first one must be
  863                                  * special..  Put it out in a different
  864                                  * form.
  865                                  */
  866                                 if (cp < ep) {
  867                                         if (putc(FRAME_ESCAPE, &tp->t_outq))
  868                                                 break;
  869                                         if (putc(*cp++ == FRAME_ESCAPE ?
  870                                             TRANS_FRAME_ESCAPE :
  871                                             TRANS_FRAME_END,
  872                                             &tp->t_outq)) {
  873                                                 (void)unputc(&tp->t_outq);
  874                                                 break;
  875                                         }
  876                                         sc->sc_if.if_obytes += 2;
  877                                 }
  878                                 bp = cp;
  879                         }
  880                         MFREE(m, m2);
  881                         m = m2;
  882                 }
  883 
  884                 if (putc(FRAME_END, &tp->t_outq)) {
  885                         /*
  886                          * Not enough room.  Remove a char to make
  887                          * room and end the packet normally.  If
  888                          * you get many collisions (more than one
  889                          * or two a day), you probably do not have
  890                          * enough clists and you should increase
  891                          * "nclist" in param.c
  892                          */
  893                         (void)unputc(&tp->t_outq);
  894                         (void)putc(FRAME_END, &tp->t_outq);
  895                         sc->sc_if.if_collisions++;
  896                 } else {
  897                         sc->sc_if.if_obytes++;
  898                         sc->sc_if.if_opackets++;
  899                 }
  900 
  901                 /*
  902                  * We now have characters in the output queue,
  903                  * kick the serial port.
  904                  */
  905                 (*tp->t_oproc)(tp);
  906                 splx(s);
  907         }
  908 
  909         /*
  910          * Input processing loop.
  911          */
  912         for (;;) {
  913                 s = spltty();
  914                 IF_DEQUEUE(&sc->sc_inq, m);
  915                 splx(s);
  916                 if (m == NULL)
  917                         break;
  918                 pktstart = mtod(m, u_char *);
  919                 len = m->m_pkthdr.len;
  920 #if NBPFILTER > 0
  921                 if (sc->sc_if.if_bpf) {
  922                         /*
  923                          * Save the compressed header, so we
  924                          * can tack it on later.  Note that we
  925                          * will end up copying garbage in some
  926                          * cases but this is okay.  We remember
  927                          * where the buffer started so we can
  928                          * compute the new header length.
  929                          */
  930                         memcpy(chdr, pktstart, CHDR_LEN);
  931                 }
  932 #endif /* NBPFILTER > 0 */
  933 #ifdef INET
  934                 if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) {
  935                         if (c & 0x80)
  936                                 c = TYPE_COMPRESSED_TCP;
  937                         else if (c == TYPE_UNCOMPRESSED_TCP)
  938                                 *pktstart &= 0x4f; /* XXX */
  939                         /*
  940                          * We've got something that's not an IP
  941                          * packet.  If compression is enabled,
  942                          * try to decompress it.  Otherwise, if
  943                          * `auto-enable' compression is on and
  944                          * it's a reasonable packet, decompress
  945                          * it and then enable compression.
  946                          * Otherwise, drop it.
  947                          */
  948                         if (sc->sc_if.if_flags & SC_COMPRESS) {
  949                                 len = sl_uncompress_tcp(&pktstart, len,
  950                                     (u_int)c, &sc->sc_comp);
  951                                 if (len <= 0) {
  952                                         m_freem(m);
  953                                         continue;
  954                                 }
  955                         } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
  956                             c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
  957                                 len = sl_uncompress_tcp(&pktstart, len,
  958                                     (u_int)c, &sc->sc_comp);
  959                                 if (len <= 0) {
  960                                         m_freem(m);
  961                                         continue;
  962                                 }
  963                                 sc->sc_if.if_flags |= SC_COMPRESS;
  964                         } else {
  965                                 m_freem(m);
  966                                 continue;
  967                         }
  968                 }
  969 #endif
  970                 m->m_data = (caddr_t) pktstart;
  971                 m->m_pkthdr.len = m->m_len = len;
  972 #if NBPFILTER > 0
  973                 if (sc->sc_if.if_bpf) {
  974                         bpf_mtap_sl_in(sc->sc_if.if_bpf, chdr, &m);
  975                         if (m == NULL)
  976                                 continue;
  977                 }
  978 #endif /* NBPFILTER > 0 */
  979                 /*
  980                  * If the packet will fit into a single
  981                  * header mbuf, copy it into one, to save
  982                  * memory.
  983                  */
  984                 if (m->m_pkthdr.len < MHLEN) {
  985                         struct mbuf *n;
  986                         int pktlen;
  987 
  988                         MGETHDR(n, M_DONTWAIT, MT_DATA);
  989                         pktlen = m->m_pkthdr.len;
  990                         M_MOVE_PKTHDR(n, m);
  991                         memcpy(mtod(n, caddr_t), mtod(m, caddr_t), pktlen);
  992                         n->m_len = m->m_len;
  993                         m_freem(m);
  994                         m = n;
  995                 }
  996 
  997                 sc->sc_if.if_ipackets++;
  998                 getbinuptime(&sc->sc_lastpacket);
  999 
 1000 #ifdef INET
 1001                 s = splnet();
 1002                 if (IF_QFULL(&ipintrq)) {
 1003                         IF_DROP(&ipintrq);
 1004                         sc->sc_if.if_ierrors++;
 1005                         sc->sc_if.if_iqdrops++;
 1006                         m_freem(m);
 1007                 } else {
 1008                         IF_ENQUEUE(&ipintrq, m);
 1009                         schednetisr(NETISR_IP);
 1010                 }
 1011                 splx(s);
 1012 #endif
 1013         }
 1014 }
 1015 
 1016 /*
 1017  * Process an ioctl request.
 1018  */
 1019 static int
 1020 slioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1021 {
 1022         struct ifaddr *ifa = (struct ifaddr *)data;
 1023         struct ifreq *ifr = (struct ifreq *)data;
 1024         int s = splnet(), error = 0;
 1025         struct sl_softc *sc = ifp->if_softc;
 1026         struct ppp_stats *psp;
 1027         struct ppp_comp_stats *pcp;
 1028 
 1029         switch (cmd) {
 1030 
 1031         case SIOCSIFADDR:
 1032                 if (ifa->ifa_addr->sa_family == AF_INET)
 1033                         ifp->if_flags |= IFF_UP;
 1034                 else
 1035                         error = EAFNOSUPPORT;
 1036                 break;
 1037 
 1038         case SIOCSIFDSTADDR:
 1039                 if (ifa->ifa_addr->sa_family != AF_INET)
 1040                         error = EAFNOSUPPORT;
 1041                 break;
 1042 
 1043         case SIOCSIFMTU:
 1044                 if ((ifr->ifr_mtu < 3) || (ifr->ifr_mtu > SLMAX)) {
 1045                     error = EINVAL;
 1046                     break;
 1047                 }
 1048                 sc->sc_if.if_mtu = ifr->ifr_mtu;
 1049                 break;
 1050 
 1051         case SIOCGIFMTU:
 1052                 ifr->ifr_mtu = sc->sc_if.if_mtu;
 1053                 break;
 1054 
 1055         case SIOCADDMULTI:
 1056         case SIOCDELMULTI:
 1057                 if (ifr == 0) {
 1058                         error = EAFNOSUPPORT;           /* XXX */
 1059                         break;
 1060                 }
 1061                 switch (ifr->ifr_addr.sa_family) {
 1062 
 1063 #ifdef INET
 1064                 case AF_INET:
 1065                         break;
 1066 #endif
 1067 
 1068                 default:
 1069                         error = EAFNOSUPPORT;
 1070                         break;
 1071                 }
 1072                 break;
 1073 
 1074         case SIOCGPPPSTATS:
 1075                 psp = &((struct ifpppstatsreq *) data)->stats;
 1076                 (void)memset(psp, 0, sizeof(*psp));
 1077                 psp->p.ppp_ibytes = sc->sc_if.if_ibytes;
 1078                 psp->p.ppp_ipackets = sc->sc_if.if_ipackets;
 1079                 psp->p.ppp_ierrors = sc->sc_if.if_ierrors;
 1080                 psp->p.ppp_obytes = sc->sc_if.if_obytes;
 1081                 psp->p.ppp_opackets = sc->sc_if.if_opackets;
 1082                 psp->p.ppp_oerrors = sc->sc_if.if_oerrors;
 1083 #ifdef INET
 1084                 psp->vj.vjs_packets = sc->sc_comp.sls_packets;
 1085                 psp->vj.vjs_compressed = sc->sc_comp.sls_compressed;
 1086                 psp->vj.vjs_searches = sc->sc_comp.sls_searches;
 1087                 psp->vj.vjs_misses = sc->sc_comp.sls_misses;
 1088                 psp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin;
 1089                 psp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin;
 1090                 psp->vj.vjs_errorin = sc->sc_comp.sls_errorin;
 1091                 psp->vj.vjs_tossed = sc->sc_comp.sls_tossed;
 1092 #endif
 1093                 break;
 1094 
 1095         case SIOCGPPPCSTATS:
 1096                 pcp = &((struct ifpppcstatsreq *) data)->stats;
 1097                 (void)memset(pcp, 0, sizeof(*pcp));
 1098                 break;
 1099 
 1100         default:
 1101                 error = EINVAL;
 1102         }
 1103         splx(s);
 1104         return error;
 1105 }

Cache object: 9db513f909ae63a248add9d7725bab09


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