xref: /csrg-svn/sys/net/if_sl.c (revision 38365)
133183Sbostic /*
233183Sbostic  * Copyright (c) 1987 Regents of the University of California.
333183Sbostic  * All rights reserved.
433183Sbostic  *
533183Sbostic  * Redistribution and use in source and binary forms are permitted
634844Sbostic  * provided that the above copyright notice and this paragraph are
734844Sbostic  * duplicated in all such forms and that any documentation,
834844Sbostic  * advertising materials, and other materials related to such
934844Sbostic  * distribution and use acknowledge that the software was developed
1034844Sbostic  * by the University of California, Berkeley.  The name of the
1134844Sbostic  * University may not be used to endorse or promote products derived
1234844Sbostic  * from this software without specific prior written permission.
1334844Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434844Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534844Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633183Sbostic  *
17*38365Swilliam  *	@(#)if_sl.c	7.15 (Berkeley) 06/29/89
1833183Sbostic  */
1926122Skarels 
2026121Skarels /*
2126121Skarels  * Serial Line interface
2226121Skarels  *
2326121Skarels  * Rick Adams
2426121Skarels  * Center for Seismic Studies
2526121Skarels  * 1300 N 17th Street, Suite 1450
2626121Skarels  * Arlington, Virginia 22209
2726121Skarels  * (703)276-7900
2826121Skarels  * rick@seismo.ARPA
2926121Skarels  * seismo!rick
3026121Skarels  *
3126121Skarels  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
3226378Skarels  * N.B.: this belongs in netinet, not net, the way it stands now.
3326122Skarels  * Should have a link-layer type designation, but wouldn't be
3426122Skarels  * backwards-compatible.
3526121Skarels  *
3626121Skarels  * Converted to 4.3BSD Beta by Chris Torek.
3726378Skarels  * Other changes made at Berkeley, based in part on code by Kirk Smith.
38*38365Swilliam  * W. Jolitz, added slip abort & time domain window
39*38365Swilliam  * also added Van Jacobson's hdr compression code
4026121Skarels  */
4126121Skarels 
4226121Skarels /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
4326121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
4426121Skarels 
4526121Skarels #include "sl.h"
4626121Skarels #if NSL > 0
4726121Skarels 
4826121Skarels #include "param.h"
49*38365Swilliam #include "dir.h"
5038280Swilliam #include "user.h"
5126121Skarels #include "mbuf.h"
5226121Skarels #include "buf.h"
5337472Ssklower #include "dkstat.h"
5426121Skarels #include "socket.h"
5526121Skarels #include "ioctl.h"
5626378Skarels #include "file.h"
5726121Skarels #include "tty.h"
58*38365Swilliam #include "kernel.h"
59*38365Swilliam #include "conf.h"
6026121Skarels #include "errno.h"
6126121Skarels 
6226378Skarels #include "if.h"
6326378Skarels #include "netisr.h"
6426378Skarels #include "route.h"
6526378Skarels #if INET
6626121Skarels #include "../netinet/in.h"
6726121Skarels #include "../netinet/in_systm.h"
6828986Skarels #include "../netinet/in_var.h"
6926121Skarels #include "../netinet/ip.h"
70*38365Swilliam #include "slcompress.h"
7126378Skarels #endif
72*38365Swilliam #include "if_slvar.h"
7326121Skarels 
7437500Smckusick #include "machine/mtpr.h"
7526121Skarels 
7626121Skarels /*
7726378Skarels  * N.B.: SLMTU is now a hard limit on input packet size.
7833980Skarels  * SLMTU must be <= MCLBYTES - sizeof(struct ifnet *).
7926121Skarels  */
8026121Skarels #define	SLMTU	1006
8126378Skarels #define	SLIP_HIWAT	1000	/* don't start a new packet if HIWAT on queue */
8226378Skarels #define	CLISTRESERVE	1000	/* Can't let clists get too low */
8326121Skarels 
84*38365Swilliam /*
85*38365Swilliam  * SLIP ABORT ESCAPE MECHANISM:
86*38365Swilliam  *	(inspired by HAYES modem escape arrangement)
87*38365Swilliam  *	1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
88*38365Swilliam  *	signals a "soft" exit from slip mode by usermode process
89*38365Swilliam  *	(hard exit unimplemented -- currently system dependant)
90*38365Swilliam  */
9126121Skarels 
92*38365Swilliam #define	ABT_ESC		'\033'	/* can't be t_intr - distant host must know it*/
93*38365Swilliam #define ABT_WAIT	1	/* in seconds - idle before an escape & after */
94*38365Swilliam #define ABT_RECYCLE	(5*2+2)	/* in seconds - time window processing abort */
9526121Skarels 
96*38365Swilliam /* a "soft" abort means to pass a suggestion to user code to abort slip */
97*38365Swilliam #define ABT_SOFT	3	/* count of escapes */
98*38365Swilliam 
99*38365Swilliam /* a "hard" abort means to force abort slip within the kernel -- process jam? */
100*38365Swilliam #define ABT_HARD	5	/* count of escapes */
101*38365Swilliam 
102*38365Swilliam /*
103*38365Swilliam  * SLIP TIME WINDOW:
104*38365Swilliam  *	Only accept packets with octets that come at least this often.
105*38365Swilliam  *	With non-reliable but fast modems (FAX, Packet Radio), we assume that
106*38365Swilliam  *	packets come in groups (time domain), and that fractional groups that
107*38365Swilliam  *	come erratically are just noise that will foul subsequent packets.
108*38365Swilliam  *	We reject them on a time filter basis.
109*38365Swilliam  *
110*38365Swilliam  *	This is a very coarse filter, because error correcting modems like the
111*38365Swilliam  *	telebit take there own sweet time encoding/decoding packets. If you
112*38365Swilliam  *	are using an MNP,PEP or other such arrangement, this won't help much.
113*38365Swilliam  *	If you are using packet radio, use the millisecond time val with
114*38365Swilliam  *	as small a resolution as possible. In any case, the coarse filter
115*38365Swilliam  *	saves noisey lines about 50 % of the time.
116*38365Swilliam  */
117*38365Swilliam 
118*38365Swilliam #define	TIME_WINDOW	2	/* max seconds between valid packet chars */
119*38365Swilliam 
120*38365Swilliam struct sl_softc	 sl_softc[NSL];
121*38365Swilliam 
12226121Skarels #define FRAME_END	 	0300		/* Frame End */
12326121Skarels #define FRAME_ESCAPE		0333		/* Frame Esc */
12426121Skarels #define TRANS_FRAME_END	 	0334		/* transposed frame end */
12526121Skarels #define TRANS_FRAME_ESCAPE 	0335		/* transposed frame esc */
12626121Skarels 
12726121Skarels #define t_sc T_LINEP
12826121Skarels 
12926121Skarels int sloutput(), slioctl(), ttrstrt();
13026121Skarels 
13126121Skarels /*
13226121Skarels  * Called from boot code to establish sl interfaces.
13326121Skarels  */
13426121Skarels slattach()
13526121Skarels {
13626121Skarels 	register struct sl_softc *sc;
13726121Skarels 	register int i = 0;
13826121Skarels 
13926121Skarels 	for (sc = sl_softc; i < NSL; sc++) {
14026121Skarels 		sc->sc_if.if_name = "sl";
14126121Skarels 		sc->sc_if.if_unit = i++;
14226121Skarels 		sc->sc_if.if_mtu = SLMTU;
14326121Skarels 		sc->sc_if.if_flags = IFF_POINTOPOINT;
14426121Skarels 		sc->sc_if.if_ioctl = slioctl;
14526121Skarels 		sc->sc_if.if_output = sloutput;
14626121Skarels 		sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
14726121Skarels 		if_attach(&sc->sc_if);
14826121Skarels 	}
14926121Skarels }
15026121Skarels 
15126121Skarels /*
15226121Skarels  * Line specific open routine.
15326121Skarels  * Attach the given tty to the first available sl unit.
15426121Skarels  */
15526378Skarels /* ARGSUSED */
15626121Skarels slopen(dev, tp)
15726121Skarels 	dev_t dev;
15826121Skarels 	register struct tty *tp;
15926121Skarels {
16026121Skarels 	register struct sl_softc *sc;
16126121Skarels 	register int nsl;
16237549Smckusick 	int error;
16326121Skarels 
16437549Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
16537549Smckusick 		return (error);
16626378Skarels 	if (tp->t_line == SLIPDISC)
16726121Skarels 		return (EBUSY);
16826121Skarels 
16926121Skarels 	for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++)
17026121Skarels 		if (sc->sc_ttyp == NULL) {
17126121Skarels 			sc->sc_flags = 0;
17226121Skarels 			sc->sc_ilen = 0;
17326378Skarels 			if (slinit(sc) == 0)
17426378Skarels 				return (ENOBUFS);
175*38365Swilliam #ifdef INET
176*38365Swilliam 			sl_compress_init(&sc->sc_comp);
177*38365Swilliam #endif
17826121Skarels 			tp->t_sc = (caddr_t)sc;
17926121Skarels 			sc->sc_ttyp = tp;
18026378Skarels 			ttyflush(tp, FREAD | FWRITE);
18126121Skarels 			return (0);
18226121Skarels 		}
18326121Skarels 
18426378Skarels 	return (ENXIO);
18526121Skarels }
18626121Skarels 
18726121Skarels /*
18826121Skarels  * Line specific close routine.
18926121Skarels  * Detach the tty from the sl unit.
19026121Skarels  * Mimics part of ttyclose().
19126121Skarels  */
19226121Skarels slclose(tp)
19326121Skarels 	struct tty *tp;
19426121Skarels {
19526121Skarels 	register struct sl_softc *sc;
19626121Skarels 	int s;
19726121Skarels 
19826121Skarels 	ttywflush(tp);
19926121Skarels 	tp->t_line = 0;
20026121Skarels 	s = splimp();		/* paranoid; splnet probably ok */
20126121Skarels 	sc = (struct sl_softc *)tp->t_sc;
20226121Skarels 	if (sc != NULL) {
20326121Skarels 		if_down(&sc->sc_if);
20426121Skarels 		sc->sc_ttyp = NULL;
20526121Skarels 		tp->t_sc = NULL;
20626378Skarels 		MCLFREE((struct mbuf *)sc->sc_buf);
20726378Skarels 		sc->sc_buf = 0;
208*38365Swilliam 		sc->sc_mp = (char *) 4; /*XXX!?! */
20926121Skarels 	}
21026121Skarels 	splx(s);
21126121Skarels }
21226121Skarels 
21326121Skarels /*
21426121Skarels  * Line specific (tty) ioctl routine.
21526121Skarels  * Provide a way to get the sl unit number.
21626121Skarels  */
21726378Skarels /* ARGSUSED */
21826121Skarels sltioctl(tp, cmd, data, flag)
21926121Skarels 	struct tty *tp;
22026121Skarels 	caddr_t data;
22126121Skarels {
222*38365Swilliam 	struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
223*38365Swilliam 	int s;
22426121Skarels 
225*38365Swilliam 	switch (cmd) {
226*38365Swilliam 	case TIOCGETD:
227*38365Swilliam 		*(int *)data = sc->sc_if.if_unit;
228*38365Swilliam 		break;
229*38365Swilliam 	case TIOCMGET:
23038280Swilliam 		if (tp->t_state&TS_CARR_ON)
23138280Swilliam 			*(int *)data = TIOCM_CAR ;
232*38365Swilliam 		else	*(int *)data = 0 ;
233*38365Swilliam 
234*38365Swilliam 		if (sc->sc_flags&SC_ABORT)
235*38365Swilliam 			*(int *)data |= TIOCM_DTR ;
236*38365Swilliam 		break;
237*38365Swilliam 	case SLIOCGFLAGS:
238*38365Swilliam 		*(int *)data = sc->sc_flags;
239*38365Swilliam 		break;
240*38365Swilliam 	case SLIOCSFLAGS:
241*38365Swilliam #define	SC_MASK	(SC_COMPRESS|SC_NOICMP)
242*38365Swilliam 		s = splimp();
243*38365Swilliam 		sc->sc_flags =
244*38365Swilliam 		    (sc->sc_flags &~ SC_MASK) | ((*(int *)data) & SC_MASK);
245*38365Swilliam 		splx(s);
246*38365Swilliam 		break;
247*38365Swilliam 	default:
248*38365Swilliam 		return (-1);
24938280Swilliam 	}
250*38365Swilliam 	return (0);
25126121Skarels }
25226121Skarels 
25326121Skarels /*
25426121Skarels  * Queue a packet.  Start transmission if not active.
25526121Skarels  */
25626121Skarels sloutput(ifp, m, dst)
25726121Skarels 	register struct ifnet *ifp;
25826121Skarels 	register struct mbuf *m;
25926121Skarels 	struct sockaddr *dst;
26026121Skarels {
26126121Skarels 	register struct sl_softc *sc;
26226121Skarels 	int s;
26326121Skarels 
26426121Skarels 	/*
26526121Skarels 	 * `Cannot happen' (see slioctl).  Someday we will extend
26626121Skarels 	 * the line protocol to support other address families.
26726121Skarels 	 */
26826121Skarels 	if (dst->sa_family != AF_INET) {
26926121Skarels 		printf("sl%d: af%d not supported\n", ifp->if_unit,
27026121Skarels 			dst->sa_family);
27126121Skarels 		m_freem(m);
27226121Skarels 		return (EAFNOSUPPORT);
27326121Skarels 	}
27426121Skarels 
27526121Skarels 	sc = &sl_softc[ifp->if_unit];
27626121Skarels 	if (sc->sc_ttyp == NULL) {
27726121Skarels 		m_freem(m);
27826121Skarels 		return (ENETDOWN);	/* sort of */
27926121Skarels 	}
28026899Skarels 	if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
28126899Skarels 		m_freem(m);
28226899Skarels 		return (EHOSTUNREACH);
28326899Skarels 	}
28426121Skarels 	s = splimp();
285*38365Swilliam #ifdef INET
286*38365Swilliam 	if (sc->sc_flags & (SC_COMPRESS|SC_NOICMP)) {
287*38365Swilliam 		register struct ip *ip = mtod(m, struct ip *);
288*38365Swilliam 		if (ip->ip_p == IPPROTO_TCP) {
289*38365Swilliam 			/* add stuff to TOS routing */
290*38365Swilliam 			if (sc->sc_flags & SC_COMPRESS)
291*38365Swilliam 				(void) sl_compress_tcp(m, ip, &sc->sc_comp);
292*38365Swilliam 		} else if ((sc->sc_flags & SC_NOICMP) &&
293*38365Swilliam 		    ip->ip_p == IPPROTO_ICMP) {
294*38365Swilliam 			m_freem(m);
295*38365Swilliam 			splx(s);
296*38365Swilliam 			return (0);
297*38365Swilliam 		}
298*38365Swilliam 	}
299*38365Swilliam #endif
30026121Skarels 	if (IF_QFULL(&ifp->if_snd)) {
30126121Skarels 		IF_DROP(&ifp->if_snd);
30226121Skarels 		splx(s);
30326121Skarels 		m_freem(m);
30426378Skarels 		sc->sc_if.if_oerrors++;
30526121Skarels 		return (ENOBUFS);
30626121Skarels 	}
30726121Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
30833740Skarels 	if (sc->sc_ttyp->t_outq.c_cc == 0) {
30926121Skarels 		splx(s);
31026121Skarels 		slstart(sc->sc_ttyp);
31126121Skarels 	} else
31226121Skarels 		splx(s);
31326121Skarels 	return (0);
31426121Skarels }
31526121Skarels 
31626121Skarels /*
31726121Skarels  * Start output on interface.  Get another datagram
31826121Skarels  * to send from the interface queue and map it to
31926121Skarels  * the interface before starting output.
32026121Skarels  */
32126121Skarels slstart(tp)
32226121Skarels 	register struct tty *tp;
32326121Skarels {
32426121Skarels 	register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
32526121Skarels 	register struct mbuf *m;
32626378Skarels 	register int len;
32726378Skarels 	register u_char *cp;
32833740Skarels 	int nd, np, n, s;
32926378Skarels 	struct mbuf *m2;
33026378Skarels 	extern int cfreecount;
33126121Skarels 
33226378Skarels 	for (;;) {
33326378Skarels 		/*
33426378Skarels 		 * If there is more in the output queue, just send it now.
33526378Skarels 		 * We are being called in lieu of ttstart and must do what
33626378Skarels 		 * it would.
33726378Skarels 		 */
33826378Skarels 		if (tp->t_outq.c_cc > 0)
33926378Skarels 			ttstart(tp);
34026378Skarels 		if (tp->t_outq.c_cc > SLIP_HIWAT)
34126378Skarels 			return;
34226121Skarels 
34326378Skarels 		/*
34426378Skarels 		 * This happens briefly when the line shuts down.
34526378Skarels 		 */
34626378Skarels 		if (sc == NULL)
34726378Skarels 			return;
34826121Skarels 
34926378Skarels 		/*
35026378Skarels 		 * If system is getting low on clists
35126378Skarels 		 * and we have something running already, stop here.
35226378Skarels 		 */
35334361Skarels 		if (cfreecount < CLISTRESERVE + SLMTU && tp->t_outq.c_cc)
35426378Skarels 			return;
35526121Skarels 
35626378Skarels 		/*
35726378Skarels 		 * Get a packet and send it to the interface.
35826378Skarels 		 */
35926378Skarels 		s = splimp();
36026378Skarels 		IF_DEQUEUE(&sc->sc_if.if_snd, m);
36133740Skarels 		splx(s);
36233740Skarels 		if (m == NULL)
36326378Skarels 			return;
36426121Skarels 
36526378Skarels 		/*
36626378Skarels 		 * The extra FRAME_END will start up a new packet, and thus
36726378Skarels 		 * will flush any accumulated garbage.  We do this whenever
36826378Skarels 		 * the line may have been idle for some time.
36926378Skarels 		 */
37033740Skarels 		if (tp->t_outq.c_cc == 0)
37126378Skarels 			(void) putc(FRAME_END, &tp->t_outq);
37226378Skarels 
37326378Skarels 		while (m) {
37426378Skarels 			cp = mtod(m, u_char *);
37526378Skarels 			len = m->m_len;
37626378Skarels 			while (len > 0) {
37726378Skarels 				/*
37826378Skarels 				 * Find out how many bytes in the string we can
37926378Skarels 				 * handle without doing something special.
38026378Skarels 				 */
38126378Skarels 				nd = locc(FRAME_ESCAPE, len, cp);
38226378Skarels 				np = locc(FRAME_END, len, cp);
38326378Skarels 				n = len - MAX(nd, np);
38426378Skarels 				if (n) {
38526378Skarels 					/*
38626378Skarels 					 * Put n characters at once
38726378Skarels 					 * into the tty output queue.
38826378Skarels 					 */
38926378Skarels 					if (b_to_q((char *)cp, n, &tp->t_outq))
39026378Skarels 						break;
39127688Smckusick 					len -= n;
39227688Smckusick 					cp += n;
39326121Skarels 				}
39426378Skarels 				/*
39526378Skarels 				 * If there are characters left in the mbuf,
39626378Skarels 				 * the first one must be special..
39726378Skarels 				 * Put it out in a different form.
39826378Skarels 				 */
39926378Skarels 				if (len) {
40026378Skarels 					if (putc(FRAME_ESCAPE, &tp->t_outq))
40126378Skarels 						break;
40226378Skarels 					if (putc(*cp == FRAME_ESCAPE ?
40326378Skarels 					   TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
40426378Skarels 					   &tp->t_outq)) {
40526378Skarels 						(void) unputc(&tp->t_outq);
40626378Skarels 						break;
40726378Skarels 					}
40826378Skarels 					cp++;
40926378Skarels 					len--;
41026378Skarels 				}
41126378Skarels 			}
41226378Skarels 			MFREE(m, m2);
41326378Skarels 			m = m2;
41426121Skarels 		}
41526378Skarels 
41626378Skarels 		if (putc(FRAME_END, &tp->t_outq)) {
41726378Skarels 			/*
41826378Skarels 			 * Not enough room.  Remove a char to make room
41926378Skarels 			 * and end the packet normally.
42026378Skarels 			 * If you get many collisions (more than one or two
42126378Skarels 			 * a day) you probably do not have enough clists
42226378Skarels 			 * and you should increase "nclist" in param.c.
42326378Skarels 			 */
42426378Skarels 			(void) unputc(&tp->t_outq);
42526378Skarels 			(void) putc(FRAME_END, &tp->t_outq);
42626378Skarels 			sc->sc_if.if_collisions++;
42726378Skarels 		} else
42826378Skarels 			sc->sc_if.if_opackets++;
42926121Skarels 	}
43026378Skarels }
43126121Skarels 
43226378Skarels slinit(sc)
43326378Skarels 	register struct sl_softc *sc;
43426378Skarels {
43537472Ssklower 	register caddr_t p;
43626121Skarels 
43726378Skarels 	if (sc->sc_buf == (char *) 0) {
43837472Ssklower 		MCLALLOC(p, M_WAIT);
43926378Skarels 		if (p) {
44037472Ssklower 			sc->sc_buf = p;
44137472Ssklower 			sc->sc_mp = p;
44226378Skarels 		} else {
44326378Skarels 			printf("sl%d: can't allocate buffer\n", sc - sl_softc);
44426378Skarels 			sc->sc_if.if_flags &= ~IFF_UP;
44526378Skarels 			return (0);
44626378Skarels 		}
44726378Skarels 	}
44826378Skarels 	return (1);
44926121Skarels }
45026121Skarels 
45126121Skarels /*
45226121Skarels  * Copy data buffer to mbuf chain; add ifnet pointer ifp.
45326121Skarels  */
45426121Skarels struct mbuf *
45526378Skarels sl_btom(sc, len, ifp)
45626378Skarels 	struct sl_softc *sc;
45726121Skarels 	register int len;
45826121Skarels 	struct ifnet *ifp;
45926121Skarels {
46026378Skarels 	register caddr_t cp;
46126121Skarels 	register struct mbuf *m, **mp;
46226378Skarels 	register unsigned count;
46326121Skarels 	struct mbuf *top = NULL;
46426121Skarels 
46538280Swilliam 	cp = sc->sc_buf;
46626121Skarels 	mp = &top;
46738280Swilliam 
46826121Skarels 	while (len > 0) {
46937472Ssklower 		if (top == NULL) {
47037472Ssklower 			MGETHDR(m, M_DONTWAIT, MT_DATA);
47137472Ssklower 		} else {
47237472Ssklower 			MGET(m, M_DONTWAIT, MT_DATA);
47337472Ssklower 		}
47438280Swilliam 		if (m == NULL) {
47526121Skarels 			m_freem(top);
47626121Skarels 			return (NULL);
47726121Skarels 		}
47837472Ssklower 		if (top == NULL) {
47937472Ssklower 			m->m_pkthdr.rcvif = ifp;
48037472Ssklower 			m->m_pkthdr.len = len;
48137472Ssklower 			m->m_len = MHLEN;
48237472Ssklower 		} else
48337472Ssklower 			m->m_len = MLEN;
48438280Swilliam 		*mp = m;
48526378Skarels 		/*
48637472Ssklower 		 * If we have at least MINCLSIZE bytes,
48737472Ssklower 		 * allocate a new page.  Swap the current
48837472Ssklower 		 * buffer page with the new one.
48926378Skarels 		 */
49037472Ssklower 		if (len >= MINCLSIZE) {
49137472Ssklower 			MCLGET(m, M_DONTWAIT);
49237472Ssklower 			if (m->m_flags & M_EXT) {
49326378Skarels 				cp = mtod(m, char *);
49437472Ssklower 				m->m_data = sc->sc_buf;
49528184Smckusick 				sc->sc_buf = cp;
49637472Ssklower 				count = MIN(len, MCLBYTES);
49726378Skarels 				goto nocopy;
49826378Skarels 			}
49926121Skarels 		}
50037472Ssklower 		count = MIN(len, m->m_len);
50126378Skarels 		bcopy(cp, mtod(m, caddr_t), count);
50226378Skarels nocopy:
50326121Skarels 		m->m_len = count;
50426378Skarels 		cp += count;
50526121Skarels 		len -= count;
50626121Skarels 		mp = &m->m_next;
50726121Skarels 	}
50826121Skarels 	return (top);
50926121Skarels }
51026121Skarels 
51126121Skarels /*
51226121Skarels  * tty interface receiver interrupt.
51326121Skarels  */
51426121Skarels slinput(c, tp)
51526121Skarels 	register int c;
51626121Skarels 	register struct tty *tp;
51726121Skarels {
51826121Skarels 	register struct sl_softc *sc;
51926121Skarels 	register struct mbuf *m;
52026121Skarels 	int s;
52126121Skarels 
52226378Skarels 	tk_nin++;
52326121Skarels 	sc = (struct sl_softc *)tp->t_sc;
52426121Skarels 	if (sc == NULL)
52526121Skarels 		return;
526*38365Swilliam 	if (!(tp->t_state&TS_CARR_ON))	/*XXX*/
527*38365Swilliam 		return;
52826121Skarels 
52926121Skarels 	c &= 0xff;
530*38365Swilliam 
531*38365Swilliam 	/* if we see an abort after "idle" time, count it */
532*38365Swilliam 	if ((c&0x7f) == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) {
533*38365Swilliam 		sc->sc_abortcount++;
534*38365Swilliam 		/* record when the first abort escape arrived */
535*38365Swilliam 		if (sc->sc_abortcount == 1) sc->sc_starttime = time.tv_sec;
536*38365Swilliam 	}
537*38365Swilliam 
538*38365Swilliam 	/* if we have an abort, see that we have not run out of time, or
539*38365Swilliam 	   that we have an "idle" time after the complete escape sequence */
540*38365Swilliam 	if (sc->sc_abortcount) {
541*38365Swilliam 		if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE)
542*38365Swilliam 			sc->sc_abortcount = 0;
543*38365Swilliam 		if (sc->sc_abortcount >= ABT_SOFT
544*38365Swilliam 		&& time.tv_sec >= sc->sc_lasttime + ABT_WAIT)
545*38365Swilliam 			sc->sc_flags |= SC_ABORT;
546*38365Swilliam 	}
547*38365Swilliam 
548*38365Swilliam 	if (sc->sc_ilen && time.tv_sec >= sc->sc_lasttime + TIME_WINDOW) {
549*38365Swilliam 		sc->sc_flags &= ~SC_ESCAPED;
550*38365Swilliam 		sc->sc_mp = sc->sc_buf;
551*38365Swilliam 		sc->sc_ilen = 0;
552*38365Swilliam 		sc->sc_if.if_ierrors++;
553*38365Swilliam 		return;
554*38365Swilliam 	}
555*38365Swilliam 
556*38365Swilliam 	sc->sc_lasttime = time.tv_sec;
557*38365Swilliam 
55826121Skarels 	if (sc->sc_flags & SC_ESCAPED) {
55926121Skarels 		sc->sc_flags &= ~SC_ESCAPED;
56026121Skarels 		switch (c) {
56126121Skarels 
56226121Skarels 		case TRANS_FRAME_ESCAPE:
56326121Skarels 			c = FRAME_ESCAPE;
56426121Skarels 			break;
56526121Skarels 
56626121Skarels 		case TRANS_FRAME_END:
56726121Skarels 			c = FRAME_END;
56826121Skarels 			break;
56926121Skarels 
57026121Skarels 		default:
57126121Skarels 			sc->sc_if.if_ierrors++;
57238280Swilliam 			sc->sc_mp = sc->sc_buf;
57326121Skarels 			sc->sc_ilen = 0;
57426121Skarels 			return;
57526121Skarels 		}
57626121Skarels 	} else {
57726121Skarels 		switch (c) {
57826121Skarels 
57926121Skarels 		case FRAME_END:
58026121Skarels 			if (sc->sc_ilen == 0)	/* ignore */
58126121Skarels 				return;
58226378Skarels 			m = sl_btom(sc, sc->sc_ilen, &sc->sc_if);
583*38365Swilliam 			sc->sc_mp = sc->sc_buf;
584*38365Swilliam 			sc->sc_ilen = 0;
58526121Skarels 			if (m == NULL) {
58626121Skarels 				sc->sc_if.if_ierrors++;
58726121Skarels 				return;
58826121Skarels 			}
58926121Skarels 			sc->sc_if.if_ipackets++;
590*38365Swilliam #ifdef INET
591*38365Swilliam 			{ u_char type = *mtod(m, u_char *);
592*38365Swilliam 			  if (!(m = sl_uncompress_tcp(m, type&0xf0, &sc->sc_comp)))
593*38365Swilliam 				return;
594*38365Swilliam 			}
595*38365Swilliam #endif
59626121Skarels 			s = splimp();
59726121Skarels 			if (IF_QFULL(&ipintrq)) {
59826121Skarels 				IF_DROP(&ipintrq);
59926121Skarels 				sc->sc_if.if_ierrors++;
60026121Skarels 				m_freem(m);
60126121Skarels 			} else {
60226121Skarels 				IF_ENQUEUE(&ipintrq, m);
60326121Skarels 				schednetisr(NETISR_IP);
60426121Skarels 			}
60526121Skarels 			splx(s);
60626121Skarels 			return;
60726121Skarels 
60826121Skarels 		case FRAME_ESCAPE:
60926121Skarels 			sc->sc_flags |= SC_ESCAPED;
61026121Skarels 			return;
61126121Skarels 		}
61226121Skarels 	}
61328200Skarels 	if (++sc->sc_ilen > SLMTU) {
61426121Skarels 		sc->sc_if.if_ierrors++;
61538280Swilliam 		sc->sc_mp = sc->sc_buf;
61626121Skarels 		sc->sc_ilen = 0;
61726121Skarels 		return;
61826121Skarels 	}
61926121Skarels 	*sc->sc_mp++ = c;
62026121Skarels }
62126121Skarels 
62226121Skarels /*
62326121Skarels  * Process an ioctl request.
62426121Skarels  */
62526121Skarels slioctl(ifp, cmd, data)
62626121Skarels 	register struct ifnet *ifp;
62726121Skarels 	int cmd;
62826121Skarels 	caddr_t data;
62926121Skarels {
63026121Skarels 	register struct ifaddr *ifa = (struct ifaddr *)data;
63126121Skarels 	int s = splimp(), error = 0;
63226121Skarels 
63326121Skarels 	switch (cmd) {
63426121Skarels 
63526121Skarels 	case SIOCSIFADDR:
63637472Ssklower 		if (ifa->ifa_addr->sa_family == AF_INET)
63726121Skarels 			ifp->if_flags |= IFF_UP;
63826121Skarels 		else
63926121Skarels 			error = EAFNOSUPPORT;
64026121Skarels 		break;
64126121Skarels 
64226121Skarels 	case SIOCSIFDSTADDR:
64337472Ssklower 		if (ifa->ifa_addr->sa_family != AF_INET)
64426121Skarels 			error = EAFNOSUPPORT;
64526121Skarels 		break;
64626121Skarels 
64726121Skarels 	default:
64826121Skarels 		error = EINVAL;
64926121Skarels 	}
65026121Skarels 	splx(s);
65126121Skarels 	return (error);
65226121Skarels }
65326121Skarels #endif
654