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