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