[ 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  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  cheribsd  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD8-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  3  -  10 

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

Cache object: 899a35e2b3c842063513ef052b2cf67c


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