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 */ |
137 | typedef u_char ttychar_t; |
138 | #else |
139 | typedef 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 | |
215 | static int strip_clone_create(struct if_clone *, int); |
216 | static int strip_clone_destroy(struct ifnet *); |
217 | |
218 | static LIST_HEAD(, strip_softc) strip_softc_list; |
219 | |
220 | struct 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 | |
225 | static void stripintr(void *); |
226 | |
227 | static int stripcreate(struct strip_softc *); |
228 | static 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 |
246 | struct { |
247 | u_char [STARMODE_ADDR_LEN]; |
248 | u_char [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 | */ |
257 | static u_char* UnStuffData(u_char *src, u_char *end, u_char |
258 | *dest, u_long dest_length); |
259 | |
260 | static u_char* StuffData(u_char *src, u_long length, u_char *dest, |
261 | u_char **code_ptr_ptr); |
262 | |
263 | static void RecvErr(const char *msg, struct strip_softc *sc); |
264 | static void RecvErr_Message(struct strip_softc *strip_info, |
265 | u_char *sendername, const u_char *msg); |
266 | void strip_resetradio(struct strip_softc *sc, struct tty *tp); |
267 | void strip_proberadio(struct strip_softc *sc, struct tty *tp); |
268 | void strip_watchdog(struct ifnet *ifp); |
269 | void strip_sendbody(struct strip_softc *sc, struct mbuf *m); |
270 | int strip_newpacket(struct strip_softc *sc, u_char *ptr, u_char *end); |
271 | void strip_send(struct strip_softc *sc, struct mbuf *m0); |
272 | |
273 | void 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 | |
332 | static int stripclose(struct tty *, int); |
333 | static int stripinput(int, struct tty *); |
334 | static int stripioctl(struct ifnet *, u_long, void *); |
335 | static int stripopen(dev_t, struct tty *); |
336 | static int stripoutput(struct ifnet *, |
337 | struct mbuf *, const struct sockaddr *, |
338 | const struct rtentry *); |
339 | static int stripstart(struct tty *); |
340 | static int striptioctl(struct tty *, u_long, void *, int, struct lwp *); |
341 | |
342 | static 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 | |
355 | void |
356 | stripattach(void) |
357 | { |
358 | /* |
359 | * Nothing to do here, initialization is handled by the |
360 | * module initialization code in slinit() below). |
361 | */ |
362 | } |
363 | |
364 | static void |
365 | stripinit(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 | |
374 | static int |
375 | stripdetach(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 | |
391 | static int |
392 | strip_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 | |
421 | static int |
422 | strip_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 | |
438 | static int |
439 | stripcreate(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 */ |
495 | int |
496 | stripopen(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 | */ |
570 | static int |
571 | stripclose(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 */ |
637 | int |
638 | striptioctl(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 | */ |
658 | void |
659 | strip_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 | */ |
698 | void |
699 | strip_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 | */ |
751 | int |
752 | stripoutput(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 | */ |
906 | int |
907 | stripstart(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 | */ |
934 | static struct mbuf * |
935 | strip_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 | */ |
972 | int |
973 | stripinput(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 | |
1061 | error: |
1062 | sc->sc_if.if_ierrors++; |
1063 | |
1064 | newpack: |
1065 | sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf + |
1066 | BUFOFFSET; |
1067 | |
1068 | return (0); |
1069 | } |
1070 | |
1071 | static void |
1072 | stripintr(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 | */ |
1272 | int |
1273 | stripioctl(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 | */ |
1331 | void |
1332 | strip_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 | */ |
1379 | void |
1380 | strip_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 |
1405 | static 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 | */ |
1417 | void |
1418 | strip_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 | */ |
1452 | void |
1453 | strip_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 | */ |
1545 | int |
1546 | strip_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 | */ |
1647 | typedef 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 | |
1680 | static u_char* |
1681 | StuffData(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 | |
1808 | static u_char* |
1809 | UnStuffData(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 | */ |
1890 | static void |
1891 | RecvErr(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 | */ |
1923 | static void |
1924 | RecvErr_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 | |
2010 | IF_MODULE(MODULE_CLASS_DRIVER, strip, "slcompress" ); |
2011 | |