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