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

Cache object: 44f296a17e063935cdf0496bfca2cd99


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