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