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

Cache object: 22c59e9c58751ed0e4049d7e8d8d4203


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