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