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