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