xref: /openbsd-src/sys/net/ppp_tty.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: ppp_tty.c,v 1.44 2016/09/15 02:00:18 dlg Exp $	*/
2 /*	$NetBSD: ppp_tty.c,v 1.12 1997/03/24 21:23:10 christos Exp $	*/
3 
4 /*
5  * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
6  * 	       tty devices.
7  *
8  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in
19  *    the documentation and/or other materials provided with the
20  *    distribution.
21  *
22  * 3. The name "Carnegie Mellon University" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For permission or any legal
25  *    details, please contact
26  *      Office of Technology Transfer
27  *      Carnegie Mellon University
28  *      5000 Forbes Avenue
29  *      Pittsburgh, PA  15213-3890
30  *      (412) 268-4387, fax: (412) 268-7395
31  *      tech-transfer@andrew.cmu.edu
32  *
33  * 4. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by Computing Services
36  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37  *
38  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
39  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
40  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
41  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
42  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
43  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
44  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45  *
46  * Based on:
47  *	@(#)if_sl.c	7.6.1.2 (Berkeley) 2/15/89
48  *
49  * Copyright (c) 1987 Regents of the University of California.
50  * All rights reserved.
51  *
52  * Redistribution and use in source and binary forms are permitted
53  * provided that the above copyright notice and this paragraph are
54  * duplicated in all such forms and that any documentation,
55  * advertising materials, and other materials related to such
56  * distribution and use acknowledge that the software was developed
57  * by the University of California, Berkeley.  The name of the
58  * University may not be used to endorse or promote products derived
59  * from this software without specific prior written permission.
60  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
61  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
62  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
63  *
64  * Serial Line interface
65  *
66  * Rick Adams
67  * Center for Seismic Studies
68  * 1300 N 17th Street, Suite 1450
69  * Arlington, Virginia 22209
70  * (703)276-7900
71  * rick@seismo.ARPA
72  * seismo!rick
73  *
74  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
75  * Converted to 4.3BSD Beta by Chris Torek.
76  * Other changes made at Berkeley, based in part on code by Kirk Smith.
77  *
78  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
79  * Added VJ tcp header compression; more unified ioctls
80  *
81  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
82  * Cleaned up a lot of the mbuf-related code to fix bugs that
83  * caused system crashes and packet corruption.  Changed pppstart
84  * so that it doesn't just give up with a collision if the whole
85  * packet doesn't fit in the output ring buffer.
86  *
87  * Added priority queueing for interactive IP packets, following
88  * the model of if_sl.c, plus hooks for bpf.
89  * Paul Mackerras (paulus@cs.anu.edu.au).
90  */
91 
92 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
93 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
94 
95 #include "ppp.h"
96 #if NPPP > 0
97 
98 #define VJC
99 #define PPP_COMPRESS
100 
101 #include <sys/param.h>
102 #include <sys/proc.h>
103 #include <sys/mbuf.h>
104 #include <sys/socket.h>
105 #include <sys/timeout.h>
106 #include <sys/ioctl.h>
107 #include <sys/file.h>
108 #include <sys/tty.h>
109 #include <sys/kernel.h>
110 #include <sys/conf.h>
111 #include <sys/vnode.h>
112 #include <sys/systm.h>
113 #include <sys/rwlock.h>
114 #include <sys/pool.h>
115 
116 #include <net/if.h>
117 #include <net/if_var.h>
118 
119 #ifdef VJC
120 #include <netinet/in.h>
121 #include <netinet/ip.h>
122 #include <net/slcompress.h>
123 #endif
124 
125 #include <net/bpf.h>
126 #include <net/ppp_defs.h>
127 #include <net/if_ppp.h>
128 #include <net/if_pppvar.h>
129 
130 int	pppstart_internal(struct tty *tp, int);
131 
132 u_int16_t pppfcs(u_int16_t fcs, u_char *cp, int len);
133 void	pppasyncstart(struct ppp_softc *);
134 void	pppasyncctlp(struct ppp_softc *);
135 void	pppasyncrelinq(struct ppp_softc *);
136 void	ppp_timeout(void *);
137 void	ppppkt(struct ppp_softc *sc);
138 void	pppdumpb(u_char *b, int l);
139 void	ppplogchar(struct ppp_softc *, int);
140 
141 struct rwlock ppp_pkt_init = RWLOCK_INITIALIZER("ppppktini");
142 struct pool ppp_pkts;
143 
144 #define PKT_MAXLEN(_sc) ((_sc)->sc_mru + PPP_HDRLEN + PPP_FCSLEN)
145 
146 /*
147  * Does c need to be escaped?
148  */
149 #define ESCAPE_P(c)	(sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
150 
151 /*
152  * Procedures for using an async tty interface for PPP.
153  */
154 
155 /* This is a NetBSD-1.0 or later kernel. */
156 #define CCOUNT(q)	((q)->c_cc)
157 
158 /*
159  * Line specific open routine for async tty devices.
160  * Attach the given tty to the first available ppp unit.
161  * Called from device open routine or ttioctl.
162  */
163 int
164 pppopen(dev_t dev, struct tty *tp, struct proc *p)
165 {
166     struct ppp_softc *sc;
167     int error, s;
168 
169     if ((error = suser(p, 0)) != 0)
170 	return (error);
171 
172     rw_enter_write(&ppp_pkt_init);
173     if (ppp_pkts.pr_size == 0) {
174 	extern struct kmem_pa_mode kp_dma_contig;
175 
176 	pool_init(&ppp_pkts, sizeof(struct ppp_pkt), 0,
177 	  IPL_TTY, 0, "ppppkts", NULL); /* IPL_SOFTTTY */
178 	pool_set_constraints(&ppp_pkts, &kp_dma_contig);
179     }
180     rw_exit_write(&ppp_pkt_init);
181 
182     s = spltty();
183 
184     if (tp->t_line == PPPDISC) {
185 	sc = (struct ppp_softc *) tp->t_sc;
186 	if (sc != NULL && sc->sc_devp == (void *) tp) {
187 	    splx(s);
188 	    return (0);
189 	}
190     }
191 
192     if ((sc = pppalloc(p->p_p->ps_pid)) == NULL) {
193 	splx(s);
194 	return ENXIO;
195     }
196 
197     if (sc->sc_relinq)
198 	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
199 
200     timeout_set(&sc->sc_timo, ppp_timeout, sc);
201     sc->sc_ilen = 0;
202     sc->sc_pkt = NULL;
203     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
204     sc->sc_asyncmap[0] = 0xffffffff;
205     sc->sc_asyncmap[3] = 0x60000000;
206     sc->sc_rasyncmap = 0;
207     sc->sc_devp = (void *) tp;
208     sc->sc_start = pppasyncstart;
209     sc->sc_ctlp = pppasyncctlp;
210     sc->sc_relinq = pppasyncrelinq;
211     sc->sc_outm = NULL;
212     ppppkt(sc);
213     sc->sc_if.if_flags |= IFF_RUNNING;
214     sc->sc_if.if_baudrate = tp->t_ospeed;
215 
216     tp->t_sc = (caddr_t) sc;
217     ttyflush(tp, FREAD | FWRITE);
218 
219     splx(s);
220     return (0);
221 }
222 
223 /*
224  * Line specific close routine, called from device close routine
225  * and from ttioctl.
226  * Detach the tty from the ppp unit.
227  * Mimics part of ttyclose().
228  */
229 int
230 pppclose(struct tty *tp, int flag, struct proc *p)
231 {
232     struct ppp_softc *sc;
233     int s;
234 
235     s = spltty();
236     ttyflush(tp, FREAD|FWRITE);
237     tp->t_line = 0;
238     sc = (struct ppp_softc *) tp->t_sc;
239     if (sc != NULL) {
240 	tp->t_sc = NULL;
241 	if (tp == (struct tty *) sc->sc_devp) {
242 	    pppasyncrelinq(sc);
243 	    pppdealloc(sc);
244 	}
245     }
246     splx(s);
247     return 0;
248 }
249 
250 /*
251  * Relinquish the interface unit to another device.
252  */
253 void
254 pppasyncrelinq(struct ppp_softc *sc)
255 {
256     int s;
257 
258     s = spltty();
259     m_freem(sc->sc_outm);
260     sc->sc_outm = NULL;
261 
262     if (sc->sc_pkt != NULL) {
263 	ppp_pkt_free(sc->sc_pkt);
264 	sc->sc_pkt = sc->sc_pktc = NULL;
265     }
266     if (sc->sc_flags & SC_TIMEOUT) {
267 	timeout_del(&sc->sc_timo);
268 	sc->sc_flags &= ~SC_TIMEOUT;
269     }
270     splx(s);
271 }
272 
273 /*
274  * Line specific (tty) read routine.
275  */
276 int
277 pppread(struct tty *tp, struct uio *uio, int flag)
278 {
279     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
280     struct mbuf *m, *m0;
281     int s;
282     int error = 0;
283 
284     if (sc == NULL)
285 	return 0;
286     /*
287      * Loop waiting for input, checking that nothing disasterous
288      * happens in the meantime.
289      */
290     s = spltty();
291     for (;;) {
292 	if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
293 	    splx(s);
294 	    return 0;
295 	}
296 	/* Get the packet from the input queue */
297 	m0 = mq_dequeue(&sc->sc_inq);
298 	if (m0 != NULL)
299 	    break;
300 	if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
301 	    && (tp->t_state & TS_ISOPEN)) {
302 	    splx(s);
303 	    return 0;		/* end of file */
304 	}
305 	if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
306 	    splx(s);
307 	    return (EWOULDBLOCK);
308 	}
309 	error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
310 	if (error) {
311 	    splx(s);
312 	    return error;
313 	}
314     }
315 
316     /* Pull place-holder byte out of canonical queue */
317     getc(&tp->t_canq);
318     splx(s);
319 
320     for (m = m0; m && uio->uio_resid; m = m->m_next)
321 	if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
322 	    break;
323     m_freem(m0);
324     return (error);
325 }
326 
327 /*
328  * Line specific (tty) write routine.
329  */
330 int
331 pppwrite(struct tty *tp, struct uio *uio, int flag)
332 {
333     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
334     struct mbuf *m, *m0, **mp;
335     struct sockaddr dst;
336     u_int len;
337     int error;
338 
339     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
340 	return 0;		/* wrote 0 bytes */
341     if (tp->t_line != PPPDISC)
342 	return (EINVAL);
343     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
344 	return EIO;
345     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
346 	uio->uio_resid < PPP_HDRLEN)
347 	return (EMSGSIZE);
348     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
349 	if (mp == &m0) {
350 	    MGETHDR(m, M_WAIT, MT_DATA);
351 	    m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN;
352 	    m->m_pkthdr.ph_ifidx = 0;
353 	} else
354 	    MGET(m, M_WAIT, MT_DATA);
355 	*mp = m;
356 	m->m_len = 0;
357 	if (uio->uio_resid >= MCLBYTES / 2)
358 	    MCLGET(m, M_DONTWAIT);
359 	len = M_TRAILINGSPACE(m);
360 	if (len > uio->uio_resid)
361 	    len = uio->uio_resid;
362 	if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
363 	    m_freem(m0);
364 	    return (error);
365 	}
366 	m->m_len = len;
367     }
368     dst.sa_family = AF_UNSPEC;
369     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
370     m0->m_data += PPP_HDRLEN;
371     m0->m_len -= PPP_HDRLEN;
372     return sc->sc_if.if_output(&sc->sc_if, m0, &dst, NULL);
373 }
374 
375 /*
376  * Line specific (tty) ioctl routine.
377  * This discipline requires that tty device drivers call
378  * the line specific l_ioctl routine from their ioctl routines.
379  */
380 int
381 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
382 {
383     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
384     int error, s;
385 
386     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
387 	return -1;
388 
389     error = 0;
390     switch (cmd) {
391     case PPPIOCSASYNCMAP:
392 	if ((error = suser(p, 0)) != 0)
393 	    break;
394 	sc->sc_asyncmap[0] = *(u_int *)data;
395 	break;
396 
397     case PPPIOCGASYNCMAP:
398 	*(u_int *)data = sc->sc_asyncmap[0];
399 	break;
400 
401     case PPPIOCSRASYNCMAP:
402 	if ((error = suser(p, 0)) != 0)
403 	    break;
404 	sc->sc_rasyncmap = *(u_int *)data;
405 	break;
406 
407     case PPPIOCGRASYNCMAP:
408 	*(u_int *)data = sc->sc_rasyncmap;
409 	break;
410 
411     case PPPIOCSXASYNCMAP:
412 	if ((error = suser(p, 0)) != 0)
413 	    break;
414 	s = spltty();
415 	bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
416 	sc->sc_asyncmap[1] = 0;		    /* mustn't escape 0x20 - 0x3f */
417 	sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
418 	sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
419 	splx(s);
420 	break;
421 
422     case PPPIOCGXASYNCMAP:
423 	bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
424 	break;
425 
426     default:
427 	error = pppioctl(sc, cmd, data, flag, p);
428 	if (error == 0 && cmd == PPPIOCSMRU)
429 	    ppppkt(sc);
430     }
431 
432     return error;
433 }
434 
435 /*
436  * FCS lookup table as calculated by genfcstab.
437  */
438 static u_int16_t fcstab[256] = {
439 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
440 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
441 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
442 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
443 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
444 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
445 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
446 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
447 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
448 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
449 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
450 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
451 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
452 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
453 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
454 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
455 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
456 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
457 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
458 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
459 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
460 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
461 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
462 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
463 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
464 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
465 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
466 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
467 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
468 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
469 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
470 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
471 };
472 
473 /*
474  * Calculate a new FCS given the current FCS and the new data.
475  */
476 u_int16_t
477 pppfcs(u_int16_t fcs, u_char *cp, int len)
478 {
479     while (len--)
480 	fcs = PPP_FCS(fcs, *cp++);
481     return (fcs);
482 }
483 
484 /*
485  * This gets called from pppoutput when a new packet is
486  * put on a queue, at splsoftnet.
487  */
488 void
489 pppasyncstart(struct ppp_softc *sc)
490 {
491     struct tty *tp = (struct tty *) sc->sc_devp;
492     struct mbuf *m;
493     int len;
494     u_char *start, *stop, *cp;
495     int n, ndone, done, idle;
496     struct mbuf *m2;
497     int s;
498 
499     idle = 0;
500     while (CCOUNT(&tp->t_outq) < tp->t_hiwat) {
501 	/*
502 	 * See if we have an existing packet partly sent.
503 	 * If not, get a new packet and start sending it.
504 	 */
505 	m = sc->sc_outm;
506 	if (m == NULL) {
507 	    /*
508 	     * Get another packet to be sent.
509 	     */
510 	    m = ppp_dequeue(sc);
511 	    if (m == NULL) {
512 		idle = 1;
513 		break;
514 	    }
515 
516 	    /*
517 	     * The extra PPP_FLAG will start up a new packet, and thus
518 	     * will flush any accumulated garbage.  We do this whenever
519 	     * the line may have been idle for some time.
520 	     */
521 	    if (CCOUNT(&tp->t_outq) == 0) {
522 		++sc->sc_stats.ppp_obytes;
523 		(void) putc(PPP_FLAG, &tp->t_outq);
524 	    }
525 
526 	    /* Calculate the FCS for the first mbuf's worth. */
527 	    sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
528 	}
529 
530 	for (;;) {
531 	    start = mtod(m, u_char *);
532 	    len = m->m_len;
533 	    stop = start + len;
534 	    while (len > 0) {
535 		/*
536 		 * Find out how many bytes in the string we can
537 		 * handle without doing something special.
538 		 */
539 		for (cp = start; cp < stop; cp++)
540 		    if (ESCAPE_P(*cp))
541 			break;
542 		n = cp - start;
543 		if (n) {
544 		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
545 		    ndone = n - b_to_q(start, n, &tp->t_outq);
546 		    len -= ndone;
547 		    start += ndone;
548 		    sc->sc_stats.ppp_obytes += ndone;
549 
550 		    if (ndone < n)
551 			break;	/* packet doesn't fit */
552 		}
553 		/*
554 		 * If there are characters left in the mbuf,
555 		 * the first one must be special.
556 		 * Put it out in a different form.
557 		 */
558 		if (len) {
559 		    s = spltty();
560 		    if (putc(PPP_ESCAPE, &tp->t_outq)) {
561 			splx(s);
562 			break;
563 		    }
564 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
565 			(void) unputc(&tp->t_outq);
566 			splx(s);
567 			break;
568 		    }
569 		    splx(s);
570 		    sc->sc_stats.ppp_obytes += 2;
571 		    start++;
572 		    len--;
573 		}
574 	    }
575 
576 	    /*
577 	     * If we didn't empty this mbuf, remember where we're up to.
578 	     * If we emptied the last mbuf, try to add the FCS and closing
579 	     * flag, and if we can't, leave sc_outm pointing to m, but with
580 	     * m->m_len == 0, to remind us to output the FCS and flag later.
581 	     */
582 	    done = len == 0;
583 	    if (done && m->m_next == NULL) {
584 		u_char *p, *q;
585 		int c;
586 		u_char endseq[8];
587 
588 		/*
589 		 * We may have to escape the bytes in the FCS.
590 		 */
591 		p = endseq;
592 		c = ~sc->sc_outfcs & 0xFF;
593 		if (ESCAPE_P(c)) {
594 		    *p++ = PPP_ESCAPE;
595 		    *p++ = c ^ PPP_TRANS;
596 		} else
597 		    *p++ = c;
598 		c = (~sc->sc_outfcs >> 8) & 0xFF;
599 		if (ESCAPE_P(c)) {
600 		    *p++ = PPP_ESCAPE;
601 		    *p++ = c ^ PPP_TRANS;
602 		} else
603 		    *p++ = c;
604 		*p++ = PPP_FLAG;
605 
606 		/*
607 		 * Try to output the FCS and flag.  If the bytes
608 		 * don't all fit, back out.
609 		 */
610 		s = spltty();
611 		for (q = endseq; q < p; ++q)
612 		    if (putc(*q, &tp->t_outq)) {
613 			done = 0;
614 			for (; q > endseq; --q)
615 			    unputc(&tp->t_outq);
616 			break;
617 		    }
618 		splx(s);
619 		if (done)
620 		    sc->sc_stats.ppp_obytes += q - endseq;
621 	    }
622 
623 	    if (!done) {
624 		/* remember where we got to */
625 		m->m_data = start;
626 		m->m_len = len;
627 		break;
628 	    }
629 
630 	    /* Finished with this mbuf; free it and move on. */
631 	    m2 = m_free(m);
632 	    m = m2;
633 	    if (m == NULL) {
634 		/* Finished a packet */
635 		break;
636 	    }
637 	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
638 	}
639 
640 	/*
641 	 * If m == NULL, we have finished a packet.
642 	 * If m != NULL, we've either done as much work this time
643 	 * as we need to, or else we've filled up the output queue.
644 	 */
645 	sc->sc_outm = m;
646 	if (m)
647 	    break;
648     }
649 
650     /* Call pppstart to start output again if necessary. */
651     s = spltty();
652     pppstart_internal(tp, 0);
653 
654     /*
655      * This timeout is needed for operation on a pseudo-tty,
656      * because the pty code doesn't call pppstart after it has
657      * drained the t_outq.
658      */
659     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
660 	timeout_add(&sc->sc_timo, 1);
661 	sc->sc_flags |= SC_TIMEOUT;
662     }
663 
664     splx(s);
665 }
666 
667 /*
668  * This gets called when a received packet is placed on
669  * the inq, at splsoftnet.
670  */
671 void
672 pppasyncctlp(struct ppp_softc *sc)
673 {
674     struct tty *tp;
675     int s;
676 
677     /* Put a placeholder byte in canq for ttpoll()/ttnread(). */
678     s = spltty();
679     tp = (struct tty *) sc->sc_devp;
680     putc(0, &tp->t_canq);
681     ttwakeup(tp);
682     splx(s);
683 }
684 
685 /*
686  * Start output on async tty interface.  If the transmit queue
687  * has drained sufficiently, arrange for pppasyncstart to be
688  * called later at splsoftnet.
689  */
690 int
691 pppstart_internal(struct tty *tp, int force)
692 {
693     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
694 
695     /*
696      * If there is stuff in the output queue, send it now.
697      * We are being called in lieu of ttstart and must do what it would.
698      */
699     if (tp->t_oproc != NULL)
700 	(*tp->t_oproc)(tp);
701 
702     /*
703      * If the transmit queue has drained and the tty has not hung up
704      * or been disconnected from the ppp unit, then tell if_ppp.c that
705      * we need more output.
706      */
707     if ((CCOUNT(&tp->t_outq) < tp->t_lowat || force)
708 	&& !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
709 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
710 	ppp_restart(sc);
711     }
712 
713     return 0;
714 }
715 
716 int
717 pppstart(struct tty *tp)
718 {
719 	return pppstart_internal(tp, 0);
720 }
721 
722 /*
723  * Timeout routine - try to start some more output.
724  */
725 void
726 ppp_timeout(void *x)
727 {
728     struct ppp_softc *sc = (struct ppp_softc *) x;
729     struct tty *tp = (struct tty *) sc->sc_devp;
730     int s;
731 
732     s = spltty();
733     sc->sc_flags &= ~SC_TIMEOUT;
734     pppstart_internal(tp, 1);
735     splx(s);
736 }
737 
738 /*
739  * Allocate enough mbuf to handle current MRU.
740  */
741 void
742 ppppkt(struct ppp_softc *sc)
743 {
744     struct ppp_pkt **pktp, *pkt;
745     int len;
746     int s;
747 
748     s = spltty();
749     pktp = &sc->sc_pkt;
750     for (len = PKT_MAXLEN(sc); len > 0; len -= sizeof(pkt->p_buf)) {
751 	pkt = *pktp;
752 	if (pkt == NULL) {
753 	    pkt = pool_get(&ppp_pkts, PR_NOWAIT);
754 	    if (pkt == NULL)
755 		break;
756 	    PKT_NEXT(pkt) = NULL;
757 	    PKT_PREV(pkt) = *pktp;
758 	    PKT_LEN(pkt) = 0;
759 	    *pktp = pkt;
760 	}
761 	pktp = &PKT_NEXT(pkt);
762     }
763     splx(s);
764 }
765 
766 void
767 ppp_pkt_free(struct ppp_pkt *pkt)
768 {
769 	struct ppp_pkt *next;
770 
771 	while (pkt != NULL) {
772 		next = PKT_NEXT(pkt);
773 		pool_put(&ppp_pkts, pkt);
774 		pkt = next;
775 	}
776 }
777 
778 /*
779  * tty interface receiver interrupt.
780  */
781 static unsigned int paritytab[8] = {
782     0x96696996, 0x69969669, 0x69969669, 0x96696996,
783     0x69969669, 0x96696996, 0x96696996, 0x69969669
784 };
785 
786 int
787 pppinput(int c, struct tty *tp)
788 {
789     struct ppp_softc *sc;
790     struct ppp_pkt *pkt;
791     int ilen, s;
792 
793     sc = (struct ppp_softc *) tp->t_sc;
794     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
795 	return 0;
796 
797     ++tk_nin;
798     ++sc->sc_stats.ppp_ibytes;
799 
800     if (c & TTY_FE) {
801 	/* framing error or overrun on this char - abort packet */
802 	if (sc->sc_flags & SC_DEBUG)
803 	    printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
804 	goto flush;
805     }
806 
807     c &= 0xff;
808 
809     /*
810      * Handle software flow control of output.
811      */
812     if (tp->t_iflag & IXON) {
813 	if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
814 	    if ((tp->t_state & TS_TTSTOP) == 0) {
815 		tp->t_state |= TS_TTSTOP;
816 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
817 	    }
818 	    return 0;
819 	}
820 	if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
821 	    tp->t_state &= ~TS_TTSTOP;
822 	    if (tp->t_oproc != NULL)
823 		(*tp->t_oproc)(tp);
824 	    return 0;
825 	}
826     }
827 
828     s = spltty();
829     if (c & 0x80)
830 	sc->sc_flags |= SC_RCV_B7_1;
831     else
832 	sc->sc_flags |= SC_RCV_B7_0;
833     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
834 	sc->sc_flags |= SC_RCV_ODDP;
835     else
836 	sc->sc_flags |= SC_RCV_EVNP;
837     splx(s);
838 
839     if (sc->sc_flags & SC_LOG_RAWIN)
840 	ppplogchar(sc, c);
841 
842     if (c == PPP_FLAG) {
843 	ilen = sc->sc_ilen;
844 	sc->sc_ilen = 0;
845 
846 	if (sc->sc_rawin_count > 0)
847 	    ppplogchar(sc, -1);
848 
849 	/*
850 	 * If SC_ESCAPED is set, then we've seen the packet
851 	 * abort sequence "}~".
852 	 */
853 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
854 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
855 	    s = spltty();
856 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
857 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
858 		if (sc->sc_flags & SC_DEBUG)
859 		    printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
860 			sc->sc_fcs);
861 		sc->sc_if.if_ierrors++;
862 		sc->sc_stats.ppp_ierrors++;
863 	    } else
864 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
865 	    splx(s);
866 	    return 0;
867 	}
868 
869 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
870 	    if (ilen) {
871 		if (sc->sc_flags & SC_DEBUG)
872 		    printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
873 		s = spltty();
874 		sc->sc_if.if_ierrors++;
875 		sc->sc_stats.ppp_ierrors++;
876 		sc->sc_flags |= SC_PKTLOST;
877 		splx(s);
878 	    }
879 	    return 0;
880 	}
881 
882 	/*
883 	 * Remove FCS trailer.
884 	 */
885 	ilen -= 2;
886 	pkt = sc->sc_pktc;
887 	if (--PKT_LEN(pkt) == 0) {
888             pkt = PKT_PREV(pkt);
889 	    sc->sc_pktc = pkt;
890 	}
891 	PKT_LEN(pkt)--;
892 
893 	/* excise this mbuf chain */
894 	pkt = sc->sc_pkt;
895 	sc->sc_pkt = sc->sc_pktc = PKT_NEXT(sc->sc_pktc);
896 	PKT_NEXT(pkt) = NULL;
897 
898 	ppppktin(sc, pkt, sc->sc_flags & SC_PKTLOST);
899 	if (sc->sc_flags & SC_PKTLOST) {
900 	    s = spltty();
901 	    sc->sc_flags &= ~SC_PKTLOST;
902 	    splx(s);
903 	}
904 
905 	ppppkt(sc);
906 	return 0;
907     }
908 
909     if (sc->sc_flags & SC_FLUSH) {
910 	if (sc->sc_flags & SC_LOG_FLUSH)
911 	    ppplogchar(sc, c);
912 	return 0;
913     }
914 
915     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
916 	return 0;
917 
918     s = spltty();
919     if (sc->sc_flags & SC_ESCAPED) {
920 	sc->sc_flags &= ~SC_ESCAPED;
921 	c ^= PPP_TRANS;
922     } else if (c == PPP_ESCAPE) {
923 	sc->sc_flags |= SC_ESCAPED;
924 	splx(s);
925 	return 0;
926     }
927     splx(s);
928 
929     /*
930      * Initialize buffer on first octet received.
931      * First octet could be address or protocol (when compressing
932      * address/control).
933      * Second octet is control.
934      * Third octet is first or second (when compressing protocol)
935      * octet of protocol.
936      * Fourth octet is second octet of protocol.
937      */
938     if (sc->sc_ilen == 0) {
939 	/* reset the first input mbuf */
940 	if (sc->sc_pkt == NULL) {
941 	    ppppkt(sc);
942 	    if (sc->sc_pkt == NULL) {
943 		if (sc->sc_flags & SC_DEBUG)
944 		    printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
945 		goto flush;
946 	    }
947 	}
948 	pkt = sc->sc_pkt;
949 	PKT_LEN(pkt) = 0;
950 	sc->sc_pktc = pkt;
951 	sc->sc_pktp = pkt->p_buf;
952 	sc->sc_fcs = PPP_INITFCS;
953 	if (c != PPP_ALLSTATIONS) {
954 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
955 		if (sc->sc_flags & SC_DEBUG)
956 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
957 			sc->sc_if.if_xname, c);
958 		goto flush;
959 	    }
960 	    *sc->sc_pktp++ = PPP_ALLSTATIONS;
961 	    *sc->sc_pktp++ = PPP_UI;
962 	    sc->sc_ilen += 2;
963 	    PKT_LEN(pkt) += 2;
964 	}
965     }
966     if (sc->sc_ilen == 1 && c != PPP_UI) {
967 	if (sc->sc_flags & SC_DEBUG)
968 	    printf("%s: missing UI (0x3), got 0x%x\n",
969 		sc->sc_if.if_xname, c);
970 	goto flush;
971     }
972     if (sc->sc_ilen == 2 && (c & 1) == 1) {
973 	/* a compressed protocol */
974 	*sc->sc_pktp++ = 0;
975 	sc->sc_ilen++;
976 	PKT_LEN(sc->sc_pktc)++;
977     }
978     if (sc->sc_ilen == 3 && (c & 1) == 0) {
979 	if (sc->sc_flags & SC_DEBUG)
980 	    printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
981 		(sc->sc_pktp[-1] << 8) + c);
982 	goto flush;
983     }
984 
985     /* packet beyond configured mru? */
986     if (++sc->sc_ilen > PKT_MAXLEN(sc)) {
987 	if (sc->sc_flags & SC_DEBUG)
988 	    printf("%s: packet too big\n", sc->sc_if.if_xname);
989 	goto flush;
990     }
991 
992     /* is this packet full? */
993     pkt = sc->sc_pktc;
994     if (PKT_LEN(pkt) >= sizeof(pkt->p_buf)) {
995 	if (PKT_NEXT(pkt) == NULL) {
996 	    ppppkt(sc);
997 	    if (PKT_NEXT(pkt) == NULL) {
998 		if (sc->sc_flags & SC_DEBUG)
999 		    printf("%s: too few input packets!\n", sc->sc_if.if_xname);
1000 		goto flush;
1001 	    }
1002 	}
1003 	sc->sc_pktc = pkt = PKT_NEXT(pkt);
1004 	PKT_LEN(pkt) = 0;
1005 	sc->sc_pktp = pkt->p_buf;
1006     }
1007 
1008     ++PKT_LEN(pkt);
1009     *sc->sc_pktp++ = c;
1010     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1011     return 0;
1012 
1013  flush:
1014     if (!(sc->sc_flags & SC_FLUSH)) {
1015 	s = spltty();
1016 	sc->sc_if.if_ierrors++;
1017 	sc->sc_stats.ppp_ierrors++;
1018 	sc->sc_flags |= SC_FLUSH;
1019 	splx(s);
1020 	if (sc->sc_flags & SC_LOG_FLUSH)
1021 	    ppplogchar(sc, c);
1022     }
1023     return 0;
1024 }
1025 
1026 #define MAX_DUMP_BYTES	128
1027 
1028 void
1029 ppplogchar(struct ppp_softc *sc, int c)
1030 {
1031     if (c >= 0)
1032 	sc->sc_rawin[sc->sc_rawin_count++] = c;
1033     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1034 	|| (c < 0 && sc->sc_rawin_count > 0)) {
1035 	printf("%s input: ", sc->sc_if.if_xname);
1036 	pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1037 	sc->sc_rawin_count = 0;
1038     }
1039 }
1040 
1041 void
1042 pppdumpb(u_char *b, int l)
1043 {
1044     char buf[3*MAX_DUMP_BYTES+4];
1045     char *bp = buf;
1046     static char digits[] = "0123456789abcdef";
1047 
1048     while (l--) {
1049 	if (bp >= buf + sizeof(buf) - 3) {
1050 	    *bp++ = '>';
1051 	    break;
1052 	}
1053 	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1054 	*bp++ = digits[*b++ & 0xf];
1055 	*bp++ = ' ';
1056     }
1057 
1058     *bp = 0;
1059     printf("%s\n", buf);
1060 }
1061 
1062 #endif	/* NPPP > 0 */
1063