Annotation of sys/net/if_strip.c, Revision 1.1.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