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