if_sl.c revision 1.125 1 /* $NetBSD: if_sl.c,v 1.125 2016/08/06 12:48:23 christos Exp $ */
2
3 /*
4 * Copyright (c) 1987, 1989, 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)if_sl.c 8.9 (Berkeley) 1/9/95
32 */
33
34 /*
35 * Serial Line interface
36 *
37 * Rick Adams
38 * Center for Seismic Studies
39 * 1300 N 17th Street, Suite 1450
40 * Arlington, Virginia 22209
41 * (703)276-7900
42 * rick (at) seismo.ARPA
43 * seismo!rick
44 *
45 * Pounded on heavily by Chris Torek (chris (at) mimsy.umd.edu, umcp-cs!chris).
46 * N.B.: this belongs in netinet, not net, the way it stands now.
47 * Should have a link-layer type designation, but wouldn't be
48 * backwards-compatible.
49 *
50 * Converted to 4.3BSD Beta by Chris Torek.
51 * Other changes made at Berkeley, based in part on code by Kirk Smith.
52 * W. Jolitz added slip abort.
53 *
54 * Hacked almost beyond recognition by Van Jacobson (van (at) helios.ee.lbl.gov).
55 * Added priority queuing for "interactive" traffic; hooks for TCP
56 * header compression; ICMP filtering (at 2400 baud, some cretin
57 * pinging you can use up all your bandwidth). Made low clist behavior
58 * more robust and slightly less likely to hang serial line.
59 * Sped up a bunch of things.
60 */
61
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: if_sl.c,v 1.125 2016/08/06 12:48:23 christos Exp $");
64
65 #ifdef _KERNEL_OPT
66 #include "opt_inet.h"
67 #endif
68
69 #include <sys/param.h>
70 #include <sys/proc.h>
71 #include <sys/malloc.h>
72 #include <sys/mbuf.h>
73 #include <sys/buf.h>
74 #include <sys/dkstat.h>
75 #include <sys/socket.h>
76 #include <sys/ioctl.h>
77 #include <sys/file.h>
78 #include <sys/conf.h>
79 #include <sys/tty.h>
80 #include <sys/kernel.h>
81 #include <sys/socketvar.h>
82 #if __NetBSD__
83 #include <sys/systm.h>
84 #include <sys/kauth.h>
85 #endif
86 #include <sys/cpu.h>
87 #include <sys/intr.h>
88 #include <sys/device.h>
89 #include <sys/module.h>
90
91 #include <net/if.h>
92 #include <net/if_types.h>
93 #include <net/netisr.h>
94 #include <net/route.h>
95
96 #ifdef INET
97 #include <netinet/in.h>
98 #include <netinet/in_systm.h>
99 #include <netinet/in_var.h>
100 #include <netinet/ip.h>
101 #endif
102
103 #include <net/slcompress.h>
104 #include <net/if_slvar.h>
105 #include <net/slip.h>
106 #include <net/ppp_defs.h>
107 #include <net/if_ppp.h>
108
109 #include <sys/time.h>
110 #include <net/bpf.h>
111
112 #include "ioconf.h"
113
114 /*
115 * SLMAX is a hard limit on input packet size. To simplify the code
116 * and improve performance, we require that packets fit in an mbuf
117 * cluster, and if we get a compressed packet, there's enough extra
118 * room to expand the header into a max length tcp/ip header (128
119 * bytes). So, SLMAX can be at most
120 * MCLBYTES - 128
121 *
122 * SLMTU is a hard limit on output packet size. To insure good
123 * interactive response, SLMTU wants to be the smallest size that
124 * amortizes the header cost. (Remember that even with
125 * type-of-service queuing, we have to wait for any in-progress
126 * packet to finish. I.e., we wait, on the average, 1/2 * mtu /
127 * cps, where cps is the line speed in characters per second.
128 * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The
129 * average compressed header size is 6-8 bytes so any MTU > 90
130 * bytes will give us 90% of the line bandwidth. A 100ms wait is
131 * tolerable (500ms is not), so want an MTU around 296. (Since TCP
132 * will send 256 byte segments (to allow for 40 byte headers), the
133 * typical packet size on the wire will be around 260 bytes). In
134 * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
135 * leave the interface MTU relatively high (so we don't IP fragment
136 * when acting as a gateway to someone using a stupid MTU).
137 *
138 * Similar considerations apply to SLIP_HIWAT: It's the amount of
139 * data that will be queued 'downstream' of us (i.e., in clists
140 * waiting to be picked up by the tty output interrupt). If we
141 * queue a lot of data downstream, it's immune to our t.o.s. queuing.
142 * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
143 * telnet/ftp will see a 1 sec wait, independent of the mtu (the
144 * wait is dependent on the ftp window size but that's typically
145 * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize
146 * the cost (in idle time on the wire) of the tty driver running
147 * off the end of its clists & having to call back slstart for a
148 * new packet. For a tty interface with any buffering at all, this
149 * cost will be zero. Even with a totally brain dead interface (like
150 * the one on a typical workstation), the cost will be <= 1 character
151 * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
152 * at most 1% while maintaining good interactive response.
153 */
154 #define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
155 #define SLMAX (MCLBYTES - BUFOFFSET)
156 #define SLBUFSIZE (SLMAX + BUFOFFSET)
157 #ifndef SLMTU
158 #define SLMTU 296
159 #endif
160 #if (SLMTU < 3)
161 #error SLMTU way too small.
162 #endif
163 #define SLIP_HIWAT roundup(50, TTROUND)
164 #ifndef __NetBSD__ /* XXX - cgd */
165 #define CLISTRESERVE 1024 /* Can't let clists get too low */
166 #endif /* !__NetBSD__ */
167
168 /*
169 * SLIP ABORT ESCAPE MECHANISM:
170 * (inspired by HAYES modem escape arrangement)
171 * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
172 * within window time signals a "soft" exit from slip mode by remote end
173 * if the IFF_DEBUG flag is on.
174 */
175 #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/
176 #define ABT_IDLE 1 /* in seconds - idle before an escape */
177 #define ABT_COUNT 3 /* count of escapes for abort */
178 #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */
179
180 static int sl_clone_create(struct if_clone *, int);
181 static int sl_clone_destroy(struct ifnet *);
182
183 static LIST_HEAD(, sl_softc) sl_softc_list;
184
185 struct if_clone sl_cloner =
186 IF_CLONE_INITIALIZER("sl", sl_clone_create, sl_clone_destroy);
187
188 #define FRAME_END 0xc0 /* Frame End */
189 #define FRAME_ESCAPE 0xdb /* Frame Esc */
190 #define TRANS_FRAME_END 0xdc /* transposed frame end */
191 #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */
192
193 static void slintr(void *);
194
195 static int slcreate(struct sl_softc *);
196 static struct mbuf *sl_btom(struct sl_softc *, int);
197
198 static int slclose(struct tty *, int);
199 static int slinput(int, struct tty *);
200 static int slioctl(struct ifnet *, u_long, void *);
201 static int slopen(dev_t, struct tty *);
202 static int sloutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
203 const struct rtentry *);
204 static int slstart(struct tty *);
205 static int sltioctl(struct tty *, u_long, void *, int, struct lwp *);
206
207 static struct linesw slip_disc = {
208 .l_name = "slip",
209 .l_open = slopen,
210 .l_close = slclose,
211 .l_read = ttyerrio,
212 .l_write = ttyerrio,
213 .l_ioctl = sltioctl,
214 .l_rint = slinput,
215 .l_start = slstart,
216 .l_modem = nullmodem,
217 .l_poll = ttyerrpoll
218 };
219
220 void
221 slattach(int n __unused)
222 {
223
224 /*
225 * Nothing to do here, initialization is handled by the
226 * module initialization code in slinit() below).
227 */
228 }
229
230 static void
231 slinit(void)
232 {
233
234 if (ttyldisc_attach(&slip_disc) != 0)
235 panic("%s", __func__);
236 LIST_INIT(&sl_softc_list);
237 if_clone_attach(&sl_cloner);
238 }
239
240 static int
241 sldetach(void)
242 {
243 int error = 0;
244
245 if (!LIST_EMPTY(&sl_softc_list))
246 error = EBUSY;
247
248 if (error == 0)
249 error = ttyldisc_detach(&slip_disc);
250
251 return error;
252 }
253
254 static int
255 sl_clone_create(struct if_clone *ifc, int unit)
256 {
257 struct sl_softc *sc;
258
259 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAIT|M_ZERO);
260 sc->sc_unit = unit;
261 if_initname(&sc->sc_if, ifc->ifc_name, unit);
262 sc->sc_if.if_softc = sc;
263 sc->sc_if.if_mtu = SLMTU;
264 sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
265 sc->sc_if.if_type = IFT_SLIP;
266 sc->sc_if.if_ioctl = slioctl;
267 sc->sc_if.if_output = sloutput;
268 sc->sc_if.if_dlt = DLT_SLIP;
269 sc->sc_fastq.ifq_maxlen = 32;
270 IFQ_SET_READY(&sc->sc_if.if_snd);
271 if_attach(&sc->sc_if);
272 if_alloc_sadl(&sc->sc_if);
273 bpf_attach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
274 LIST_INSERT_HEAD(&sl_softc_list, sc, sc_iflist);
275 return 0;
276 }
277
278 static int
279 sl_clone_destroy(struct ifnet *ifp)
280 {
281 struct sl_softc *sc = (struct sl_softc *)ifp->if_softc;
282
283 if (sc->sc_ttyp != NULL)
284 return EBUSY; /* Not removing it */
285
286 LIST_REMOVE(sc, sc_iflist);
287
288 bpf_detach(ifp);
289 if_detach(ifp);
290
291 free(sc, M_DEVBUF);
292 return 0;
293 }
294
295 static int
296 slcreate(struct sl_softc *sc)
297 {
298
299 if (sc->sc_mbuf == NULL) {
300 sc->sc_mbuf = m_gethdr(M_WAIT, MT_DATA);
301 m_clget(sc->sc_mbuf, M_WAIT);
302 }
303 sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
304 sc->sc_mbuf->m_ext.ext_size;
305 sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
306 BUFOFFSET;
307
308 #ifdef INET
309 sl_compress_init(&sc->sc_comp);
310 #endif
311
312 return 1;
313 }
314
315 /*
316 * Line specific open routine.
317 * Attach the given tty to the first available sl unit.
318 */
319 /* ARGSUSED */
320 static int
321 slopen(dev_t dev, struct tty *tp)
322 {
323 struct lwp *l = curlwp; /* XXX */
324 struct sl_softc *sc;
325 int error;
326
327 error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_SLIP,
328 KAUTH_REQ_NETWORK_INTERFACE_SLIP_ADD, NULL, NULL, NULL);
329 if (error)
330 return error;
331
332 if (tp->t_linesw == &slip_disc)
333 return 0;
334
335 LIST_FOREACH(sc, &sl_softc_list, sc_iflist)
336 if (sc->sc_ttyp == NULL) {
337 sc->sc_si = softint_establish(SOFTINT_NET,
338 slintr, sc);
339 if (sc->sc_si == NULL)
340 return ENOMEM;
341 if (slcreate(sc) == 0) {
342 softint_disestablish(sc->sc_si);
343 return ENOBUFS;
344 }
345 tp->t_sc = (void *)sc;
346 sc->sc_ttyp = tp;
347 sc->sc_if.if_baudrate = tp->t_ospeed;
348 mutex_spin_enter(&tty_lock);
349 tp->t_state |= TS_ISOPEN | TS_XCLUDE;
350 ttyflush(tp, FREAD | FWRITE);
351 /*
352 * make sure tty output queue is large enough
353 * to hold a full-sized packet (including frame
354 * end, and a possible extra frame end). full-sized
355 * packet occupies a max of 2*SLMAX bytes (because
356 * of possible escapes), and add two on for frame
357 * ends.
358 */
359 if (tp->t_outq.c_cn < 2 * SLMAX + 2) {
360 sc->sc_oldbufsize = tp->t_outq.c_cn;
361 sc->sc_oldbufquot = tp->t_outq.c_cq != 0;
362
363 clfree(&tp->t_outq);
364 mutex_spin_exit(&tty_lock);
365 error = clalloc(&tp->t_outq, 2 * SLMAX + 2, 0);
366 if (error) {
367 softint_disestablish(sc->sc_si);
368 /*
369 * clalloc() might return -1 which
370 * is no good, so we need to return
371 * something else.
372 */
373 return ENOMEM; /* XXX ?! */
374 }
375 } else {
376 sc->sc_oldbufsize = sc->sc_oldbufquot = 0;
377 mutex_spin_exit(&tty_lock);
378 }
379 return 0;
380 }
381 return ENXIO;
382 }
383
384 /*
385 * Line specific close routine.
386 * Detach the tty from the sl unit.
387 */
388 static int
389 slclose(struct tty *tp, int flag)
390 {
391 struct sl_softc *sc;
392 int s;
393
394 ttywflush(tp);
395 sc = tp->t_sc;
396
397 if (sc != NULL) {
398 softint_disestablish(sc->sc_si);
399 s = splnet();
400 if_down(&sc->sc_if);
401 IF_PURGE(&sc->sc_fastq);
402 splx(s);
403
404 s = spltty();
405 ttyldisc_release(tp->t_linesw);
406 tp->t_linesw = ttyldisc_default();
407 tp->t_state = 0;
408
409 sc->sc_ttyp = NULL;
410 tp->t_sc = NULL;
411
412 m_freem(sc->sc_mbuf);
413 sc->sc_mbuf = NULL;
414 sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL;
415 IF_PURGE(&sc->sc_inq);
416
417 /*
418 * If necessary, install a new outq buffer of the
419 * appropriate size.
420 */
421 if (sc->sc_oldbufsize != 0) {
422 clfree(&tp->t_outq);
423 clalloc(&tp->t_outq, sc->sc_oldbufsize,
424 sc->sc_oldbufquot);
425 }
426 splx(s);
427 }
428
429 return 0;
430 }
431
432 /*
433 * Line specific (tty) ioctl routine.
434 * Provide a way to get the sl unit number.
435 */
436 /* ARGSUSED */
437 static int
438 sltioctl(struct tty *tp, u_long cmd, void *data, int flag,
439 struct lwp *l)
440 {
441 struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
442
443 switch (cmd) {
444 case SLIOCGUNIT:
445 *(int *)data = sc->sc_unit; /* XXX */
446 break;
447
448 default:
449 return EPASSTHROUGH;
450 }
451 return 0;
452 }
453
454 /*
455 * Queue a packet. Start transmission if not active.
456 * Compression happens in slintr(); if we do it here, IP TOS
457 * will cause us to not compress "background" packets, because
458 * ordering gets trashed. It can be done for all packets in slintr().
459 */
460 static int
461 sloutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
462 const struct rtentry *rtp)
463 {
464 struct sl_softc *sc = ifp->if_softc;
465 struct ip *ip;
466 struct ifqueue *ifq = NULL;
467 int s, error;
468
469 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
470
471 /*
472 * `Cannot happen' (see slioctl). Someday we will extend
473 * the line protocol to support other address families.
474 */
475 if (dst->sa_family != AF_INET) {
476 printf("%s: af%d not supported\n", sc->sc_if.if_xname,
477 dst->sa_family);
478 m_freem(m);
479 sc->sc_if.if_noproto++;
480 return EAFNOSUPPORT;
481 }
482
483 if (sc->sc_ttyp == NULL) {
484 m_freem(m);
485 return ENETDOWN; /* sort of */
486 }
487 if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
488 (sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
489 m_freem(m);
490 printf("%s: no carrier and not local\n", sc->sc_if.if_xname);
491 return EHOSTUNREACH;
492 }
493 ip = mtod(m, struct ip *);
494 #ifdef INET
495 if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
496 m_freem(m);
497 return ENETRESET; /* XXX ? */
498 }
499 #endif
500
501 s = spltty();
502 if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
503 struct bintime bt;
504
505 /* if output's been stalled for too long, and restart */
506 getbinuptime(&bt);
507 bintime_sub(&bt, &sc->sc_lastpacket);
508 if (bt.sec > 0) {
509 sc->sc_otimeout++;
510 slstart(sc->sc_ttyp);
511 }
512 }
513 splx(s);
514
515 s = splnet();
516 #ifdef INET
517 if ((ip->ip_tos & IPTOS_LOWDELAY) != 0)
518 ifq = &sc->sc_fastq;
519 #endif
520 if ((error = ifq_enqueue2(ifp, ifq, m)) != 0) {
521 splx(s);
522 return error;
523 }
524 getbinuptime(&sc->sc_lastpacket);
525 splx(s);
526
527 s = spltty();
528 if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0)
529 slstart(sc->sc_ttyp);
530 splx(s);
531
532 return 0;
533 }
534
535 /*
536 * Start output on interface. Get another datagram
537 * to send from the interface queue and map it to
538 * the interface before starting output.
539 */
540 static int
541 slstart(struct tty *tp)
542 {
543 struct sl_softc *sc = tp->t_sc;
544
545 /*
546 * If there is more in the output queue, just send it now.
547 * We are being called in lieu of ttstart and must do what
548 * it would.
549 */
550 if (tp->t_outq.c_cc != 0) {
551 (*tp->t_oproc)(tp);
552 if (tp->t_outq.c_cc > SLIP_HIWAT)
553 return 0;
554 }
555
556 /*
557 * This happens briefly when the line shuts down.
558 */
559 if (sc == NULL)
560 return 0;
561 softint_schedule(sc->sc_si);
562 return 0;
563 }
564
565 /*
566 * Copy data buffer to mbuf chain; add ifnet pointer.
567 */
568 static struct mbuf *
569 sl_btom(struct sl_softc *sc, int len)
570 {
571 struct mbuf *m;
572
573 /*
574 * Allocate a new input buffer and swap.
575 */
576 m = sc->sc_mbuf;
577 MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA);
578 if (sc->sc_mbuf == NULL) {
579 sc->sc_mbuf = m;
580 return NULL;
581 }
582 MCLGET(sc->sc_mbuf, M_DONTWAIT);
583 if ((sc->sc_mbuf->m_flags & M_EXT) == 0) {
584 m_freem(sc->sc_mbuf);
585 sc->sc_mbuf = m;
586 return NULL;
587 }
588 sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
589 sc->sc_mbuf->m_ext.ext_size;
590
591 m->m_data = sc->sc_pktstart;
592
593 m->m_pkthdr.len = m->m_len = len;
594 m_set_rcvif(m, &sc->sc_if);
595 return m;
596 }
597
598 /*
599 * tty interface receiver interrupt.
600 */
601 static int
602 slinput(int c, struct tty *tp)
603 {
604 struct sl_softc *sc;
605 struct mbuf *m;
606 int len;
607
608 tk_nin++;
609 sc = (struct sl_softc *)tp->t_sc;
610 if (sc == NULL)
611 return 0;
612 if ((c & TTY_ERRORMASK) || ((tp->t_state & TS_CARR_ON) == 0 &&
613 (tp->t_cflag & CLOCAL) == 0)) {
614 sc->sc_flags |= SC_ERROR;
615 return 0;
616 }
617 c &= TTY_CHARMASK;
618
619 ++sc->sc_if.if_ibytes;
620
621 if (sc->sc_if.if_flags & IFF_DEBUG) {
622 if (c == ABT_ESC) {
623 /*
624 * If we have a previous abort, see whether
625 * this one is within the time limit.
626 */
627 if (sc->sc_abortcount &&
628 time_second >= sc->sc_starttime + ABT_WINDOW)
629 sc->sc_abortcount = 0;
630 /*
631 * If we see an abort after "idle" time, count it;
632 * record when the first abort escape arrived.
633 */
634 if (time_second >= sc->sc_lasttime + ABT_IDLE) {
635 if (++sc->sc_abortcount == 1)
636 sc->sc_starttime = time_second;
637 if (sc->sc_abortcount >= ABT_COUNT) {
638 slclose(tp, 0);
639 return 0;
640 }
641 }
642 } else
643 sc->sc_abortcount = 0;
644 sc->sc_lasttime = time_second;
645 }
646
647 switch (c) {
648
649 case TRANS_FRAME_ESCAPE:
650 if (sc->sc_escape)
651 c = FRAME_ESCAPE;
652 break;
653
654 case TRANS_FRAME_END:
655 if (sc->sc_escape)
656 c = FRAME_END;
657 break;
658
659 case FRAME_ESCAPE:
660 sc->sc_escape = 1;
661 return 0;
662
663 case FRAME_END:
664 if (sc->sc_flags & SC_ERROR) {
665 sc->sc_flags &= ~SC_ERROR;
666 goto newpack;
667 }
668 len = sc->sc_mp - sc->sc_pktstart;
669 if (len < 3)
670 /* less than min length packet - ignore */
671 goto newpack;
672
673 m = sl_btom(sc, len);
674 if (m == NULL)
675 goto error;
676
677 IF_ENQUEUE(&sc->sc_inq, m);
678 softint_schedule(sc->sc_si);
679 goto newpack;
680 }
681 if (sc->sc_mp < sc->sc_ep) {
682 *sc->sc_mp++ = c;
683 sc->sc_escape = 0;
684 return 0;
685 }
686
687 /* can't put lower; would miss an extra frame */
688 sc->sc_flags |= SC_ERROR;
689
690 error:
691 sc->sc_if.if_ierrors++;
692 newpack:
693 sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf +
694 BUFOFFSET;
695 sc->sc_escape = 0;
696
697 return 0;
698 }
699
700 static void
701 slintr(void *arg)
702 {
703 struct sl_softc *sc = arg;
704 struct tty *tp = sc->sc_ttyp;
705 struct mbuf *m;
706 int s, len;
707 u_char *pktstart;
708 #ifdef INET
709 u_char c;
710 #endif
711 u_char chdr[CHDR_LEN];
712
713 KASSERT(tp != NULL);
714
715 /*
716 * Output processing loop.
717 */
718 mutex_enter(softnet_lock);
719 for (;;) {
720 #ifdef INET
721 struct ip *ip;
722 #endif
723 struct mbuf *m2;
724 struct mbuf *bpf_m;
725
726 /*
727 * Do not remove the packet from the queue if it
728 * doesn't look like it will fit into the current
729 * serial output queue. With a packet full of
730 * escapes, this could be as bad as MTU*2+2.
731 */
732 s = spltty();
733 if (tp->t_outq.c_cn - tp->t_outq.c_cc <
734 2 * sc->sc_if.if_mtu + 2) {
735 splx(s);
736 break;
737 }
738 splx(s);
739
740 /*
741 * Get a packet and send it to the interface.
742 */
743 s = splnet();
744 IF_DEQUEUE(&sc->sc_fastq, m);
745 if (m)
746 sc->sc_if.if_omcasts++; /* XXX */
747 else
748 IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
749 splx(s);
750
751 if (m == NULL)
752 break;
753
754 /*
755 * We do the header compression here rather than in
756 * sloutput() because the packets will be out of order
757 * if we are using TOS queueing, and the connection
758 * ID compression will get munged when this happens.
759 */
760 if (sc->sc_if.if_bpf) {
761 /*
762 * We need to save the TCP/IP header before
763 * it's compressed. To avoid complicated
764 * code, we just make a deep copy of the
765 * entire packet (since this is a serial
766 * line, packets should be short and/or the
767 * copy should be negligible cost compared
768 * to the packet transmission time).
769 */
770 bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT);
771 } else
772 bpf_m = NULL;
773 #ifdef INET
774 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
775 if (sc->sc_if.if_flags & SC_COMPRESS)
776 *mtod(m, u_char *) |=
777 sl_compress_tcp(m, ip, &sc->sc_comp, 1);
778 }
779 #endif
780 if (bpf_m)
781 bpf_mtap_sl_out(&sc->sc_if, mtod(m, u_char *), bpf_m);
782 getbinuptime(&sc->sc_lastpacket);
783
784 s = spltty();
785
786 /*
787 * The extra FRAME_END will start up a new packet,
788 * and thus will flush any accumulated garbage. We
789 * do this whenever the line may have been idle for
790 * some time.
791 */
792 if (tp->t_outq.c_cc == 0) {
793 sc->sc_if.if_obytes++;
794 (void)putc(FRAME_END, &tp->t_outq);
795 }
796
797 while (m) {
798 u_char *bp, *cp, *ep;
799
800 bp = cp = mtod(m, u_char *);
801 ep = cp + m->m_len;
802 while (cp < ep) {
803 /*
804 * Find out how many bytes in the
805 * string we can handle without
806 * doing something special.
807 */
808 while (cp < ep) {
809 switch (*cp++) {
810 case FRAME_ESCAPE:
811 case FRAME_END:
812 cp--;
813 goto out;
814 }
815 }
816 out:
817 if (cp > bp) {
818 /*
819 * Put N characters at once
820 * into the tty output queue.
821 */
822 if (b_to_q(bp, cp - bp, &tp->t_outq))
823 break;
824 sc->sc_if.if_obytes += cp - bp;
825 }
826 /*
827 * If there are characters left in
828 * the mbuf, the first one must be
829 * special.. Put it out in a different
830 * form.
831 */
832 if (cp < ep) {
833 if (putc(FRAME_ESCAPE, &tp->t_outq))
834 break;
835 if (putc(*cp++ == FRAME_ESCAPE ?
836 TRANS_FRAME_ESCAPE :
837 TRANS_FRAME_END,
838 &tp->t_outq)) {
839 (void)unputc(&tp->t_outq);
840 break;
841 }
842 sc->sc_if.if_obytes += 2;
843 }
844 bp = cp;
845 }
846 MFREE(m, m2);
847 m = m2;
848 }
849
850 if (putc(FRAME_END, &tp->t_outq)) {
851 /*
852 * Not enough room. Remove a char to make
853 * room and end the packet normally. If
854 * you get many collisions (more than one
855 * or two a day), you probably do not have
856 * enough clists and you should increase
857 * "nclist" in param.c
858 */
859 (void)unputc(&tp->t_outq);
860 (void)putc(FRAME_END, &tp->t_outq);
861 sc->sc_if.if_collisions++;
862 } else {
863 sc->sc_if.if_obytes++;
864 sc->sc_if.if_opackets++;
865 }
866
867 /*
868 * We now have characters in the output queue,
869 * kick the serial port.
870 */
871 (*tp->t_oproc)(tp);
872 splx(s);
873 }
874
875 /*
876 * Input processing loop.
877 */
878 for (;;) {
879 s = spltty();
880 IF_DEQUEUE(&sc->sc_inq, m);
881 splx(s);
882 if (m == NULL)
883 break;
884 pktstart = mtod(m, u_char *);
885 len = m->m_pkthdr.len;
886 if (sc->sc_if.if_bpf) {
887 /*
888 * Save the compressed header, so we
889 * can tack it on later. Note that we
890 * will end up copying garbage in some
891 * cases but this is okay. We remember
892 * where the buffer started so we can
893 * compute the new header length.
894 */
895 memcpy(chdr, pktstart, CHDR_LEN);
896 }
897 #ifdef INET
898 if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) {
899 if (c & 0x80)
900 c = TYPE_COMPRESSED_TCP;
901 else if (c == TYPE_UNCOMPRESSED_TCP)
902 *pktstart &= 0x4f; /* XXX */
903 /*
904 * We've got something that's not an IP
905 * packet. If compression is enabled,
906 * try to decompress it. Otherwise, if
907 * `auto-enable' compression is on and
908 * it's a reasonable packet, decompress
909 * it and then enable compression.
910 * Otherwise, drop it.
911 */
912 if (sc->sc_if.if_flags & SC_COMPRESS) {
913 len = sl_uncompress_tcp(&pktstart, len,
914 (u_int)c, &sc->sc_comp);
915 if (len <= 0) {
916 m_freem(m);
917 continue;
918 }
919 } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
920 c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
921 len = sl_uncompress_tcp(&pktstart, len,
922 (u_int)c, &sc->sc_comp);
923 if (len <= 0) {
924 m_freem(m);
925 continue;
926 }
927 sc->sc_if.if_flags |= SC_COMPRESS;
928 } else {
929 m_freem(m);
930 continue;
931 }
932 }
933 #endif
934 m->m_data = (void *) pktstart;
935 m->m_pkthdr.len = m->m_len = len;
936 if (sc->sc_if.if_bpf) {
937 bpf_mtap_sl_in(&sc->sc_if, chdr, &m);
938 if (m == NULL)
939 continue;
940 }
941 /*
942 * If the packet will fit into a single
943 * header mbuf, copy it into one, to save
944 * memory.
945 */
946 if (m->m_pkthdr.len < MHLEN) {
947 struct mbuf *n;
948 int pktlen;
949
950 MGETHDR(n, M_DONTWAIT, MT_DATA);
951 pktlen = m->m_pkthdr.len;
952 M_MOVE_PKTHDR(n, m);
953 memcpy(mtod(n, void *), mtod(m, void *), pktlen);
954 n->m_len = m->m_len;
955 m_freem(m);
956 m = n;
957 }
958
959 sc->sc_if.if_ipackets++;
960 getbinuptime(&sc->sc_lastpacket);
961
962 #ifdef INET
963 s = splnet();
964 if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) {
965 sc->sc_if.if_ierrors++;
966 sc->sc_if.if_iqdrops++;
967 m_freem(m);
968 }
969 splx(s);
970 #endif
971 }
972 mutex_exit(softnet_lock);
973 }
974
975 /*
976 * Process an ioctl request.
977 */
978 static int
979 slioctl(struct ifnet *ifp, u_long cmd, void *data)
980 {
981 struct ifaddr *ifa = (struct ifaddr *)data;
982 struct ifreq *ifr = (struct ifreq *)data;
983 int s = splnet(), error = 0;
984 struct sl_softc *sc = ifp->if_softc;
985 struct ppp_stats *psp;
986 struct ppp_comp_stats *pcp;
987
988 switch (cmd) {
989
990 case SIOCINITIFADDR:
991 if (ifa->ifa_addr->sa_family == AF_INET)
992 ifp->if_flags |= IFF_UP;
993 else
994 error = EAFNOSUPPORT;
995 break;
996
997 case SIOCSIFDSTADDR:
998 if (ifa->ifa_addr->sa_family != AF_INET)
999 error = EAFNOSUPPORT;
1000 break;
1001
1002 case SIOCSIFMTU:
1003 if ((ifr->ifr_mtu < 3) || (ifr->ifr_mtu > SLMAX)) {
1004 error = EINVAL;
1005 break;
1006 }
1007 /*FALLTHROUGH*/
1008 case SIOCGIFMTU:
1009 if ((error = ifioctl_common(&sc->sc_if, cmd, data)) == ENETRESET)
1010 error = 0;
1011 break;
1012
1013 case SIOCADDMULTI:
1014 case SIOCDELMULTI:
1015 if (ifr == 0) {
1016 error = EAFNOSUPPORT; /* XXX */
1017 break;
1018 }
1019 switch (ifreq_getaddr(cmd, ifr)->sa_family) {
1020
1021 #ifdef INET
1022 case AF_INET:
1023 break;
1024 #endif
1025
1026 default:
1027 error = EAFNOSUPPORT;
1028 break;
1029 }
1030 break;
1031
1032 case SIOCGPPPSTATS:
1033 psp = &((struct ifpppstatsreq *) data)->stats;
1034 (void)memset(psp, 0, sizeof(*psp));
1035 psp->p.ppp_ibytes = sc->sc_if.if_ibytes;
1036 psp->p.ppp_ipackets = sc->sc_if.if_ipackets;
1037 psp->p.ppp_ierrors = sc->sc_if.if_ierrors;
1038 psp->p.ppp_obytes = sc->sc_if.if_obytes;
1039 psp->p.ppp_opackets = sc->sc_if.if_opackets;
1040 psp->p.ppp_oerrors = sc->sc_if.if_oerrors;
1041 #ifdef INET
1042 psp->vj.vjs_packets = sc->sc_comp.sls_packets;
1043 psp->vj.vjs_compressed = sc->sc_comp.sls_compressed;
1044 psp->vj.vjs_searches = sc->sc_comp.sls_searches;
1045 psp->vj.vjs_misses = sc->sc_comp.sls_misses;
1046 psp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin;
1047 psp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin;
1048 psp->vj.vjs_errorin = sc->sc_comp.sls_errorin;
1049 psp->vj.vjs_tossed = sc->sc_comp.sls_tossed;
1050 #endif
1051 break;
1052
1053 case SIOCGPPPCSTATS:
1054 pcp = &((struct ifpppcstatsreq *) data)->stats;
1055 (void)memset(pcp, 0, sizeof(*pcp));
1056 break;
1057
1058 default:
1059 error = ifioctl_common(ifp, cmd, data);
1060 break;
1061 }
1062 splx(s);
1063 return error;
1064 }
1065
1066
1067 /*
1068 * Module infrastructure
1069 */
1070
1071 MODULE(MODULE_CLASS_DRIVER, if_sl, "slcompress");
1072
1073 #ifdef _MODULE
1074 CFDRIVER_DECL(sl, DV_IFNET, NULL);
1075 #endif
1076
1077 static int
1078 if_sl_modcmd(modcmd_t cmd, void *arg)
1079 {
1080 int error = 0;
1081
1082 switch (cmd) {
1083 case MODULE_CMD_INIT:
1084 #ifdef _MODULE
1085 error = config_cfdriver_attach(&sl_cd);
1086 if (error) {
1087 aprint_error("%s: unable to register cfdriver for"
1088 "%s, error %d\n", __func__, sl_cd.cd_name, error);
1089 break;
1090 }
1091
1092 #endif
1093 /* Init the unit list and line discipline stuff */
1094 slinit();
1095 break;
1096
1097 case MODULE_CMD_FINI:
1098 /*
1099 * Make sure it's ok to detach - no units left, and
1100 * line discipline is removed
1101 */
1102 error = sldetach();
1103 if (error != 0)
1104 break;
1105 #ifdef _MODULE
1106 /* Remove device from autoconf database */
1107 error = config_cfdriver_detach(&sl_cd);
1108 if (error) {
1109 aprint_error("%s: failed to detach %s cfdriver, "
1110 "error %d\n", __func__, sl_cd.cd_name, error);
1111 break;
1112 }
1113 #endif
1114 break;
1115
1116 case MODULE_CMD_STAT:
1117 error = ENOTTY;
1118 break;
1119 default:
1120 error = ENOTTY;
1121 break;
1122 }
1123
1124 return error;
1125 }
1126