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