xref: /netbsd-src/sys/net/ppp_tty.c (revision 7d62b00eb9ad855ffcd7da46b41e23feb5476fac)
1 /*	$NetBSD: ppp_tty.c,v 1.72 2022/12/21 19:08:22 chs Exp $	*/
2 /*	Id: ppp_tty.c,v 1.3 1996/07/01 01:04:11 paulus 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 <sys/cdefs.h>
96 __KERNEL_RCSID(0, "$NetBSD: ppp_tty.c,v 1.72 2022/12/21 19:08:22 chs Exp $");
97 
98 #ifdef _KERNEL_OPT
99 #include "ppp.h"
100 #include "opt_ppp.h"
101 #endif
102 #define VJC
103 #define PPP_COMPRESS
104 
105 #include <sys/param.h>
106 #include <sys/proc.h>
107 #include <sys/mbuf.h>
108 #include <sys/dkstat.h>
109 #include <sys/socket.h>
110 #include <sys/ioctl.h>
111 #include <sys/file.h>
112 #include <sys/tty.h>
113 #include <sys/kernel.h>
114 #include <sys/conf.h>
115 #include <sys/vnode.h>
116 #include <sys/systm.h>
117 #include <sys/kauth.h>
118 
119 #include <net/if.h>
120 #include <net/if_types.h>
121 
122 #ifdef VJC
123 #include <netinet/in.h>
124 #include <netinet/in_systm.h>
125 #include <netinet/ip.h>
126 #include <net/slcompress.h>
127 #endif
128 
129 #include <net/bpf.h>
130 #include <net/ppp_defs.h>
131 #include <net/if_ppp.h>
132 #include <net/if_pppvar.h>
133 
134 static int	pppopen(dev_t dev, struct tty *tp);
135 static int	pppclose(struct tty *tp, int flag);
136 static int	pppread(struct tty *tp, struct uio *uio, int flag);
137 static int	pppwrite(struct tty *tp, struct uio *uio, int flag);
138 static int	ppptioctl(struct tty *tp, u_long cmd, void *data, int flag,
139 			  struct lwp *);
140 static int	pppinput(int c, struct tty *tp);
141 static int	pppstart(struct tty *tp);
142 
143 struct linesw ppp_disc = {	/* XXX should be static */
144 	.l_name = "ppp",
145 	.l_open = pppopen,
146 	.l_close = pppclose,
147 	.l_read = pppread,
148 	.l_write = pppwrite,
149 	.l_ioctl = ppptioctl,
150 	.l_rint = pppinput,
151 	.l_start = pppstart,
152 	.l_modem = ttymodem,
153 	.l_poll = ttpoll
154 };
155 
156 static uint16_t pppfcs(uint16_t fcs, const uint8_t *cp, int len);
157 static void	pppasyncstart(struct ppp_softc *);
158 static void	pppasyncctlp(struct ppp_softc *);
159 static void	pppasyncrelinq(struct ppp_softc *);
160 static void	ppp_timeout(void *);
161 static void	pppgetm(struct ppp_softc *sc);
162 static void	pppdumpb(u_char *b, int l);
163 static void	ppplogchar(struct ppp_softc *, int);
164 
165 /*
166  * Does c need to be escaped?
167  */
168 #define ESCAPE_P(c)	(sc->sc_asyncmap[(c) >> 5] & (1U << ((c) & 0x1F)))
169 
170 /*
171  * Procedures for using an async tty interface for PPP.
172  */
173 
174 /* This is a NetBSD-1.0 or later kernel. */
175 #define CCOUNT(q)	((q)->c_cc)
176 
177 #define PPP_LOWAT	100	/* Process more output when < LOWAT on queue */
178 #define	PPP_HIWAT	400	/* Don't start a new packet if HIWAT on que */
179 
180 /*
181  * Line specific open routine for async tty devices.
182  * Attach the given tty to the first available ppp unit.
183  * Called from device open routine or ttioctl.
184  */
185 /* ARGSUSED */
186 static int
187 pppopen(dev_t dev, struct tty *tp)
188 {
189     struct lwp *l = curlwp;		/* XXX */
190     struct ppp_softc *sc;
191     int error, s;
192 
193     error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_PPP,
194 	KAUTH_REQ_NETWORK_INTERFACE_PPP_ADD, NULL, NULL, NULL);
195     if (error)
196 	return (error);
197 
198     s = spltty();
199 
200     if (tp->t_linesw == &ppp_disc) {
201 	sc = (struct ppp_softc *) tp->t_sc;
202 	if (sc != NULL && sc->sc_devp == (void *) tp) {
203 	    splx(s);
204 	    return (0);
205 	}
206     }
207 
208     if ((sc = pppalloc(l->l_proc->p_pid)) == NULL) {
209 	splx(s);
210 	return ENXIO;
211     }
212 
213     if (sc->sc_relinq)
214 	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
215 
216     /* Switch DLT to PPP-over-serial. */
217     bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN);
218 
219     sc->sc_ilen = 0;
220     sc->sc_m = NULL;
221     memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap));
222     sc->sc_asyncmap[0] = 0xffffffff;
223     sc->sc_asyncmap[3] = 0x60000000;
224     sc->sc_rasyncmap = 0;
225     sc->sc_devp = (void *) tp;
226     sc->sc_start = pppasyncstart;
227     sc->sc_ctlp = pppasyncctlp;
228     sc->sc_relinq = pppasyncrelinq;
229     sc->sc_outm = NULL;
230     pppgetm(sc);
231     sc->sc_if.if_flags |= IFF_RUNNING;
232     sc->sc_if.if_baudrate = tp->t_ospeed;
233 
234     tp->t_sc = (void *) sc;
235     ttylock(tp);
236     ttyflush(tp, FREAD | FWRITE);
237     ttyunlock(tp);
238 
239     splx(s);
240     return (0);
241 }
242 
243 /*
244  * Line specific close routine, called from device close routine
245  * and from ttioctl.
246  * Detach the tty from the ppp unit.
247  * Mimics part of ttyclose().
248  */
249 static int
250 pppclose(struct tty *tp, int flag)
251 {
252     struct ppp_softc *sc;
253     int s;
254 
255     s = spltty();
256     ttylock(tp);
257     ttyflush(tp, FREAD|FWRITE);
258     ttyunlock(tp);	/* XXX */
259     ttyldisc_release(tp->t_linesw);
260     tp->t_linesw = ttyldisc_default();
261     sc = (struct ppp_softc *) tp->t_sc;
262     if (sc != NULL) {
263 	tp->t_sc = NULL;
264 	if (tp == (struct tty *) sc->sc_devp) {
265 	    pppasyncrelinq(sc);
266 	    pppdealloc(sc);
267 	}
268     }
269     splx(s);
270     return 0;
271 }
272 
273 /*
274  * Relinquish the interface unit to another device.
275  */
276 static void
277 pppasyncrelinq(struct ppp_softc *sc)
278 {
279     int s;
280 
281     /* Change DLT to back none. */
282     bpf_change_type(&sc->sc_if, DLT_NULL, 0);
283 
284     s = spltty();
285     if (sc->sc_outm) {
286 	m_freem(sc->sc_outm);
287 	sc->sc_outm = NULL;
288     }
289     if (sc->sc_m) {
290 	m_freem(sc->sc_m);
291 	sc->sc_m = NULL;
292     }
293     if (sc->sc_flags & SC_TIMEOUT) {
294 	callout_stop(&sc->sc_timo_ch);
295 	sc->sc_flags &= ~SC_TIMEOUT;
296     }
297     splx(s);
298 }
299 
300 /*
301  * Line specific (tty) read routine.
302  */
303 static int
304 pppread(struct tty *tp, struct uio *uio, int flag)
305 {
306     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
307     struct mbuf *m, *m0;
308     int error = 0;
309 
310     if (sc == NULL)
311 	return 0;
312     /*
313      * Loop waiting for input, checking that nothing disastrous
314      * happens in the meantime.
315      */
316     ttylock(tp);
317     for (;;) {
318 	if (tp != (struct tty *) sc->sc_devp ||
319 	    tp->t_linesw != &ppp_disc) {
320 	    ttyunlock(tp);
321 	    return 0;
322 	}
323 	if (sc->sc_inq.ifq_head != NULL)
324 	    break;
325 	if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
326 	    && (tp->t_state & TS_ISOPEN)) {
327 	    ttyunlock(tp);
328 	    return 0;		/* end of file */
329 	}
330 	if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
331 	    ttyunlock(tp);
332 	    return (EWOULDBLOCK);
333 	}
334 	error = ttysleep(tp, &tp->t_rawcv, true, 0);
335 	if (error) {
336 	    ttyunlock(tp);
337 	    return error;
338 	}
339     }
340 
341     /* Pull place-holder byte out of canonical queue */
342     getc(&tp->t_canq);
343 
344     /* Get the packet from the input queue */
345     IF_DEQUEUE(&sc->sc_inq, m0);
346     ttyunlock(tp);
347 
348     for (m = m0; m && uio->uio_resid; m = m->m_next)
349 	if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
350 	    break;
351     m_freem(m0);
352     return (error);
353 }
354 
355 /*
356  * Line specific (tty) write routine.
357  */
358 static int
359 pppwrite(struct tty *tp, struct uio *uio, int flag)
360 {
361     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
362     struct mbuf *m, *m0;
363     struct sockaddr dst;
364     int len, error;
365 
366     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
367 	return 0;		/* wrote 0 bytes */
368     if (tp->t_linesw != &ppp_disc)
369 	return (EINVAL);
370     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
371 	return EIO;
372     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
373 	uio->uio_resid < PPP_HDRLEN)
374 	return (EMSGSIZE);
375 
376     MGETHDR(m0, M_WAIT, MT_DATA);
377     if (m0 == NULL)
378 	return ENOBUFS;
379 
380     m0->m_len = 0;
381     m0->m_pkthdr.len = uio->uio_resid;
382     m_reset_rcvif(m0);
383 
384     if (uio->uio_resid >= MCLBYTES / 2)
385 	MCLGET(m0, M_DONTWAIT);
386 
387     for (m = m0; uio->uio_resid;) {
388 	len = M_TRAILINGSPACE(m);
389 	if (len > uio->uio_resid)
390 	    len = uio->uio_resid;
391 	if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
392 	    m_freem(m0);
393 	    return (error);
394 	}
395 	m->m_len = len;
396 
397 	if (uio->uio_resid == 0)
398 	    break;
399 
400 	MGET(m->m_next, M_WAIT, MT_DATA);
401 	if (m->m_next == NULL) {
402 	    m_freem(m0);
403 	    return ENOBUFS;
404 	}
405 	m = m->m_next;
406 	m->m_len = 0;
407     }
408     dst.sa_family = AF_UNSPEC;
409     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
410     m_adj(m0, PPP_HDRLEN);
411     return if_output_lock(&sc->sc_if, &sc->sc_if, m0, &dst, (struct rtentry *)0);
412 }
413 
414 /*
415  * Line specific (tty) ioctl routine.
416  * This discipline requires that tty device drivers call
417  * the line specific l_ioctl routine from their ioctl routines.
418  */
419 /* ARGSUSED */
420 static int
421 ppptioctl(struct tty *tp, u_long cmd, void *data, int flag, struct lwp *l)
422 {
423     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
424     int error, s;
425 
426     if (sc == NULL)
427         return (EPASSTHROUGH);
428 
429     KERNEL_LOCK(1, NULL);
430 
431     if (tp != (struct tty *) sc->sc_devp) {
432         error = EPASSTHROUGH;
433         goto out;
434     }
435 
436     error = 0;
437     switch (cmd) {
438     case PPPIOCSASYNCMAP:
439 	if ((error = kauth_authorize_device_tty(l->l_cred,
440  	  KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
441 	    break;
442 	sc->sc_asyncmap[0] = *(u_int *)data;
443 	break;
444 
445     case PPPIOCGASYNCMAP:
446 	*(u_int *)data = sc->sc_asyncmap[0];
447 	break;
448 
449     case PPPIOCSRASYNCMAP:
450 	if ((error = kauth_authorize_device_tty(l->l_cred,
451 	  KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
452 	    break;
453 	sc->sc_rasyncmap = *(u_int *)data;
454 	break;
455 
456     case PPPIOCGRASYNCMAP:
457 	*(u_int *)data = sc->sc_rasyncmap;
458 	break;
459 
460     case PPPIOCSXASYNCMAP:
461 	if ((error = kauth_authorize_device_tty(l->l_cred,
462 	  KAUTH_DEVICE_TTY_PRIVSET, tp)) != 0)
463 	    break;
464 	s = spltty();
465 	bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
466 	sc->sc_asyncmap[1] = 0;		    /* mustn't escape 0x20 - 0x3f */
467 	sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
468 	sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
469 	splx(s);
470 	break;
471 
472     case PPPIOCGXASYNCMAP:
473 	bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
474 	break;
475 
476     default:
477 	error = pppioctl(sc, cmd, data, flag, l);
478 	if (error == 0 && cmd == PPPIOCSMRU)
479 	    pppgetm(sc);
480     }
481 
482  out:
483     KERNEL_UNLOCK_ONE(NULL);
484     return error;
485 }
486 
487 /*
488  * FCS lookup table as calculated by genfcstab.
489  */
490 static const uint16_t fcstab[256] = {
491 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
492 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
493 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
494 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
495 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
496 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
497 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
498 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
499 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
500 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
501 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
502 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
503 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
504 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
505 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
506 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
507 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
508 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
509 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
510 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
511 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
512 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
513 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
514 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
515 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
516 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
517 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
518 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
519 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
520 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
521 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
522 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
523 };
524 
525 /*
526  * Calculate a new FCS given the current FCS and the new data.
527  */
528 static uint16_t
529 pppfcs(uint16_t fcs, const uint8_t *cp, int len)
530 {
531     while (len--)
532 	fcs = PPP_FCS(fcs, *cp++);
533     return (fcs);
534 }
535 
536 /*
537  * This gets called at splsoftnet from if_ppp.c at various times
538  * when there is data ready to be sent.
539  */
540 static void
541 pppasyncstart(struct ppp_softc *sc)
542 {
543     struct tty *tp = (struct tty *) sc->sc_devp;
544     struct mbuf *m;
545     int len;
546     u_char *start, *stop, *cp;
547     int n, ndone, done, idle;
548     struct mbuf *m2;
549 
550     ttylock(tp);
551 
552     idle = 0;
553     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
554 	/*
555 	 * See if we have an existing packet partly sent.
556 	 * If not, get a new packet and start sending it.
557 	 */
558 	m = sc->sc_outm;
559 	if (m == NULL) {
560 	    /*
561 	     * Get another packet to be sent.
562 	     */
563 	    m = ppp_dequeue(sc);
564 	    if (m == NULL) {
565 		idle = 1;
566 		break;
567 	    }
568 
569 	    /*
570 	     * The extra PPP_FLAG will start up a new packet, and thus
571 	     * will flush any accumulated garbage.  We do this whenever
572 	     * the line may have been idle for some time.
573 	     */
574 	    if (CCOUNT(&tp->t_outq) == 0) {
575 		++sc->sc_stats.ppp_obytes;
576 		(void) putc(PPP_FLAG, &tp->t_outq);
577 	    }
578 
579 	    /* Calculate the FCS for the first mbuf's worth. */
580 	    sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, uint8_t *), m->m_len);
581 	}
582 
583 	for (;;) {
584 	    start = mtod(m, u_char *);
585 	    len = m->m_len;
586 	    stop = start + len;
587 	    while (len > 0) {
588 		/*
589 		 * Find out how many bytes in the string we can
590 		 * handle without doing something special.
591 		 */
592 		for (cp = start; cp < stop; cp++)
593 		    if (ESCAPE_P(*cp))
594 			break;
595 		n = cp - start;
596 		if (n) {
597 		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
598 		    ndone = n - b_to_q(start, n, &tp->t_outq);
599 		    len -= ndone;
600 		    start += ndone;
601 		    sc->sc_stats.ppp_obytes += ndone;
602 
603 		    if (ndone < n)
604 			break;	/* packet doesn't fit */
605 		}
606 		/*
607 		 * If there are characters left in the mbuf,
608 		 * the first one must be special.
609 		 * Put it out in a different form.
610 		 */
611 		if (len) {
612 		    if (putc(PPP_ESCAPE, &tp->t_outq))
613 			break;
614 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
615 			(void) unputc(&tp->t_outq);
616 			break;
617 		    }
618 		    sc->sc_stats.ppp_obytes += 2;
619 		    start++;
620 		    len--;
621 		}
622 	    }
623 
624 	    /*
625 	     * If we didn't empty this mbuf, remember where we're up to.
626 	     * If we emptied the last mbuf, try to add the FCS and closing
627 	     * flag, and if we can't, leave sc_outm pointing to m, but with
628 	     * m->m_len == 0, to remind us to output the FCS and flag later.
629 	     */
630 	    done = len == 0;
631 	    if (done && m->m_next == NULL) {
632 		u_char *p, *q;
633 		int c;
634 		u_char endseq[8];
635 
636 		/*
637 		 * We may have to escape the bytes in the FCS.
638 		 */
639 		p = endseq;
640 		c = ~sc->sc_outfcs & 0xFF;
641 		if (ESCAPE_P(c)) {
642 		    *p++ = PPP_ESCAPE;
643 		    *p++ = c ^ PPP_TRANS;
644 		} else
645 		    *p++ = c;
646 		c = (~sc->sc_outfcs >> 8) & 0xFF;
647 		if (ESCAPE_P(c)) {
648 		    *p++ = PPP_ESCAPE;
649 		    *p++ = c ^ PPP_TRANS;
650 		} else
651 		    *p++ = c;
652 		*p++ = PPP_FLAG;
653 
654 		/*
655 		 * Try to output the FCS and flag.  If the bytes
656 		 * don't all fit, back out.
657 		 */
658 		for (q = endseq; q < p; ++q)
659 		    if (putc(*q, &tp->t_outq)) {
660 			done = 0;
661 			for (; q > endseq; --q)
662 			    unputc(&tp->t_outq);
663 			break;
664 		    }
665 		if (done)
666 		    sc->sc_stats.ppp_obytes += q - endseq;
667 	    }
668 
669 	    if (!done) {
670 		/* remember where we got to */
671 		m->m_data = start;
672 		m->m_len = len;
673 		break;
674 	    }
675 
676 	    /* Finished with this mbuf; free it and move on. */
677 	    m = m2 = m_free(m);
678 	    if (m == NULL) {
679 		/* Finished a packet */
680 		break;
681 	    }
682 	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, uint8_t *), m->m_len);
683 	}
684 
685 	/*
686 	 * If m == NULL, we have finished a packet.
687 	 * If m != NULL, we've either done as much work this time
688 	 * as we need to, or else we've filled up the output queue.
689 	 */
690 	sc->sc_outm = m;
691 	if (m)
692 	    break;
693     }
694 
695     /* Call pppstart to start output again if necessary. */
696     pppstart(tp);
697 
698     /*
699      * This timeout is needed for operation on a pseudo-tty,
700      * because the pty code doesn't call pppstart after it has
701      * drained the t_outq.
702      */
703     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
704 	callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
705 	sc->sc_flags |= SC_TIMEOUT;
706     }
707 
708     ttyunlock(tp);
709 }
710 
711 /*
712  * This gets called when a received packet is placed on
713  * the inq, at splsoftnet.
714  */
715 static void
716 pppasyncctlp(struct ppp_softc *sc)
717 {
718     struct tty *tp;
719 
720     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
721     tp = (struct tty *) sc->sc_devp;
722     ttylock(tp);
723     putc(0, &tp->t_canq);
724     ttwakeup(tp);
725     ttyunlock(tp);
726 }
727 
728 /*
729  * Start output on async tty interface.  If the transmit queue
730  * has drained sufficiently, arrange for pppasyncstart to be
731  * called later at splsoftnet.
732  * Called at spltty or higher.
733  */
734 static int
735 pppstart(struct tty *tp)
736 {
737     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
738 
739     /*
740      * If there is stuff in the output queue, send it now.
741      * We are being called in lieu of ttstart and must do what it would.
742      */
743     if (tp->t_oproc != NULL)
744 	(*tp->t_oproc)(tp);
745 
746     /*
747      * If the transmit queue has drained and the tty has not hung up
748      * or been disconnected from the ppp unit, then tell if_ppp.c that
749      * we need more output.
750      */
751     if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
752 	&& ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
753 	return 0;
754 #ifdef ALTQ
755     /*
756      * if ALTQ is enabled, don't invoke NETISR_PPP.
757      * pppintr() could loop without doing anything useful
758      * under rate-limiting.
759      */
760     if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
761 	return 0;
762 #endif
763     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
764 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
765 	ppp_restart(sc);
766     }
767 
768     return 0;
769 }
770 
771 /*
772  * Timeout routine - try to start some more output.
773  */
774 static void
775 ppp_timeout(void *x)
776 {
777     struct ppp_softc *sc = (struct ppp_softc *) x;
778     struct tty *tp = (struct tty *) sc->sc_devp;
779 
780     ttylock(tp);
781     sc->sc_flags &= ~SC_TIMEOUT;
782     pppstart(tp);
783     ttyunlock(tp);
784 }
785 
786 /*
787  * Allocate enough mbuf to handle current MRU.
788  */
789 static void
790 pppgetm(struct ppp_softc *sc)
791 {
792     struct mbuf *m, **mp;
793     int len;
794 
795     mp = &sc->sc_m;
796     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
797 	if ((m = *mp) == NULL) {
798 	    MGETHDR(m, M_DONTWAIT, MT_DATA);
799 	    if (m == NULL)
800 		break;
801 	    *mp = m;
802 	    MCLGET(m, M_DONTWAIT);
803 	}
804 	len -= M_BUFSIZE(m);
805 	mp = &m->m_next;
806     }
807 }
808 
809 /*
810  * tty interface receiver interrupt.
811  */
812 static const unsigned paritytab[8] = {
813     0x96696996, 0x69969669, 0x69969669, 0x96696996,
814     0x69969669, 0x96696996, 0x96696996, 0x69969669
815 };
816 
817 static int
818 pppinput(int c, struct tty *tp)
819 {
820     struct ppp_softc *sc;
821     struct mbuf *m;
822     int ilen, s;
823     int result;
824 
825     sc = (struct ppp_softc *) tp->t_sc;
826     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
827 	return 0;
828 
829     ++tk_nin;
830     ++sc->sc_stats.ppp_ibytes;
831 
832     if (c & TTY_FE) {
833 	/* framing error or overrun on this char - abort packet */
834 	if (sc->sc_flags & SC_DEBUG)
835 	    printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
836 	goto flush;
837     }
838 
839     c &= 0xff;
840 
841     /*
842      * Handle software flow control of output.
843      */
844     result = tty_try_xonxoff(tp, c);
845     if (result == 0) {
846 	    /* Character was recognized and consumed. */
847 	    return 0;
848     }
849     /* Character wasn't consumed, continue processing it. */
850 
851     s = spltty();
852     if (c & 0x80)
853 	sc->sc_flags |= SC_RCV_B7_1;
854     else
855 	sc->sc_flags |= SC_RCV_B7_0;
856     if (paritytab[c >> 5] & (1U << (c & 0x1F)))
857 	sc->sc_flags |= SC_RCV_ODDP;
858     else
859 	sc->sc_flags |= SC_RCV_EVNP;
860     splx(s);
861 
862     ppplogchar(sc, c);
863 
864     if (c == PPP_FLAG) {
865 	ilen = sc->sc_ilen;
866 	sc->sc_ilen = 0;
867 
868 	if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
869 	    ppplogchar(sc, -1);
870 
871 	/*
872 	 * If SC_ESCAPED is set, then we've seen the packet
873 	 * abort sequence "}~".
874 	 */
875 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
876 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
877 	    s = spltty();
878 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
879 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
880 		if (sc->sc_flags & SC_DEBUG)
881 		    printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
882 			sc->sc_fcs);
883 		if_statinc(&sc->sc_if, if_ierrors);
884 		sc->sc_stats.ppp_ierrors++;
885 	    } else
886 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
887 	    splx(s);
888 	    return 0;
889 	}
890 
891 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
892 	    if (ilen) {
893 		if (sc->sc_flags & SC_DEBUG)
894 		    printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
895 		s = spltty();
896 		if_statinc(&sc->sc_if, if_ierrors);
897 		sc->sc_stats.ppp_ierrors++;
898 		sc->sc_flags |= SC_PKTLOST;
899 		splx(s);
900 	    }
901 	    return 0;
902 	}
903 
904 	/*
905 	 * Remove FCS trailer.  Somewhat painful...
906 	 */
907 	ilen -= 2;
908 	if (--sc->sc_mc->m_len == 0) {
909 	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
910 		;
911 	    sc->sc_mc = m;
912 	}
913 	sc->sc_mc->m_len--;
914 
915 	/* excise this mbuf chain */
916 	m = sc->sc_m;
917 	sc->sc_m = sc->sc_mc->m_next;
918 	sc->sc_mc->m_next = NULL;
919 
920 	ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
921 	if (sc->sc_flags & SC_PKTLOST) {
922 	    s = spltty();
923 	    sc->sc_flags &= ~SC_PKTLOST;
924 	    splx(s);
925 	}
926 
927 	pppgetm(sc);
928 	return 0;
929     }
930 
931     if (sc->sc_flags & SC_FLUSH) {
932 	if (sc->sc_flags & SC_LOG_FLUSH)
933 	    ppplogchar(sc, c);
934 	return 0;
935     }
936 
937     if (c < 0x20 && (sc->sc_rasyncmap & (1U << c)))
938 	return 0;
939 
940     s = spltty();
941     if (sc->sc_flags & SC_ESCAPED) {
942 	sc->sc_flags &= ~SC_ESCAPED;
943 	c ^= PPP_TRANS;
944     } else if (c == PPP_ESCAPE) {
945 	sc->sc_flags |= SC_ESCAPED;
946 	splx(s);
947 	return 0;
948     }
949     splx(s);
950 
951     /*
952      * Initialize buffer on first octet received.
953      * First octet could be address or protocol (when compressing
954      * address/control).
955      * Second octet is control.
956      * Third octet is first or second (when compressing protocol)
957      * octet of protocol.
958      * Fourth octet is second octet of protocol.
959      */
960     if (sc->sc_ilen == 0) {
961 	/* reset the first input mbuf */
962 	if (sc->sc_m == NULL) {
963 	    pppgetm(sc);
964 	    if (sc->sc_m == NULL) {
965 		if (sc->sc_flags & SC_DEBUG)
966 		    printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
967 		goto flush;
968 	    }
969 	}
970 	m = sc->sc_m;
971 	m->m_len = 0;
972 	MRESETDATA(m);
973 	sc->sc_mc = m;
974 	sc->sc_mp = mtod(m, char *);
975 	sc->sc_fcs = PPP_INITFCS;
976 	if (c != PPP_ALLSTATIONS) {
977 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
978 		if (sc->sc_flags & SC_DEBUG)
979 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
980 		    sc->sc_if.if_xname, c);
981 		goto flush;
982 	    }
983 	    *sc->sc_mp++ = PPP_ALLSTATIONS;
984 	    *sc->sc_mp++ = PPP_UI;
985 	    sc->sc_ilen += 2;
986 	    m->m_len += 2;
987 	}
988     }
989     if (sc->sc_ilen == 1 && c != PPP_UI) {
990 	if (sc->sc_flags & SC_DEBUG)
991 	    printf("%s: missing UI (0x3), got 0x%x\n",
992 		sc->sc_if.if_xname, c);
993 	goto flush;
994     }
995     if (sc->sc_ilen == 2 && (c & 1) == 1) {
996 	/* a compressed protocol */
997 	*sc->sc_mp++ = 0;
998 	sc->sc_ilen++;
999 	sc->sc_mc->m_len++;
1000     }
1001     if (sc->sc_ilen == 3 && (c & 1) == 0) {
1002 	if (sc->sc_flags & SC_DEBUG)
1003 	    printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1004 		(sc->sc_mp[-1] << 8) + c);
1005 	goto flush;
1006     }
1007 
1008     /* packet beyond configured mru? */
1009     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1010 	if (sc->sc_flags & SC_DEBUG)
1011 	    printf("%s: packet too big\n", sc->sc_if.if_xname);
1012 	goto flush;
1013     }
1014 
1015     /* is this mbuf full? */
1016     m = sc->sc_mc;
1017     if (M_TRAILINGSPACE(m) <= 0) {
1018 	if (m->m_next == NULL) {
1019 	    pppgetm(sc);
1020 	    if (m->m_next == NULL) {
1021 		if (sc->sc_flags & SC_DEBUG)
1022 		    printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1023 		goto flush;
1024 	    }
1025 	}
1026 	sc->sc_mc = m = m->m_next;
1027 	m->m_len = 0;
1028 	MRESETDATA(m);
1029 	sc->sc_mp = mtod(m, char *);
1030     }
1031 
1032     ++m->m_len;
1033     *sc->sc_mp++ = c;
1034     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1035     return 0;
1036 
1037  flush:
1038     if (!(sc->sc_flags & SC_FLUSH)) {
1039 	s = spltty();
1040 	if_statinc(&sc->sc_if, if_ierrors);
1041 	sc->sc_stats.ppp_ierrors++;
1042 	sc->sc_flags |= SC_FLUSH;
1043 	splx(s);
1044 	if (sc->sc_flags & SC_LOG_FLUSH)
1045 	    ppplogchar(sc, c);
1046     }
1047     return 0;
1048 }
1049 
1050 #define MAX_DUMP_BYTES	128
1051 
1052 static void
1053 ppplogchar(struct ppp_softc *sc, int c)
1054 {
1055     if (c >= 0) {
1056 	sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
1057 	if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
1058 	    sc->sc_rawin.count++;
1059     }
1060     if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
1061 	|| (c < 0 && sc->sc_rawin_start > 0)) {
1062 	if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
1063 	    printf("%s input: ", sc->sc_if.if_xname);
1064 	    pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
1065 	}
1066 	if (c < 0)
1067 	    sc->sc_rawin.count = 0;
1068 	sc->sc_rawin_start = 0;
1069     }
1070 }
1071 
1072 static void
1073 pppdumpb(u_char *b, int l)
1074 {
1075     char bf[3*MAX_DUMP_BYTES+4];
1076     char *bp = bf;
1077 
1078     while (l--) {
1079 	if (bp >= bf + sizeof(bf) - 3) {
1080 	    *bp++ = '>';
1081 	    break;
1082 	}
1083 	*bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
1084 	*bp++ = hexdigits[*b++ & 0xf];
1085 	*bp++ = ' ';
1086     }
1087 
1088     *bp = 0;
1089     printf("%s\n", bf);
1090 }
1091