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_strip.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_strip.c,v 1.69 2006/11/16 01:33:40 christos Exp $   */
    2 /*      from: NetBSD: if_sl.c,v 1.38 1996/02/13 22:00:23 christos Exp $ */
    3 
    4 /*
    5  * Copyright 1996 The Board of Trustees of The Leland Stanford
    6  * Junior University. All Rights Reserved.
    7  *
    8  * Permission to use, copy, modify, and distribute this
    9  * software and its documentation for any purpose and without
   10  * fee is hereby granted, provided that the above copyright
   11  * notice appear in all copies.  Stanford University
   12  * makes no representations about the suitability of this
   13  * software for any purpose.  It is provided "as is" without
   14  * express or implied warranty.
   15  *
   16  *
   17  * This driver was contributed by Jonathan Stone.
   18  *
   19  * Starmode Radio IP interface (STRIP) for Metricom wireless radio.
   20  * This STRIP driver assumes address resolution of IP addresses to
   21  * Metricom MAC addresses is done via local link-level routes.
   22  * The link-level addresses are entered as an 8-digit packed BCD number.
   23  * To add a route for a radio at IP address 10.1.2.3, with radio
   24  * address '1234-5678', reachable via interface strip0, use the command
   25  *
   26  *      route add -host 10.1.2.3  -link strip0:12:34:56:78
   27  */
   28 
   29 
   30 /*
   31  * Copyright (c) 1987, 1989, 1992, 1993
   32  *      The Regents of the University of California.  All rights reserved.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  * 3. Neither the name of the University nor the names of its contributors
   43  *    may be used to endorse or promote products derived from this software
   44  *    without specific prior written permission.
   45  *
   46  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   56  * SUCH DAMAGE.
   57  *
   58  *      @(#)if_sl.c     8.6 (Berkeley) 2/1/94
   59  */
   60 
   61 /*
   62  * Derived from: Serial Line interface written by Rick Adams (rick@seismo.gov)
   63  *
   64  * Rick Adams
   65  * Center for Seismic Studies
   66  * 1300 N 17th Street, Suite 1450
   67  * Arlington, Virginia 22209
   68  * (703)276-7900
   69  * rick@seismo.ARPA
   70  * seismo!rick
   71  *
   72  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
   73  * N.B.: this belongs in netinet, not net, the way it stands now.
   74  * Should have a link-layer type designation, but wouldn't be
   75  * backwards-compatible.
   76  *
   77  * Converted to 4.3BSD Beta by Chris Torek.
   78  * Other changes made at Berkeley, based in part on code by Kirk Smith.
   79  * W. Jolitz added slip abort.
   80  *
   81  * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov).
   82  * Added priority queuing for "interactive" traffic; hooks for TCP
   83  * header compression; ICMP filtering (at 2400 baud, some cretin
   84  * pinging you can use up all your bandwidth).  Made low clist behavior
   85  * more robust and slightly less likely to hang serial line.
   86  * Sped up a bunch of things.
   87  */
   88 
   89 #include <sys/cdefs.h>
   90 __KERNEL_RCSID(0, "$NetBSD: if_strip.c,v 1.69 2006/11/16 01:33:40 christos Exp $");
   91 
   92 #include "opt_inet.h"
   93 #include "bpfilter.h"
   94 
   95 #include <sys/param.h>
   96 #include <sys/proc.h>
   97 #include <sys/mbuf.h>
   98 #include <sys/buf.h>
   99 #include <sys/dkstat.h>
  100 #include <sys/socket.h>
  101 #include <sys/ioctl.h>
  102 #include <sys/file.h>
  103 #include <sys/conf.h>
  104 #include <sys/tty.h>
  105 #include <sys/kernel.h>
  106 #if __NetBSD__
  107 #include <sys/systm.h>
  108 #include <sys/callout.h>
  109 #include <sys/kauth.h>
  110 #endif
  111 #include <sys/syslog.h>
  112 
  113 #include <machine/cpu.h>
  114 #include <machine/intr.h>
  115 
  116 #include <net/if.h>
  117 #include <net/if_dl.h>
  118 #include <net/if_types.h>
  119 #include <net/netisr.h>
  120 #include <net/route.h>
  121 
  122 #ifdef INET
  123 #include <netinet/in.h>
  124 #include <netinet/in_systm.h>
  125 #include <netinet/in_var.h>
  126 #include <netinet/ip.h>
  127 #endif
  128 
  129 #include <net/slcompress.h>
  130 #include <net/if_stripvar.h>
  131 #include <net/slip.h>
  132 
  133 #ifdef __NetBSD__       /* XXX -- jrs */
  134 typedef u_char ttychar_t;
  135 #else
  136 typedef char ttychar_t;
  137 #endif
  138 
  139 #if NBPFILTER > 0
  140 #include <sys/time.h>
  141 #include <net/bpf.h>
  142 #endif
  143 
  144 /*
  145  * SLMAX is a hard limit on input packet size.  To simplify the code
  146  * and improve performance, we require that packets fit in an mbuf
  147  * cluster, and if we get a compressed packet, there's enough extra
  148  * room to expand the header into a max length tcp/ip header (128
  149  * bytes).  So, SLMAX can be at most
  150  *      MCLBYTES - 128
  151  *
  152  * SLMTU is a hard limit on output packet size.  To insure good
  153  * interactive response, SLMTU wants to be the smallest size that
  154  * amortizes the header cost.  Remember that even with
  155  * type-of-service queuing, we have to wait for any in-progress
  156  * packet to finish.  I.e., we wait, on the average, 1/2 * mtu /
  157  * cps, where cps is the line speed in characters per second.
  158  * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line.  The
  159  * average compressed header size is 6-8 bytes so any MTU > 90
  160  * bytes will give us 90% of the line bandwidth.  A 100ms wait is
  161  * tolerable (500ms is not), so want an MTU around 296.  (Since TCP
  162  * will send 256 byte segments (to allow for 40 byte headers), the
  163  * typical packet size on the wire will be around 260 bytes).  In
  164  * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
  165  * leave the interface MTU relatively high (so we don't IP fragment
  166  * when acting as a gateway to someone using a stupid MTU).
  167  *
  168  * Similar considerations apply to SLIP_HIWAT:  It's the amount of
  169  * data that will be queued 'downstream' of us (i.e., in clists
  170  * waiting to be picked up by the tty output interrupt).  If we
  171  * queue a lot of data downstream, it's immune to our t.o.s. queuing.
  172  * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
  173  * telnet/ftp will see a 1 sec wait, independent of the mtu (the
  174  * wait is dependent on the ftp window size but that's typically
  175  * 1k - 4k).  So, we want SLIP_HIWAT just big enough to amortize
  176  * the cost (in idle time on the wire) of the tty driver running
  177  * off the end of its clists & having to call back slstart for a
  178  * new packet.  For a tty interface with any buffering at all, this
  179  * cost will be zero.  Even with a totally brain dead interface (like
  180  * the one on a typical workstation), the cost will be <= 1 character
  181  * time.  So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
  182  * at most 1% while maintaining good interactive response.
  183  */
  184 #define BUFOFFSET       (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
  185 #define SLMAX           (MCLBYTES - BUFOFFSET)
  186 #define SLBUFSIZE       (SLMAX + BUFOFFSET)
  187 #define SLMTU           1100 /* XXX -- appromaximated. 1024 may be safer. */
  188 
  189 #define STRIP_MTU_ONWIRE (SLMTU + 20 + STRIP_HDRLEN) /* (2*SLMTU+2 in sl.c */
  190 
  191 
  192 #define SLIP_HIWAT      roundup(50,CBSIZE)
  193 
  194 /* This is a NetBSD-1.0 or later kernel. */
  195 #define CCOUNT(q)       ((q)->c_cc)
  196 
  197 
  198 #ifndef __NetBSD__                                      /* XXX - cgd */
  199 #define CLISTRESERVE    1024    /* Can't let clists get too low */
  200 #endif  /* !__NetBSD__ */
  201 
  202 /*
  203  * SLIP ABORT ESCAPE MECHANISM:
  204  *      (inspired by HAYES modem escape arrangement)
  205  *      1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
  206  *      within window time signals a "soft" exit from slip mode by remote end
  207  *      if the IFF_DEBUG flag is on.
  208  */
  209 #define ABT_ESC         '\033'  /* can't be t_intr - distant host must know it*/
  210 #define ABT_IDLE        1       /* in seconds - idle before an escape */
  211 #define ABT_COUNT       3       /* count of escapes for abort */
  212 #define ABT_WINDOW      (ABT_COUNT*2+2) /* in seconds - time to count */
  213 
  214 static int              strip_clone_create(struct if_clone *, int);
  215 static int              strip_clone_destroy(struct ifnet *);
  216 
  217 static LIST_HEAD(, strip_softc) strip_softc_list;
  218 
  219 struct if_clone strip_cloner =
  220     IF_CLONE_INITIALIZER("strip", strip_clone_create, strip_clone_destroy);
  221 
  222 #define STRIP_FRAME_END         0x0D            /* carriage return */
  223 
  224 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
  225 void    stripnetisr(void);
  226 #endif
  227 static void     stripintr(void *);
  228 
  229 static int      stripinit(struct strip_softc *);
  230 static struct mbuf *strip_btom(struct strip_softc *, int);
  231 
  232 /*
  233  * STRIP header: '*' + modem address (dddd-dddd) + '*' + mactype ('SIP0')
  234  * A Metricom packet looks like this: *<address>*<key><payload><CR>
  235  *   eg. *0000-1164*SIP0<payload><CR>
  236  *
  237  */
  238 
  239 #define STRIP_ENCAP_SIZE(X) ((36) + (X)*65/64 + 2)
  240 #define STRIP_HDRLEN 15
  241 #define STRIP_MAC_ADDR_LEN 9
  242 
  243 /*
  244  * Star mode packet header.
  245  * (may be used for encapsulations other than STRIP.)
  246  */
  247 #define STARMODE_ADDR_LEN 11
  248 struct st_header {
  249         u_char starmode_addr[STARMODE_ADDR_LEN];
  250         u_char starmode_type[4];
  251 };
  252 
  253 /*
  254  * Forward declarations for Metricom-specific functions.
  255  * Ideally, these would be in a library and shared across
  256  * different STRIP implementations: *BSD, Linux, etc.
  257  *
  258  */
  259 static u_char* UnStuffData(u_char *src, u_char *end, u_char
  260                                 *dest, u_long dest_length);
  261 
  262 static u_char* StuffData(u_char *src, u_long length, u_char *dest,
  263                               u_char **code_ptr_ptr);
  264 
  265 static void RecvErr(const char *msg, struct strip_softc *sc);
  266 static void RecvErr_Message(struct strip_softc *strip_info,
  267                                 u_char *sendername, const u_char *msg);
  268 void    strip_resetradio(struct strip_softc *sc, struct tty *tp);
  269 void    strip_proberadio(struct strip_softc *sc, struct tty *tp);
  270 void    strip_watchdog(struct ifnet *ifp);
  271 void    strip_sendbody(struct strip_softc *sc, struct mbuf *m);
  272 int     strip_newpacket(struct strip_softc *sc, u_char *ptr, u_char *end);
  273 void    strip_send(struct strip_softc *sc, struct mbuf *m0);
  274 
  275 void    strip_timeout(void *x);
  276 
  277 #ifdef DEBUG
  278 #define DPRINTF(x)      printf x
  279 #else
  280 #define DPRINTF(x)
  281 #endif
  282 
  283 
  284 
  285 /*
  286  * Radio reset macros.
  287  * The Metricom radios are not particularly well-designed for
  288  * use in packet mode (starmode).  There's no easy way to tell
  289  * when the radio is in starmode.  Worse, when the radios are reset
  290  * or power-cycled, they come back up in Hayes AT-emulation mode,
  291  * and there's no good way for this driver to tell.
  292  * We deal with this by peridically tickling the radio
  293  * with an invalid starmode command.  If the radio doesn't
  294  * respond with an error, the driver knows to reset the radio.
  295  */
  296 
  297 /* Radio-reset finite state machine (if_watchdog) callback rate, in seconds */
  298 #define STRIP_WATCHDOG_INTERVAL 5
  299 
  300 /* Period between intrusive radio probes, in seconds */
  301 #define ST_PROBE_INTERVAL 10
  302 
  303 /* Grace period for radio to answer probe, in seconds */
  304 #define ST_PROBERESPONSE_INTERVAL 2
  305 
  306 /* Be less agressive about repeated resetting. */
  307 #define STRIP_RESET_INTERVAL 5
  308 
  309 /*
  310  * We received a response from the radio that indicates it's in
  311  * star mode.  Clear any pending probe or reset timer.
  312  * Don't  probe radio again for standard polling interval.
  313  */
  314 #define CLEAR_RESET_TIMER(sc) \
  315  do {\
  316     (sc)->sc_state = ST_ALIVE;  \
  317     (sc)->sc_statetimo = time_second + ST_PROBE_INTERVAL;       \
  318 } while (/*CONSTCOND*/ 0)
  319 
  320 /*
  321  * we received a response from the radio that indicates it's crashed
  322  * out of starmode into Hayse mode. Reset it ASAP.
  323  */
  324 #define FORCE_RESET(sc) \
  325  do {\
  326     (sc)->sc_statetimo = time_second - 1; \
  327     (sc)->sc_state = ST_DEAD;   \
  328     /*(sc)->sc_if.if_timer = 0;*/ \
  329  } while (/*CONSTCOND*/ 0)
  330 
  331 #define RADIO_PROBE_TIMEOUT(sc) \
  332          ((sc)-> sc_statetimo > time_second)
  333 
  334 static int      stripclose(struct tty *, int);
  335 static int      stripinput(int, struct tty *);
  336 static int      stripioctl(struct ifnet *, u_long, caddr_t);
  337 static int      stripopen(dev_t, struct tty *);
  338 static int      stripoutput(struct ifnet *,
  339                     struct mbuf *, struct sockaddr *, struct rtentry *);
  340 static int      stripstart(struct tty *);
  341 static int      striptioctl(struct tty *, u_long, caddr_t, int, struct lwp *);
  342 
  343 static struct linesw strip_disc = {
  344         .l_name = "strip",
  345         .l_open = stripopen,
  346         .l_close = stripclose,
  347         .l_read = ttyerrio,
  348         .l_write = ttyerrio,
  349         .l_ioctl = striptioctl,
  350         .l_rint = stripinput,
  351         .l_start = stripstart,
  352         .l_modem = nullmodem,
  353         .l_poll = ttyerrpoll
  354 };
  355 
  356 void
  357 stripattach(void)
  358 {
  359         if (ttyldisc_attach(&strip_disc) != 0)
  360                 panic("stripattach");
  361         LIST_INIT(&strip_softc_list);
  362         if_clone_attach(&strip_cloner);
  363 }
  364 
  365 static int
  366 strip_clone_create(struct if_clone *ifc, int unit)
  367 {
  368         struct strip_softc *sc;
  369 
  370         MALLOC(sc, struct strip_softc *, sizeof(*sc), M_DEVBUF, M_WAIT|M_ZERO);
  371         sc->sc_unit = unit;
  372         (void)snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname),
  373             "%s%d", ifc->ifc_name, unit);
  374         callout_init(&sc->sc_timo_ch);
  375         sc->sc_if.if_softc = sc;
  376         sc->sc_if.if_mtu = SLMTU;
  377         sc->sc_if.if_flags = 0;
  378         sc->sc_if.if_type = IFT_OTHER;
  379 #if 0
  380         sc->sc_if.if_flags |= SC_AUTOCOMP /* | IFF_POINTOPOINT | IFF_MULTICAST*/;
  381 #endif
  382         sc->sc_if.if_type = IFT_SLIP;
  383         sc->sc_if.if_ioctl = stripioctl;
  384         sc->sc_if.if_output = stripoutput;
  385         sc->sc_if.if_dlt = DLT_SLIP;
  386         sc->sc_fastq.ifq_maxlen = 32;
  387         IFQ_SET_READY(&sc->sc_if.if_snd);
  388 
  389         sc->sc_if.if_watchdog = strip_watchdog;
  390         if_attach(&sc->sc_if);
  391         if_alloc_sadl(&sc->sc_if);
  392 #if NBPFILTER > 0
  393         bpfattach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
  394 #endif
  395         LIST_INSERT_HEAD(&strip_softc_list, sc, sc_iflist);
  396         return 0;
  397 }
  398 
  399 static int
  400 strip_clone_destroy(struct ifnet *ifp)
  401 {
  402         struct strip_softc *sc = (struct strip_softc *)ifp->if_softc;
  403 
  404         if (sc->sc_ttyp != NULL)
  405                 return EBUSY;   /* Not removing it */
  406 
  407         LIST_REMOVE(sc, sc_iflist);
  408 
  409 #if NBPFILTER > 0
  410         bpfdetach(ifp);
  411 #endif
  412         if_detach(ifp);
  413 
  414         FREE(sc, M_DEVBUF);
  415         return 0;
  416 }
  417 
  418 static int
  419 stripinit(struct strip_softc *sc)
  420 {
  421         u_char *p;
  422 
  423         if (sc->sc_mbuf == NULL) {
  424                 sc->sc_mbuf = m_get(M_WAIT, MT_DATA);
  425                 m_clget(sc->sc_mbuf, M_WAIT);
  426         }
  427         sc->sc_ep = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  428             sc->sc_mbuf->m_ext.ext_size;
  429         sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  430             BUFOFFSET;
  431 
  432         /* Get contiguous buffer in which to de-bytestuff/rll-decode input */
  433         if (sc->sc_rxbuf == NULL) {
  434                 p = (u_char *)malloc(MCLBYTES, M_DEVBUF, M_WAITOK);
  435                 if (p)
  436                         sc->sc_rxbuf = p + SLBUFSIZE - SLMAX;
  437                 else {
  438                         printf("%s: can't allocate input buffer\n",
  439                             sc->sc_if.if_xname);
  440                         sc->sc_if.if_flags &= ~IFF_UP;
  441                         return (0);
  442                 }
  443         }
  444 
  445         /* Get contiguous buffer in which to bytestuff/rll-encode output */
  446         if (sc->sc_txbuf == NULL) {
  447                 p = (u_char *)malloc(MCLBYTES, M_DEVBUF, M_WAITOK);
  448                 if (p)
  449                         sc->sc_txbuf = (u_char *)p + SLBUFSIZE - SLMAX;
  450                 else {
  451                         printf("%s: can't allocate buffer\n",
  452                             sc->sc_if.if_xname);
  453 
  454                         sc->sc_if.if_flags &= ~IFF_UP;
  455                         return (0);
  456                 }
  457         }
  458 
  459 #ifdef INET
  460         sl_compress_init(&sc->sc_comp);
  461 #endif
  462 
  463         /* Initialize radio probe/reset state machine */
  464         sc->sc_state = ST_DEAD;         /* assumet the worst. */
  465         sc->sc_statetimo = time_second; /* do reset immediately */
  466 
  467         return (1);
  468 }
  469 
  470 /*
  471  * Line specific open routine.
  472  * Attach the given tty to the first available sl unit.
  473  */
  474 /* ARGSUSED */
  475 int
  476 stripopen(dev_t dev, struct tty *tp)
  477 {
  478         struct lwp *l = curlwp;         /* XXX */
  479         struct strip_softc *sc;
  480         int error;
  481 #ifdef __NetBSD__
  482         int s;
  483 #endif
  484 
  485         if ((error = kauth_authorize_generic(l->l_cred,
  486             KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
  487                 return (error);
  488 
  489         if (tp->t_linesw == &strip_disc)
  490                 return (0);
  491 
  492         LIST_FOREACH(sc, &strip_softc_list, sc_iflist) {
  493                 if (sc->sc_ttyp == NULL) {
  494 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  495                         sc->sc_si = softintr_establish(IPL_SOFTNET,
  496                             stripintr, sc);
  497 #endif
  498                         if (stripinit(sc) == 0) {
  499 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  500                                 softintr_disestablish(sc->sc_si);
  501 #endif
  502                                 return (ENOBUFS);
  503                         }
  504                         tp->t_sc = (caddr_t)sc;
  505                         sc->sc_ttyp = tp;
  506                         sc->sc_if.if_baudrate = tp->t_ospeed;
  507                         ttyflush(tp, FREAD | FWRITE);
  508 #ifdef __NetBSD__
  509                         /*
  510                          * Make sure tty output queue is large enough
  511                          * to hold a full-sized packet (including frame
  512                          * end, and a possible extra frame end).
  513                          * A   full-sized   of 65/64) *SLMTU bytes (because
  514                          * of escapes and clever RLL bytestuffing),
  515                          * plus frame header, and add two on for frame ends.
  516                          */
  517                         s = spltty();
  518                         if (tp->t_outq.c_cn < STRIP_MTU_ONWIRE) {
  519                                 sc->sc_oldbufsize = tp->t_outq.c_cn;
  520                                 sc->sc_oldbufquot = tp->t_outq.c_cq != 0;
  521 
  522                                 clfree(&tp->t_outq);
  523                                 error = clalloc(&tp->t_outq, 3*SLMTU, 0);
  524                                 if (error) {
  525                                         splx(s);
  526 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  527                                         softintr_disestablish(sc->sc_si);
  528 #endif
  529                                         /*
  530                                          * clalloc() might return -1 which
  531                                          * is no good, so we need to return
  532                                          * something else.
  533                                          */
  534                                         return (ENOMEM);
  535                                 }
  536                         } else
  537                                 sc->sc_oldbufsize = sc->sc_oldbufquot = 0;
  538                         splx(s);
  539 #endif /* __NetBSD__ */
  540                         s = spltty();
  541                         strip_resetradio(sc, tp);
  542                         splx(s);
  543 
  544                         /*
  545                          * Start the watchdog timer to get the radio
  546                          * "probe-for-death"/reset machine going.
  547                          */
  548                         sc->sc_if.if_timer = STRIP_WATCHDOG_INTERVAL;
  549 
  550                         return (0);
  551                 }
  552         }
  553         return (ENXIO);
  554 }
  555 
  556 /*
  557  * Line specific close routine.
  558  * Detach the tty from the strip unit.
  559  */
  560 static int
  561 stripclose(struct tty *tp, int flag)
  562 {
  563         struct strip_softc *sc;
  564         int s;
  565 
  566         ttywflush(tp);
  567         sc = tp->t_sc;
  568 
  569         if (sc != NULL) {
  570 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  571                 softintr_disestablish(sc->sc_si);
  572 #endif
  573                 s = splnet();
  574                 /*
  575                  * Cancel watchdog timer, which stops the "probe-for-death"/
  576                  * reset machine.
  577                  */
  578                 sc->sc_if.if_timer = 0;
  579                 if_down(&sc->sc_if);
  580                 IF_PURGE(&sc->sc_fastq);
  581                 splx(s);
  582 
  583                 s = spltty();
  584                 ttyldisc_release(tp->t_linesw);
  585                 tp->t_linesw = ttyldisc_default();
  586                 tp->t_state = 0;
  587 
  588                 sc->sc_ttyp = NULL;
  589                 tp->t_sc = NULL;
  590 
  591                 m_freem(sc->sc_mbuf);
  592                 sc->sc_mbuf = NULL;
  593                 sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL;
  594                 IF_PURGE(&sc->sc_inq);
  595 
  596                 /* XXX */
  597                 free((caddr_t)(sc->sc_rxbuf - SLBUFSIZE + SLMAX), M_DEVBUF);
  598                 sc->sc_rxbuf = NULL;
  599 
  600                 /* XXX */
  601                 free((caddr_t)(sc->sc_txbuf - SLBUFSIZE + SLMAX), M_DEVBUF);
  602                 sc->sc_txbuf = NULL;
  603 
  604                 if (sc->sc_flags & SC_TIMEOUT) {
  605                         callout_stop(&sc->sc_timo_ch);
  606                         sc->sc_flags &= ~SC_TIMEOUT;
  607                 }
  608 
  609                 /*
  610                  * If necessary, install a new outq buffer of the
  611                  * appropriate size.
  612                  */
  613                 if (sc->sc_oldbufsize != 0) {
  614                         clfree(&tp->t_outq);
  615                         clalloc(&tp->t_outq, sc->sc_oldbufsize,
  616                             sc->sc_oldbufquot);
  617                 }
  618                 splx(s);
  619         }
  620 
  621         return (0);
  622 }
  623 
  624 /*
  625  * Line specific (tty) ioctl routine.
  626  * Provide a way to get the sl unit number.
  627  */
  628 /* ARGSUSED */
  629 int
  630 striptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
  631     struct lwp *l)
  632 {
  633         struct strip_softc *sc = (struct strip_softc *)tp->t_sc;
  634 
  635         switch (cmd) {
  636         case SLIOCGUNIT:
  637                 *(int *)data = sc->sc_unit;
  638                 break;
  639 
  640         default:
  641                 return (EPASSTHROUGH);
  642         }
  643         return (0);
  644 }
  645 
  646 /*
  647  * Take an mbuf chain  containing a STRIP packet (no link-level header),
  648  * byte-stuff (escape) it, and enqueue it on the tty send queue.
  649  */
  650 void
  651 strip_sendbody(struct strip_softc *sc, struct mbuf *m)
  652 {
  653         struct tty *tp = sc->sc_ttyp;
  654         u_char *dp = sc->sc_txbuf;
  655         struct mbuf *m2;
  656         int len;
  657         u_char *rllstate_ptr = NULL;
  658 
  659         while (m) {
  660                 if (m->m_len != 0) {
  661                         /*
  662                          * Byte-stuff/run-length encode this mbuf's data
  663                          * into the output buffer.
  664                          * XXX Note that chained calls to stuffdata()
  665                          * require that the stuffed data be left in the
  666                          * output buffer until the entire packet is encoded.
  667                          */
  668                         dp = StuffData(mtod(m, u_char *), m->m_len, dp,
  669                             &rllstate_ptr);
  670                 }
  671                 MFREE(m, m2);
  672                 m = m2;
  673         }
  674 
  675         /*
  676          * Put the entire stuffed packet into the tty output queue.
  677          */
  678         len = dp - sc->sc_txbuf;
  679         if (b_to_q((ttychar_t *)sc->sc_txbuf, len, &tp->t_outq)) {
  680                 if (sc->sc_if.if_flags & IFF_DEBUG)
  681                         addlog("%s: tty output overflow\n",
  682                             sc->sc_if.if_xname);
  683                 return;
  684         }
  685         sc->sc_if.if_obytes += len;
  686 }
  687 
  688 /*
  689  * Send a STRIP packet.  Must be called at spltty().
  690  */
  691 void
  692 strip_send(struct strip_softc *sc, struct mbuf *m0)
  693 {
  694         struct tty *tp = sc->sc_ttyp;
  695         struct st_header *hdr;
  696 
  697         /*
  698          * Send starmode header (unstuffed).
  699          */
  700         hdr = mtod(m0, struct st_header *);
  701         if (b_to_q((ttychar_t *)hdr, STRIP_HDRLEN, &tp->t_outq)) {
  702                 if (sc->sc_if.if_flags & IFF_DEBUG)
  703                         addlog("%s: outq overflow writing header\n",
  704                                  sc->sc_if.if_xname);
  705                 m_freem(m0);
  706                 return;
  707         }
  708 
  709         m_adj(m0, sizeof(struct st_header));
  710 
  711         /* Byte-stuff and run-length encode the remainder of the packet. */
  712         strip_sendbody(sc, m0);
  713 
  714         if (putc(STRIP_FRAME_END, &tp->t_outq)) {
  715                 /*
  716                  * Not enough room.  Remove a char to make room
  717                  * and end the packet normally.
  718                  * If you get many collisions (more than one or two
  719                  * a day) you probably do not have enough clists
  720                  * and you should increase "nclist" in param.c.
  721                  */
  722                 (void) unputc(&tp->t_outq);
  723                 (void) putc(STRIP_FRAME_END, &tp->t_outq);
  724                 sc->sc_if.if_collisions++;
  725         } else {
  726                 ++sc->sc_if.if_obytes;
  727                 sc->sc_if.if_opackets++;
  728         }
  729 
  730         /*
  731          * If a radio probe is due now, append it to this packet rather
  732          * than waiting until the watchdog routine next runs.
  733          */
  734         if (time_second >= sc->sc_statetimo && sc->sc_state == ST_ALIVE)
  735                 strip_proberadio(sc, tp);
  736 }
  737 
  738 /*
  739  * Queue a packet.  Start transmission if not active.
  740  * Compression happens in stripintr(); if we do it here, IP TOS
  741  * will cause us to not compress "background" packets, because
  742  * ordering gets trashed.  It can be done for all packets in stripintr().
  743  */
  744 int
  745 stripoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  746     struct rtentry *rt)
  747 {
  748         struct strip_softc *sc = ifp->if_softc;
  749         struct ip *ip;
  750         struct st_header *shp;
  751         const u_char *dldst;            /* link-level next-hop */
  752         struct ifqueue *ifq;
  753         int s, error;
  754         u_char dl_addrbuf[STARMODE_ADDR_LEN+1];
  755         ALTQ_DECL(struct altq_pktattr pktattr;)
  756 
  757         /*
  758          * Verify tty line is up and alive.
  759          */
  760         if (sc->sc_ttyp == NULL) {
  761                 m_freem(m);
  762                 return (ENETDOWN);      /* sort of */
  763         }
  764         if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
  765             (sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
  766                 m_freem(m);
  767                 return (EHOSTUNREACH);
  768         }
  769 
  770 #define SDL(a)          ((struct sockaddr_dl *) (a))
  771 
  772 #ifdef DEBUG
  773         if (rt) {
  774                 printf("stripout, rt: dst af%d gw af%d",
  775                     rt_key(rt)->sa_family, rt->rt_gateway->sa_family);
  776                 if (rt_key(rt)->sa_family == AF_INET)
  777                   printf(" dst %x",
  778                       ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr);
  779                 printf("\n");
  780         }
  781 #endif
  782         switch (dst->sa_family) {
  783         case AF_INET:
  784                 if (rt != NULL && rt->rt_gwroute != NULL)
  785                         rt = rt->rt_gwroute;
  786 
  787                 /* assume rt is never NULL */
  788                 if (rt == NULL || rt->rt_gateway->sa_family != AF_LINK
  789                     || SDL(rt->rt_gateway)->sdl_alen != ifp->if_addrlen) {
  790                         DPRINTF(("strip: could not arp starmode addr %x\n",
  791                          ((struct sockaddr_in *)dst)->sin_addr.s_addr));
  792                         m_freem(m);
  793                         return (EHOSTUNREACH);
  794                 }
  795                 /*bcopy(LLADDR(SDL(rt->rt_gateway)), dldst, ifp->if_addrlen);*/
  796                 dldst = LLADDR(SDL(rt->rt_gateway));
  797                 break;
  798 
  799         case AF_LINK:
  800                 /*bcopy(LLADDR(SDL(rt->rt_gateway)), dldst, ifp->if_addrlen);*/
  801                 dldst = LLADDR(SDL(dst));
  802                 break;
  803 
  804         default:
  805                 /*
  806                  * `Cannot happen' (see stripioctl).  Someday we will extend
  807                  * the line protocol to support other address families.
  808                  */
  809                 printf("%s: af %d not supported\n", sc->sc_if.if_xname,
  810                     dst->sa_family);
  811                 m_freem(m);
  812                 sc->sc_if.if_noproto++;
  813                 return (EAFNOSUPPORT);
  814         }
  815 
  816         ip = mtod(m, struct ip *);
  817 #ifdef INET
  818         if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
  819                 m_freem(m);
  820                 return (ENETRESET);             /* XXX ? */
  821         }
  822         if ((ip->ip_tos & IPTOS_LOWDELAY) != 0
  823 #ifdef ALTQ
  824             && ALTQ_IS_ENABLED(&ifp->if_snd) == 0
  825 #endif
  826             )
  827                 ifq = &sc->sc_fastq;
  828         else
  829 #endif
  830                 ifq = NULL;
  831 
  832         /*
  833          * Add local net header.  If no space in first mbuf,
  834          * add another.
  835          */
  836         M_PREPEND(m, sizeof(struct st_header), M_DONTWAIT);
  837         if (m == 0) {
  838                 DPRINTF(("strip: could not prepend starmode header\n"));
  839                 return (ENOBUFS);
  840         }
  841 
  842         /*
  843          * Unpack BCD route entry into an ASCII starmode address.
  844          */
  845         dl_addrbuf[0] = '*';
  846 
  847         dl_addrbuf[1] = ((dldst[0] >> 4) & 0x0f) + '';
  848         dl_addrbuf[2] = ((dldst[0]     ) & 0x0f) + '';
  849 
  850         dl_addrbuf[3] = ((dldst[1] >> 4) & 0x0f) + '';
  851         dl_addrbuf[4] = ((dldst[1]     ) & 0x0f) + '';
  852 
  853         dl_addrbuf[5] = '-';
  854 
  855         dl_addrbuf[6] = ((dldst[2] >> 4) & 0x0f) + '';
  856         dl_addrbuf[7] = ((dldst[2]     ) & 0x0f) + '';
  857 
  858         dl_addrbuf[8] = ((dldst[3] >> 4) & 0x0f) + '';
  859         dl_addrbuf[9] = ((dldst[3]     ) & 0x0f) + '';
  860 
  861         dl_addrbuf[10] = '*';
  862         dl_addrbuf[11] = 0;
  863         dldst = dl_addrbuf;
  864 
  865         shp = mtod(m, struct st_header *);
  866         memcpy(&shp->starmode_type, "SIP0", sizeof(shp->starmode_type));
  867 
  868         memcpy(shp->starmode_addr, dldst, sizeof(shp->starmode_addr));
  869 
  870         s = spltty();
  871         if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
  872                 struct bintime bt;
  873 
  874                 /* if output's been stalled for too long, and restart */
  875                 getbinuptime(&bt);
  876                 bintime_sub(&bt, &sc->sc_lastpacket);
  877                 if (bt.sec > 0) {
  878                         DPRINTF(("stripoutput: stalled, resetting\n"));
  879                         sc->sc_otimeout++;
  880                         stripstart(sc->sc_ttyp);
  881                 }
  882         }
  883         splx(s);
  884 
  885         s = splnet();
  886         if ((error = ifq_enqueue2(ifp, ifq, m ALTQ_COMMA
  887             ALTQ_DECL(&pktattr))) != 0) {
  888                 splx(s);
  889                 return error;
  890         }
  891         getbinuptime(&sc->sc_lastpacket);
  892         splx(s);
  893 
  894         s = spltty();
  895         stripstart(sc->sc_ttyp);
  896         splx(s);
  897 
  898         return (0);
  899 }
  900 
  901 
  902 /*
  903  * Start output on interface.  Get another datagram
  904  * to send from the interface queue and map it to
  905  * the interface before starting output.
  906  *
  907  */
  908 int
  909 stripstart(struct tty *tp)
  910 {
  911         struct strip_softc *sc = tp->t_sc;
  912 
  913         /*
  914          * If there is more in the output queue, just send it now.
  915          * We are being called in lieu of ttstart and must do what
  916          * it would.
  917          */
  918         if (tp->t_outq.c_cc != 0) {
  919                 (*tp->t_oproc)(tp);
  920                 if (tp->t_outq.c_cc > SLIP_HIWAT)
  921                         return (0);
  922         }
  923 
  924         /*
  925          * This happens briefly when the line shuts down.
  926          */
  927         if (sc == NULL)
  928                 return (0);
  929 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
  930         softintr_schedule(sc->sc_si);
  931 #else
  932     {
  933         int s = splhigh();
  934         schednetisr(NETISR_STRIP);
  935         splx(s);
  936     }
  937 #endif
  938         return (0);
  939 }
  940 
  941 /*
  942  * Copy data buffer to mbuf chain; add ifnet pointer.
  943  */
  944 static struct mbuf *
  945 strip_btom(struct strip_softc *sc, int len)
  946 {
  947         struct mbuf *m;
  948 
  949         /*
  950          * Allocate a new input buffer and swap.
  951          */
  952         m = sc->sc_mbuf;
  953         MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA);
  954         if (sc->sc_mbuf == NULL) {
  955                 sc->sc_mbuf = m;
  956                 return (NULL);
  957         }
  958         MCLGET(sc->sc_mbuf, M_DONTWAIT);
  959         if ((sc->sc_mbuf->m_flags & M_EXT) == 0) {
  960                 m_freem(sc->sc_mbuf);
  961                 sc->sc_mbuf = m;
  962                 return (NULL);
  963         }
  964         sc->sc_ep = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
  965             sc->sc_mbuf->m_ext.ext_size;
  966 
  967         m->m_data = sc->sc_pktstart;
  968 
  969         m->m_pkthdr.len = m->m_len = len;
  970         m->m_pkthdr.rcvif = &sc->sc_if;
  971         return (m);
  972 }
  973 
  974 /*
  975  * tty interface receiver interrupt.
  976  *
  977  * Called with a single char from the tty receiver interrupt; put
  978  * the char into the buffer containing a partial packet. If the
  979  * char is a packet delimiter, decapsulate the packet, wrap it in
  980  * an mbuf, and put it on the protocol input queue.
  981 */
  982 int
  983 stripinput(int c, struct tty *tp)
  984 {
  985         struct strip_softc *sc;
  986         struct mbuf *m;
  987         int len;
  988 
  989         tk_nin++;
  990         sc = (struct strip_softc *)tp->t_sc;
  991         if (sc == NULL)
  992                 return (0);
  993         if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 &&
  994             (tp->t_cflag & CLOCAL) == 0)) {
  995                 sc->sc_flags |= SC_ERROR;
  996                 DPRINTF(("strip: input, error %x\n", c));        /* XXX */
  997                 return (0);
  998         }
  999         c &= TTY_CHARMASK;
 1000 
 1001         ++sc->sc_if.if_ibytes;
 1002 
 1003         /*
 1004          * Accumulate characters until we see a frame terminator (\r).
 1005          */
 1006         switch (c) {
 1007 
 1008         case '\n':
 1009                 /*
 1010                  * Error message strings from the modem are terminated with
 1011                  * \r\n. This driver interprets the  \r as a packet terminator.
 1012                  * If the first character in a packet is a \n, drop it.
 1013                  * (it can never be the first char of a vaild frame).
 1014                  */
 1015                 if (sc->sc_mp - sc->sc_pktstart == 0)
 1016                         break;
 1017 
 1018         /* Fall through to */
 1019 
 1020         default:
 1021                 if (sc->sc_mp < sc->sc_ep) {
 1022                         *sc->sc_mp++ = c;
 1023                 } else {
 1024                         sc->sc_flags |= SC_ERROR;
 1025                         goto error;
 1026                 }
 1027                 return (0);
 1028 
 1029         case STRIP_FRAME_END:
 1030                 break;
 1031         }
 1032 
 1033 
 1034         /*
 1035          * We only reach here if we see a CR delimiting a packet.
 1036          */
 1037 
 1038 
 1039         len = sc->sc_mp - sc->sc_pktstart;
 1040 
 1041 #ifdef XDEBUG
 1042         if (len < 15 || sc->sc_flags & SC_ERROR)
 1043                 printf("stripinput: end of pkt, len %d, err %d\n",
 1044                     len, sc->sc_flags & SC_ERROR); /*XXX*/
 1045 #endif
 1046         if(sc->sc_flags & SC_ERROR) {
 1047                 sc->sc_flags &= ~SC_ERROR;
 1048                 addlog("%s: sc error flag set. terminating packet\n",
 1049                         sc->sc_if.if_xname);
 1050                 goto newpack;
 1051         }
 1052 
 1053         /*
 1054          * We have a frame.
 1055          * Process an IP packet, ARP packet, AppleTalk packet,
 1056          * AT command resposne, or Starmode error.
 1057          */
 1058         len = strip_newpacket(sc, sc->sc_pktstart, sc->sc_mp);
 1059         if (len <= 1)
 1060                 /* less than min length packet - ignore */
 1061                 goto newpack;
 1062 
 1063         m = strip_btom(sc, len);
 1064         if (m == NULL)
 1065                 goto error;
 1066 
 1067         IF_ENQUEUE(&sc->sc_inq, m);
 1068 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
 1069         softintr_schedule(sc->sc_si);
 1070 #else
 1071     {
 1072         int s = splhigh();
 1073         schednetisr(NETISR_STRIP);
 1074         splx(s);
 1075     }
 1076 #endif
 1077         goto newpack;
 1078 
 1079 error:
 1080         sc->sc_if.if_ierrors++;
 1081 
 1082 newpack:
 1083         sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
 1084             BUFOFFSET;
 1085 
 1086         return (0);
 1087 }
 1088 
 1089 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
 1090 void
 1091 stripnetisr(void)
 1092 {
 1093         struct strip_softc *sc;
 1094 
 1095         LIST_FOREACH(sc, &strip_softc_list, sc_iflist) {
 1096                 if (sc->sc_ttyp == NULL)
 1097                         continue;
 1098                 stripintr(sc);
 1099         }
 1100 }
 1101 #endif
 1102 
 1103 static void
 1104 stripintr(void *arg)
 1105 {
 1106         struct strip_softc *sc = arg;
 1107         struct tty *tp = sc->sc_ttyp;
 1108         struct mbuf *m;
 1109         int s, len;
 1110         u_char *pktstart;
 1111 #ifdef INET
 1112         u_char c;
 1113 #endif
 1114 #if NBPFILTER > 0
 1115         u_char chdr[CHDR_LEN];
 1116 #endif
 1117 
 1118         KASSERT(tp != NULL);
 1119 
 1120         /*
 1121          * Output processing loop.
 1122          */
 1123         for (;;) {
 1124 #ifdef INET
 1125                 struct ip *ip;
 1126 #endif
 1127 #if NBPFILTER > 0
 1128                 struct mbuf *bpf_m;
 1129 #endif
 1130 
 1131                 /*
 1132                  * Do not remove the packet from the queue if it
 1133                  * doesn't look like it will fit into the current
 1134                  * serial output queue (STRIP_MTU_ONWIRE, or
 1135                  * Starmode header + 20 bytes + 4 bytes in case we
 1136                  * have to probe the radio).
 1137                  */
 1138                 s = spltty();
 1139                 if (tp->t_outq.c_cn - tp->t_outq.c_cc <
 1140                     STRIP_MTU_ONWIRE + 4) {
 1141                         splx(s);
 1142                         break;
 1143                 }
 1144                 splx(s);
 1145 
 1146                 /*
 1147                  * Get a packet and send it to the radio.
 1148                  */
 1149                 s = splnet();
 1150                 IF_DEQUEUE(&sc->sc_fastq, m);
 1151                 if (m)
 1152                         sc->sc_if.if_omcasts++; /* XXX */
 1153                 else
 1154                         IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
 1155                 splx(s);
 1156 
 1157                 if (m == NULL)
 1158                         break;
 1159 
 1160                 /*
 1161                  * We do the header compression here rather than in
 1162                  * stripoutput() because the packets will be out of
 1163                  * order if we are using TOS queueing, and the
 1164                  * connection ID compression will get munged when
 1165                  * this happens.
 1166                  */
 1167 #if NBPFILTER > 0
 1168                 if (sc->sc_if.if_bpf) {
 1169                         /*
 1170                          * We need to save the TCP/IP header before
 1171                          * it's compressed.  To avoid complicated
 1172                          * code, we just make a deep copy of the
 1173                          * entire packet (since this is a serial
 1174                          * line, packets should be short and/or the
 1175                          * copy should be negligible cost compared
 1176                          * to the packet transmission time).
 1177                          */
 1178                         bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT);
 1179                 } else
 1180                         bpf_m = NULL;
 1181 #endif
 1182 #ifdef INET
 1183                 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
 1184                         if (sc->sc_if.if_flags & SC_COMPRESS)
 1185                                 *mtod(m, u_char *) |=
 1186                                     sl_compress_tcp(m, ip,
 1187                                     &sc->sc_comp, 1);
 1188                 }
 1189 #endif
 1190 #if NBPFILTER > 0
 1191                 if (sc->sc_if.if_bpf && bpf_m != NULL)
 1192                         bpf_mtap_sl_out(sc->sc_if.if_bpf, mtod(m, u_char *),
 1193                             bpf_m);
 1194 #endif
 1195                 getbinuptime(&sc->sc_lastpacket);
 1196 
 1197                 s = spltty();
 1198                 strip_send(sc, m);
 1199 
 1200                 /*
 1201                  * We now have characters in the output queue,
 1202                  * kick the serial port.
 1203                  */
 1204                 if (tp->t_outq.c_cc != 0)
 1205                         (*tp->t_oproc)(tp);
 1206                 splx(s);
 1207         }
 1208 
 1209         /*
 1210          * Input processing loop.
 1211          */
 1212         for (;;) {
 1213                 s = spltty();
 1214                 IF_DEQUEUE(&sc->sc_inq, m);
 1215                 splx(s);
 1216                 if (m == NULL)
 1217                         break;
 1218                 pktstart = mtod(m, u_char *);
 1219                 len = m->m_pkthdr.len;
 1220 #if NBPFILTER > 0
 1221                 if (sc->sc_if.if_bpf) {
 1222                         /*
 1223                          * Save the compressed header, so we
 1224                          * can tack it on later.  Note that we
 1225                          * will end up copying garbage in come
 1226                          * cases but this is okay.  We remember
 1227                          * where the buffer started so we can
 1228                          * compute the new header length.
 1229                          */
 1230                         memcpy(chdr, pktstart, CHDR_LEN);
 1231                 }
 1232 #endif /* NBPFILTER > 0 */
 1233 #ifdef INET
 1234                 if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) {
 1235                         if (c & 0x80)
 1236                                 c = TYPE_COMPRESSED_TCP;
 1237                         else if (c == TYPE_UNCOMPRESSED_TCP)
 1238                                 *pktstart &= 0x4f; /* XXX */
 1239                         /*
 1240                          * We've got something that's not an IP
 1241                          * packet.  If compression is enabled,
 1242                          * try to decompress it.  Otherwise, if
 1243                          * `auto-enable' compression is on and
 1244                          * it's a reasonable packet, decompress
 1245                          * it and then enable compression.
 1246                          * Otherwise, drop it.
 1247                          */
 1248                         if (sc->sc_if.if_flags & SC_COMPRESS) {
 1249                                 len = sl_uncompress_tcp(&pktstart, len,
 1250                                     (u_int)c, &sc->sc_comp);
 1251                                 if (len <= 0) {
 1252                                         m_freem(m);
 1253                                         continue;
 1254                                 }
 1255                         } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
 1256                             c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
 1257                                 len = sl_uncompress_tcp(&pktstart, len,
 1258                                     (u_int)c, &sc->sc_comp);
 1259                                 if (len <= 0) {
 1260                                         m_freem(m);
 1261                                         continue;
 1262                                 }
 1263                                 sc->sc_if.if_flags |= SC_COMPRESS;
 1264                         } else {
 1265                                 m_freem(m);
 1266                                 continue;
 1267                         }
 1268                 }
 1269 #endif
 1270                 m->m_data = (caddr_t) pktstart;
 1271                 m->m_pkthdr.len = m->m_len = len;
 1272 #if NPBFILTER > 0
 1273                 if (sc->sc_if.if_bpf) {
 1274                         bpf_mtap_sl_in(sc->sc_if.if_bpf, chdr, &m);
 1275                         if (m == NULL)
 1276                                 continue;
 1277                 }
 1278 #endif
 1279                 /*
 1280                  * If the packet will fit into a single
 1281                  * header mbuf, copy it into one, to save
 1282                  * memory.
 1283                  */
 1284                 if (m->m_pkthdr.len < MHLEN) {
 1285                         struct mbuf *n;
 1286                         int pktlen;
 1287 
 1288                         MGETHDR(n, M_DONTWAIT, MT_DATA);
 1289                         pktlen = m->m_pkthdr.len;
 1290                         M_MOVE_PKTHDR(n, m);
 1291                         memcpy(mtod(n, caddr_t), mtod(m, caddr_t), pktlen);
 1292                         n->m_len = m->m_len;
 1293                         m_freem(m);
 1294                         m = n;
 1295                 }
 1296 
 1297                 sc->sc_if.if_ipackets++;
 1298                 getbinuptime(&sc->sc_lastpacket);
 1299 
 1300 #ifdef INET
 1301                 s = splnet();
 1302                 if (IF_QFULL(&ipintrq)) {
 1303                         IF_DROP(&ipintrq);
 1304                         sc->sc_if.if_ierrors++;
 1305                         sc->sc_if.if_iqdrops++;
 1306                         m_freem(m);
 1307                 } else {
 1308                         IF_ENQUEUE(&ipintrq, m);
 1309                         schednetisr(NETISR_IP);
 1310                 }
 1311                 splx(s);
 1312 #endif
 1313         }
 1314 }
 1315 
 1316 /*
 1317  * Process an ioctl request.
 1318  */
 1319 int
 1320 stripioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1321 {
 1322         struct ifaddr *ifa = (struct ifaddr *)data;
 1323         struct ifreq *ifr;
 1324         int s, error = 0;
 1325 
 1326         s = splnet();
 1327 
 1328         switch (cmd) {
 1329 
 1330         case SIOCSIFADDR:
 1331                 if (ifa->ifa_addr->sa_family == AF_INET)
 1332                         ifp->if_flags |= IFF_UP;
 1333                 else
 1334                         error = EAFNOSUPPORT;
 1335                 break;
 1336 
 1337         case SIOCSIFDSTADDR:
 1338                 if (ifa->ifa_addr->sa_family != AF_INET)
 1339                         error = EAFNOSUPPORT;
 1340                 break;
 1341 
 1342         case SIOCADDMULTI:
 1343         case SIOCDELMULTI:
 1344                 ifr = (struct ifreq *)data;
 1345                 if (ifr == 0) {
 1346                         error = EAFNOSUPPORT;           /* XXX */
 1347                         break;
 1348                 }
 1349                 switch (ifr->ifr_addr.sa_family) {
 1350 
 1351 #ifdef INET
 1352                 case AF_INET:
 1353                         break;
 1354 #endif
 1355 
 1356                 default:
 1357                         error = EAFNOSUPPORT;
 1358                         break;
 1359                 }
 1360                 break;
 1361 
 1362         default:
 1363                 error = EINVAL;
 1364         }
 1365         splx(s);
 1366         return (error);
 1367 }
 1368 
 1369 
 1370 /*
 1371  * Strip subroutines
 1372  */
 1373 
 1374 /*
 1375  * Set a radio into starmode.
 1376  * Must be called at spltty().
 1377  */
 1378 void
 1379 strip_resetradio(struct strip_softc *sc, struct tty *tp)
 1380 {
 1381 #if 0
 1382         static ttychar_t InitString[] =
 1383                 "\r\n\r\n\r\nat\r\n\r\n\r\nate0dt**starmode\r\n**\r\n";
 1384 #else
 1385         static ttychar_t InitString[] =
 1386                 "\r\rat\r\r\rate0q1dt**starmode\r**\r";
 1387 #endif
 1388         int i;
 1389 
 1390         /*
 1391          * XXX Perhaps flush  tty output queue?
 1392          */
 1393 
 1394         if ((i = b_to_q(InitString, sizeof(InitString) - 1, &tp->t_outq))) {
 1395                 printf("resetradio: %d chars didn't fit in tty queue\n", i);
 1396                 return;
 1397         }
 1398         sc->sc_if.if_obytes += sizeof(InitString) - 1;
 1399 
 1400         /*
 1401          * Assume the radio is still dead, so we can detect repeated
 1402          * resets (perhaps the radio is disconnected, powered off, or
 1403          * is so badlyhung it needs  powercycling.
 1404          */
 1405         sc->sc_state = ST_DEAD;
 1406         getbinuptime(&sc->sc_lastpacket);
 1407         sc->sc_statetimo = time_second + STRIP_RESET_INTERVAL;
 1408 
 1409         /*
 1410          * XXX Does calling the tty output routine now help resets?
 1411          */
 1412         (*sc->sc_ttyp->t_oproc)(tp);
 1413 }
 1414 
 1415 
 1416 /*
 1417  * Send an invalid starmode packet to the radio, to induce an error message
 1418  * indicating the radio is in starmode.
 1419  * Update the state machine to indicate a response is expected.
 1420  * Either the radio answers, which will be caught by the parser,
 1421  * or the watchdog will start resetting.
 1422  *
 1423  * NOTE: drops chars directly on the tty output queue.
 1424  * should be caled at spl >= spltty.
 1425  */
 1426 void
 1427 strip_proberadio(struct strip_softc *sc, struct tty *tp)
 1428 {
 1429 
 1430         int overflow;
 1431         const char *strip_probestr = "**";
 1432 
 1433         if (sc->sc_if.if_flags & IFF_DEBUG)
 1434                 addlog("%s: attempting to probe radio\n", sc->sc_if.if_xname);
 1435 
 1436         overflow = b_to_q((const ttychar_t *)strip_probestr, 2, &tp->t_outq);
 1437         if (overflow == 0) {
 1438                 if (sc->sc_if.if_flags & IFF_DEBUG)
 1439                         addlog("%s:: sent probe  to radio\n",
 1440                                sc->sc_if.if_xname);
 1441                 /* Go to probe-sent state, set timeout accordingly. */
 1442                 sc->sc_state = ST_PROBE_SENT;
 1443                 sc->sc_statetimo = time_second + ST_PROBERESPONSE_INTERVAL;
 1444         } else {
 1445                 addlog("%s: incomplete probe, tty queue %d bytes overfull\n",
 1446                         sc->sc_if.if_xname, overflow);
 1447         }
 1448 }
 1449 
 1450 
 1451 #ifdef DEBUG
 1452 static const char *strip_statenames[] = {
 1453         "Alive",
 1454         "Probe sent, awaiting answer",
 1455         "Probe not answered, resetting"
 1456 };
 1457 #endif
 1458 
 1459 
 1460 /*
 1461  * Timeout routine -- try to start more output.
 1462  * Will be needed to make strip work on ptys.
 1463  */
 1464 void
 1465 strip_timeout(void *x)
 1466 {
 1467     struct strip_softc *sc = (struct strip_softc *) x;
 1468     struct tty *tp =  sc->sc_ttyp;
 1469     int s;
 1470 
 1471     s = spltty();
 1472     sc->sc_flags &= ~SC_TIMEOUT;
 1473     stripstart(tp);
 1474     splx(s);
 1475 }
 1476 
 1477 
 1478 /*
 1479  * Strip watchdog routine.
 1480  * The radio hardware is balky. When sent long packets or bursts of small
 1481  * packets, the radios crash and reboots into Hayes-emulation mode.
 1482  * The transmit-side machinery, the error parser, and strip_watchdog()
 1483  * implement a simple finite state machine.
 1484  *
 1485  * We attempt to send a probe to the radio every ST_PROBE seconds. There
 1486  * is no direct way to tell if the radio is in starmode, so we send it a
 1487  * malformed starmode packet -- a frame with no destination address --
 1488  * and expect to an "name missing" error response from the radio within
 1489  * 1 second. If we hear such a response, we assume the radio is alive
 1490  * for the next ST_PROBE seconds.
 1491  * If we don't hear a starmode-error response from  the radio, we reset it.
 1492  *
 1493  * Probes, and parsing of error responses,  are normally done inside the send
 1494  * and receive side respectively. This watchdog routine examines the
 1495  * state-machine variables. If there are no packets to send to the radio
 1496  * during an entire probe interval, strip_output  will not be called,
 1497  * so we send a probe on its behalf.
 1498  */
 1499 void
 1500 strip_watchdog(struct ifnet *ifp)
 1501 {
 1502         struct strip_softc *sc = ifp->if_softc;
 1503         struct tty *tp =  sc->sc_ttyp;
 1504 
 1505         /*
 1506          * Just punt if the line has been closed.
 1507          */
 1508         if (tp == NULL)
 1509                 return;
 1510 
 1511 #ifdef DEBUG
 1512         if (ifp->if_flags & IFF_DEBUG)
 1513                 addlog("\n%s: in watchdog, state %s timeout %ld\n",
 1514                        ifp->if_xname,
 1515                        ((unsigned) sc->sc_state < 3) ?
 1516                        strip_statenames[sc->sc_state] : "<<illegal state>>",
 1517                        sc->sc_statetimo - time_second);
 1518 #endif
 1519 
 1520         /*
 1521          * If time in this state hasn't yet expired, return.
 1522          */
 1523         if ((ifp->if_flags & IFF_UP) ==  0 || sc->sc_statetimo > time_second) {
 1524                 goto done;
 1525         }
 1526 
 1527         /*
 1528          * The time in the current state has expired.
 1529          * Take appropriate action and advance FSA to the next state.
 1530          */
 1531         switch (sc->sc_state) {
 1532               case ST_ALIVE:
 1533                 /*
 1534                  * A probe is due but we haven't piggybacked one on a packet.
 1535                  * Send a probe now.
 1536                  */
 1537                 strip_proberadio(sc, sc->sc_ttyp);
 1538                 (*tp->t_oproc)(tp);
 1539                 break;
 1540 
 1541               case ST_PROBE_SENT:
 1542                 /*
 1543                  * Probe sent but no response within timeout. Reset.
 1544                  */
 1545                 addlog("%s: no answer to probe, resetting radio\n",
 1546                        ifp->if_xname);
 1547                 strip_resetradio(sc, sc->sc_ttyp);
 1548                 ifp->if_oerrors++;
 1549                 break;
 1550 
 1551               case ST_DEAD:
 1552                 /*
 1553                  * The radio has been sent a reset but didn't respond.
 1554                  * XXX warn user to remove AC adaptor and battery,
 1555                  * wait  5 secs, and replace.
 1556                  */
 1557                 addlog("%s: radio reset but not responding, Trying again\n",
 1558                        ifp->if_xname);
 1559                 strip_resetradio(sc, sc->sc_ttyp);
 1560                 ifp->if_oerrors++;
 1561                 break;
 1562 
 1563               default:
 1564                 /* Cannot happen. To be safe, do  a reset. */
 1565                 addlog("%s: %s %d, resetting\n",
 1566                        sc->sc_if.if_xname,
 1567                        "radio-reset finite-state machine in invalid state",
 1568                        sc->sc_state);
 1569                 strip_resetradio(sc, sc->sc_ttyp);
 1570                 sc->sc_state = ST_DEAD;
 1571                 break;
 1572         }
 1573 
 1574       done:
 1575         ifp->if_timer = STRIP_WATCHDOG_INTERVAL;
 1576         return;
 1577 }
 1578 
 1579 
 1580 /*
 1581  * The following bytestuffing and run-length encoding/decoding
 1582  * functions are taken, with permission from Stuart Cheshire,
 1583  * from the MosquitonNet strip driver for Linux.
 1584  * XXX Linux style left intact, to ease folding in updates from
 1585  * the Mosquitonet group.
 1586  */
 1587 
 1588 
 1589 /*
 1590  * Process a received packet.
 1591  */
 1592 int
 1593 strip_newpacket(struct strip_softc *sc, u_char *ptr, u_char *end)
 1594 {
 1595         int len = ptr - end;
 1596         u_char *name, *name_end;
 1597         u_int packetlen;
 1598 
 1599         /* Ignore empty lines */
 1600         if (len == 0) return 0;
 1601 
 1602         /* Catch 'OK' responses which show radio has fallen out of starmode */
 1603         if (len >= 2 && ptr[0] == 'O' && ptr[1] == 'K') {
 1604                 printf("%s: Radio is back in AT command mode: will reset\n",
 1605                     sc->sc_if.if_xname);
 1606                 FORCE_RESET(sc);                /* Do reset ASAP */
 1607         return 0;
 1608         }
 1609 
 1610         /* Check for start of address marker, and then skip over it */
 1611         if (*ptr != '*') {
 1612                 /* Catch other error messages */
 1613                 if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_')
 1614                         RecvErr_Message(sc, NULL, ptr+4);
 1615                          /* XXX what should the message above be? */
 1616                 else {
 1617                         RecvErr("No initial *", sc);
 1618                         addlog("(len = %d)\n", len);
 1619                      }
 1620                 return 0;
 1621         }
 1622 
 1623         /* skip the '*' */
 1624         ptr++;
 1625 
 1626         /* Skip the return address */
 1627         name = ptr;
 1628         while (ptr < end && *ptr != '*')
 1629                 ptr++;
 1630 
 1631         /* Check for end of address marker, and skip over it */
 1632         if (ptr == end) {
 1633                 RecvErr("No second *", sc);
 1634                 return 0;
 1635         }
 1636         name_end = ptr++;
 1637 
 1638         /* Check for SRIP key, and skip over it */
 1639         if (ptr[0] != 'S' || ptr[1] != 'I' || ptr[2] != 'P' || ptr[3] != '') {
 1640                 if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' &&
 1641                     ptr[3] == '_') {
 1642                         *name_end = 0;
 1643                         RecvErr_Message(sc, name, ptr+4);
 1644                  }
 1645                 else RecvErr("No SRIP key", sc);
 1646                 return 0;
 1647         }
 1648         ptr += 4;
 1649 
 1650         /* Decode start of the IP packet header */
 1651         ptr = UnStuffData(ptr, end, sc->sc_rxbuf, 4);
 1652         if (ptr == 0) {
 1653                 RecvErr("Runt packet (hdr)", sc);
 1654                 return 0;
 1655         }
 1656 
 1657         /*
 1658          * The STRIP bytestuff/RLL encoding has no explicit length
 1659          * of the decoded packet.  Decode start of IP header, get the
 1660          * IP header length and decode that many bytes in total.
 1661          */
 1662         packetlen = ((u_int16_t)sc->sc_rxbuf[2] << 8) | sc->sc_rxbuf[3];
 1663 
 1664 #ifdef DIAGNOSTIC
 1665 #if 0
 1666         printf("Packet %02x.%02x.%02x.%02x\n",
 1667                 sc->sc_rxbuf[0], sc->sc_rxbuf[1],
 1668                 sc->sc_rxbuf[2], sc->sc_rxbuf[3]);
 1669         printf("Got %d byte packet\n", packetlen);
 1670 #endif
 1671 #endif
 1672 
 1673         /* Decode remainder of the IP packer */
 1674         ptr = UnStuffData(ptr, end, sc->sc_rxbuf+4, packetlen-4);
 1675         if (ptr == 0) {
 1676                 RecvErr("Short packet", sc);
 1677                 return 0;
 1678         }
 1679 
 1680         /* XXX redundant copy */
 1681         bcopy(sc->sc_rxbuf, sc->sc_pktstart, packetlen );
 1682         return (packetlen);
 1683 }
 1684 
 1685 
 1686 /*
 1687  * Stuffing scheme:
 1688  * 00    Unused (reserved character)
 1689  * 01-3F Run of 2-64 different characters
 1690  * 40-7F Run of 1-64 different characters plus a single zero at the end
 1691  * 80-BF Run of 1-64 of the same character
 1692  * C0-FF Run of 1-64 zeroes (ASCII 0)
 1693 */
 1694 typedef enum
 1695 {
 1696         Stuff_Diff      = 0x00,
 1697         Stuff_DiffZero  = 0x40,
 1698         Stuff_Same      = 0x80,
 1699         Stuff_Zero      = 0xC0,
 1700         Stuff_NoCode    = 0xFF,         /* Special code, meaning no code selected */
 1701 
 1702         Stuff_CodeMask  = 0xC0,
 1703         Stuff_CountMask = 0x3F,
 1704         Stuff_MaxCount  = 0x3F,
 1705         Stuff_Magic     = 0x0D          /* The value we are eliminating */
 1706 } StuffingCode;
 1707 
 1708 /*
 1709  * StuffData encodes the data starting at "src" for "length" bytes.
 1710  * It writes it to the buffer pointed to by "dest" (which must be at least
 1711  * as long as 1 + 65/64 of the input length). The output may be up to 1.6%
 1712  * larger than the input for pathological input, but will usually be smaller.
 1713  * StuffData returns the new value of the dest pointer as its result.
 1714  *
 1715  * "code_ptr_ptr" points to a "u_char *" which is used to hold
 1716  * encoding state between calls, allowing an encoded packet to be
 1717  * incrementally built up from small parts.
 1718  * On the first call, the "u_char *" pointed to should be initialized
 1719  * to NULL;  between subsequent calls the calling routine should leave
 1720  * the value alone and simply pass it back unchanged so that the
 1721  * encoder can recover its current state.
 1722  */
 1723 
 1724 #define StuffData_FinishBlock(X) \
 1725         (*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode)
 1726 
 1727 static u_char*
 1728 StuffData(u_char *src, u_long length, u_char *dest, u_char **code_ptr_ptr)
 1729 {
 1730         u_char *end = src + length;
 1731         u_char *code_ptr = *code_ptr_ptr;
 1732         u_char code = Stuff_NoCode, count = 0;
 1733 
 1734         if (!length) return (dest);
 1735 
 1736         if (code_ptr) { /* Recover state from last call, if applicable */
 1737                 code  = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask;
 1738                 count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask;
 1739         }
 1740 
 1741         while (src < end) {
 1742                 switch (code) {
 1743                 /*
 1744                  * Stuff_NoCode: If no current code, select one
 1745                  */
 1746                 case Stuff_NoCode:
 1747                         code_ptr = dest++;      /* Record where we're going to put this code */
 1748                         count = 0;              /* Reset the count (zero means one instance) */
 1749                                                         /* Tentatively start a new block */
 1750                         if (*src == 0) {
 1751                                 code = Stuff_Zero;
 1752                                 src++;
 1753                         } else {
 1754                                 code = Stuff_Same;
 1755                                 *dest++ = *src++ ^ Stuff_Magic;
 1756                         }
 1757                         /* Note: We optimistically assume run of same -- which will be */
 1758                         /* fixed later in Stuff_Same if it turns out not to be true. */
 1759                         break;
 1760 
 1761                 /*
 1762                  * Stuff_Zero: We already have at least one zero encoded
 1763                  */
 1764                 case Stuff_Zero:
 1765 
 1766                         /* If another zero, count it, else finish this code block */
 1767                         if (*src == 0) {
 1768                                 count++;
 1769                                 src++;
 1770                         } else
 1771                                 StuffData_FinishBlock(Stuff_Zero + count);
 1772                         break;
 1773 
 1774                 /*
 1775                  * Stuff_Same: We already have at least one byte encoded
 1776                  */
 1777                 case Stuff_Same:
 1778                         /* If another one the same, count it */
 1779                         if ((*src ^ Stuff_Magic) == code_ptr[1]) {
 1780                                 count++;
 1781                                 src++;
 1782                                 break;
 1783                         }
 1784                         /* else, this byte does not match this block. */
 1785                         /* If we already have two or more bytes encoded, finish this code block */
 1786                         if (count) {
 1787                                 StuffData_FinishBlock(Stuff_Same + count);
 1788                                 break;
 1789                         }
 1790                         /* else, we only have one so far, so switch to Stuff_Diff code */
 1791                         code = Stuff_Diff; /* and fall through to Stuff_Diff case below */
 1792 
 1793                 case Stuff_Diff:        /* Stuff_Diff: We have at least two *different* bytes encoded */
 1794                         /* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */
 1795                         if (*src == 0)
 1796                                 StuffData_FinishBlock(Stuff_DiffZero + count);
 1797                         /* else, if we have three in a row, it is worth starting a Stuff_Same block */
 1798                         else if ((*src ^ Stuff_Magic) == dest[-1] && dest[-1] == dest[-2])
 1799                                 {
 1800                                 code += count-2;
 1801                                 if (code == Stuff_Diff)
 1802                                         code = Stuff_Same;
 1803                                 StuffData_FinishBlock(code);
 1804                                 code_ptr = dest-2;
 1805                                 /* dest[-1] already holds the correct value */
 1806                                 count = 2;              /* 2 means three bytes encoded */
 1807                                 code = Stuff_Same;
 1808                                 }
 1809                         /* else, another different byte, so add it to the block */
 1810                         else {
 1811                                 *dest++ = *src ^ Stuff_Magic;
 1812                                 count++;
 1813                         }
 1814                         src++;  /* Consume the byte */
 1815                         break;
 1816                 }
 1817 
 1818                 if (count == Stuff_MaxCount)
 1819                         StuffData_FinishBlock(code + count);
 1820                 }
 1821         if (code == Stuff_NoCode)
 1822                 *code_ptr_ptr = NULL;
 1823         else {
 1824                 *code_ptr_ptr = code_ptr;
 1825                 StuffData_FinishBlock(code + count);
 1826         }
 1827 
 1828         return (dest);
 1829 }
 1830 
 1831 
 1832 
 1833 /*
 1834  * UnStuffData decodes the data at "src", up to (but not including)
 1835  * "end".  It writes the decoded data into the buffer pointed to by
 1836  * "dst", up to a  maximum of "dst_length", and returns the new
 1837  * value of "src" so that a follow-on call can read more data,
 1838  * continuing from where the first left off.
 1839  *
 1840  * There are three types of results:
 1841  * 1. The source data runs out before extracting "dst_length" bytes:
 1842  *    UnStuffData returns NULL to indicate failure.
 1843  * 2. The source data produces exactly "dst_length" bytes:
 1844  *    UnStuffData returns new_src = end to indicate that all bytes
 1845  *    were consumed.
 1846  * 3. "dst_length" bytes are extracted, with more
 1847  *     remaining. UnStuffData returns new_src < end to indicate that
 1848  *     there are more bytes to be read.
 1849  *
 1850  * Note: The decoding may be dstructive, in that it may alter the
 1851  * source data in the process of decoding it (this is necessary to
 1852  * allow a follow-on  call to resume correctly).
 1853  */
 1854 
 1855 static u_char*
 1856 UnStuffData(u_char *src, u_char *end, u_char *dst, u_long dst_length)
 1857 {
 1858         u_char *dst_end = dst + dst_length;
 1859 
 1860         /* Sanity check */
 1861         if (!src || !end || !dst || !dst_length)
 1862                 return (NULL);
 1863 
 1864         while (src < end && dst < dst_end)
 1865         {
 1866                 int count = (*src ^ Stuff_Magic) & Stuff_CountMask;
 1867                 switch ((*src ^ Stuff_Magic) & Stuff_CodeMask)
 1868                         {
 1869                         case Stuff_Diff:
 1870                                 if (src+1+count >= end)
 1871                                         return (NULL);
 1872                                 do
 1873                                 {
 1874                                         *dst++ = *++src ^ Stuff_Magic;
 1875                                 }
 1876                                 while(--count >= 0 && dst < dst_end);
 1877                                 if (count < 0)
 1878                                         src += 1;
 1879                                 else
 1880                                  if (count == 0)
 1881                                         *src = Stuff_Same ^ Stuff_Magic;
 1882                                 else
 1883                                         *src = (Stuff_Diff + count) ^ Stuff_Magic;
 1884                                 break;
 1885                         case Stuff_DiffZero:
 1886                                 if (src+1+count >= end)
 1887                                         return (NULL);
 1888                                 do
 1889                                 {
 1890                                         *dst++ = *++src ^ Stuff_Magic;
 1891                                 }
 1892                                 while(--count >= 0 && dst < dst_end);
 1893                                 if (count < 0)
 1894                                         *src = Stuff_Zero ^ Stuff_Magic;
 1895                                 else
 1896                                         *src = (Stuff_DiffZero + count) ^ Stuff_Magic;
 1897                                 break;
 1898                         case Stuff_Same:
 1899                                 if (src+1 >= end)
 1900                                         return (NULL);
 1901                                 do
 1902                                 {
 1903                                         *dst++ = src[1] ^ Stuff_Magic;
 1904                                 }
 1905                                 while(--count >= 0 && dst < dst_end);
 1906                                 if (count < 0)
 1907                                         src += 2;
 1908                                 else
 1909                                         *src = (Stuff_Same + count) ^ Stuff_Magic;
 1910                                 break;
 1911                         case Stuff_Zero:
 1912                                 do
 1913                                 {
 1914                                         *dst++ = 0;
 1915                                 }
 1916                                 while(--count >= 0 && dst < dst_end);
 1917                                 if (count < 0)
 1918                                         src += 1;
 1919                                 else
 1920                                         *src = (Stuff_Zero + count) ^ Stuff_Magic;
 1921                                 break;
 1922                         }
 1923         }
 1924 
 1925         if (dst < dst_end)
 1926                 return (NULL);
 1927         else
 1928                 return (src);
 1929 }
 1930 
 1931 
 1932 
 1933 /*
 1934  * Log an error mesesage (for a packet received with errors?)
 1935  * from the STRIP driver.
 1936  */
 1937 static void
 1938 RecvErr(const char *msg, struct strip_softc *sc)
 1939 {
 1940 #define MAX_RecErr      80
 1941         u_char *ptr = sc->sc_pktstart;
 1942         u_char *end = sc->sc_mp;
 1943         u_char pkt_text[MAX_RecErr], *p = pkt_text;
 1944         *p++ = '\"';
 1945         while (ptr < end && p < &pkt_text[MAX_RecErr-4]) {
 1946                 if (*ptr == '\\') {
 1947                         *p++ = '\\';
 1948                         *p++ = '\\';
 1949                 } else if (*ptr >= 32 && *ptr <= 126)
 1950                         *p++ = *ptr;
 1951                 else {
 1952                         snprintf(p, sizeof(pkt_text) - (p - pkt_text),
 1953                             "\\%02x", *ptr);
 1954                         p += 3;
 1955                 }
 1956                 ptr++;
 1957         }
 1958 
 1959         if (ptr == end) *p++ = '\"';
 1960         *p++ = 0;
 1961         addlog("%s: %13s : %s\n", sc->sc_if.if_xname, msg, pkt_text);
 1962 
 1963         sc->sc_if.if_ierrors++;
 1964 }
 1965 
 1966 
 1967 /*
 1968  * Parse an error message from the radio.
 1969  */
 1970 static void
 1971 RecvErr_Message(struct strip_softc *strip_info, u_char *sendername,
 1972     const u_char *msg)
 1973 {
 1974         static const char ERR_001[] = "001"; /* Not in StarMode! */
 1975         static const char ERR_002[] = "002"; /* Remap handle */
 1976         static const char ERR_003[] = "003"; /* Can't resolve name */
 1977         static const char ERR_004[] = "004"; /* Name too small or missing */
 1978         static const char ERR_005[] = "005"; /* Bad count specification */
 1979         static const char ERR_006[] = "006"; /* Header too big */
 1980         static const char ERR_007[] = "007"; /* Body too big */
 1981         static const char ERR_008[] = "008"; /* Bad character in name */
 1982         static const char ERR_009[] = "009"; /* No count or line terminator */
 1983 
 1984         char * if_name;
 1985 
 1986         if_name = strip_info->sc_if.if_xname;
 1987 
 1988         if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1))
 1989         {
 1990                 RecvErr("radio error message:", strip_info);
 1991                 addlog("%s: Radio %s is not in StarMode\n",
 1992                         if_name, sendername);
 1993         }
 1994         else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1))
 1995         {
 1996                 RecvErr("radio error message:", strip_info);
 1997 #ifdef notyet           /*Kernel doesn't have scanf!*/
 1998                 int handle;
 1999                 u_char newname[64];
 2000                 sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname);
 2001                 addlog("%s: Radio name %s is handle %d\n",
 2002                         if_name, newname, handle);
 2003 #endif
 2004         }
 2005         else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1))
 2006         {
 2007                 RecvErr("radio error message:", strip_info);
 2008                 addlog("%s: Destination radio name is unknown\n", if_name);
 2009         }
 2010         else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) {
 2011                 /*
 2012                  * The radio reports it got a badly-framed starmode packet
 2013                  * from us; so it must me in starmode.
 2014                  */
 2015                 if (strip_info->sc_if.if_flags & IFF_DEBUG)
 2016                         addlog("%s: radio responded to probe\n", if_name);
 2017                 if (strip_info->sc_state == ST_DEAD) {
 2018                         /* A successful reset... */
 2019                         addlog("%s: Radio back in starmode\n", if_name);
 2020                 }
 2021                 CLEAR_RESET_TIMER(strip_info);
 2022         }
 2023         else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1))
 2024                 RecvErr("radio error message:", strip_info);
 2025         else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1))
 2026                 RecvErr("radio error message:", strip_info);
 2027         else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1))
 2028          {
 2029                 /*
 2030                  *      Note: This error knocks the radio back into
 2031                  *      command mode.
 2032                  */
 2033                 RecvErr("radio error message:", strip_info);
 2034                 printf("%s: Error! Packet size too big for radio.",
 2035                     if_name);
 2036                 FORCE_RESET(strip_info);
 2037         }
 2038         else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1))
 2039         {
 2040                 RecvErr("radio error message:", strip_info);
 2041                 printf("%s: Radio name contains illegal character\n",
 2042                     if_name);
 2043         }
 2044         else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1))
 2045                 RecvErr("radio error message:", strip_info);
 2046         else {
 2047                 addlog("failed to parse ]%3s[\n", msg);
 2048                 RecvErr("unparsed radio error message:", strip_info);
 2049         }
 2050 }

Cache object: 92f2596af17a12274b17778be42ffee9


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