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