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 */