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