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