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