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