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