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