[BACK]Return to if_strip.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/if_strip.c, Revision 1.1

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

CVSweb