xref: /netbsd-src/sys/net/ppp_tty.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: ppp_tty.c,v 1.42 2006/05/14 21:19:33 elad 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.42 2006/05/14 21:19:33 elad 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, caddr_t 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 proc *p = curproc;		/* XXX */
208     struct ppp_softc *sc;
209     int error, s;
210 
211     if ((error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag)) != 0)
212 	return (error);
213 
214     s = spltty();
215 
216     if (tp->t_linesw == &ppp_disc) {
217 	sc = (struct ppp_softc *) tp->t_sc;
218 	if (sc != NULL && sc->sc_devp == (void *) tp) {
219 	    splx(s);
220 	    return (0);
221 	}
222     }
223 
224     if ((sc = pppalloc(p->p_pid)) == NULL) {
225 	splx(s);
226 	return ENXIO;
227     }
228 
229     if (sc->sc_relinq)
230 	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
231 
232 #if NBPFILTER > 0
233     /* Switch DLT to PPP-over-serial. */
234     bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN);
235 #endif
236 
237     sc->sc_ilen = 0;
238     sc->sc_m = NULL;
239     memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap));
240     sc->sc_asyncmap[0] = 0xffffffff;
241     sc->sc_asyncmap[3] = 0x60000000;
242     sc->sc_rasyncmap = 0;
243     sc->sc_devp = (void *) tp;
244     sc->sc_start = pppasyncstart;
245     sc->sc_ctlp = pppasyncctlp;
246     sc->sc_relinq = pppasyncrelinq;
247     sc->sc_outm = NULL;
248     pppgetm(sc);
249     sc->sc_if.if_flags |= IFF_RUNNING;
250     sc->sc_if.if_baudrate = tp->t_ospeed;
251 
252     tp->t_sc = (caddr_t) sc;
253     ttyflush(tp, FREAD | FWRITE);
254 
255     splx(s);
256     return (0);
257 }
258 
259 /*
260  * Line specific close routine, called from device close routine
261  * and from ttioctl.
262  * Detach the tty from the ppp unit.
263  * Mimics part of ttyclose().
264  */
265 static int
266 pppclose(struct tty *tp, int flag)
267 {
268     struct ppp_softc *sc;
269     int s;
270 
271     s = spltty();
272     ttyflush(tp, FREAD|FWRITE);
273     ttyldisc_release(tp->t_linesw);
274     tp->t_linesw = ttyldisc_default();
275     sc = (struct ppp_softc *) tp->t_sc;
276     if (sc != NULL) {
277 	tp->t_sc = NULL;
278 	if (tp == (struct tty *) sc->sc_devp) {
279 	    pppasyncrelinq(sc);
280 	    pppdealloc(sc);
281 	}
282     }
283     splx(s);
284     return 0;
285 }
286 
287 /*
288  * Relinquish the interface unit to another device.
289  */
290 static void
291 pppasyncrelinq(struct ppp_softc *sc)
292 {
293     int s;
294 
295 #if NBPFILTER > 0
296     /* Change DLT to back none. */
297     bpf_change_type(&sc->sc_if, DLT_NULL, 0);
298 #endif
299 
300     s = spltty();
301     if (sc->sc_outm) {
302 	m_freem(sc->sc_outm);
303 	sc->sc_outm = NULL;
304     }
305     if (sc->sc_m) {
306 	m_freem(sc->sc_m);
307 	sc->sc_m = NULL;
308     }
309     if (sc->sc_flags & SC_TIMEOUT) {
310 	callout_stop(&sc->sc_timo_ch);
311 	sc->sc_flags &= ~SC_TIMEOUT;
312     }
313     splx(s);
314 }
315 
316 /*
317  * Line specific (tty) read routine.
318  */
319 static int
320 pppread(struct tty *tp, struct uio *uio, int flag)
321 {
322     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
323     struct mbuf *m, *m0;
324     int s;
325     int error = 0;
326 
327     if (sc == NULL)
328 	return 0;
329     /*
330      * Loop waiting for input, checking that nothing disasterous
331      * happens in the meantime.
332      */
333     s = spltty();
334     for (;;) {
335 	if (tp != (struct tty *) sc->sc_devp ||
336 	    tp->t_linesw != &ppp_disc) {
337 	    splx(s);
338 	    return 0;
339 	}
340 	if (sc->sc_inq.ifq_head != NULL)
341 	    break;
342 	if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
343 	    && (tp->t_state & TS_ISOPEN)) {
344 	    splx(s);
345 	    return 0;		/* end of file */
346 	}
347 	if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
348 	    splx(s);
349 	    return (EWOULDBLOCK);
350 	}
351 	error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
352 	if (error) {
353 	    splx(s);
354 	    return error;
355 	}
356     }
357 
358     /* Pull place-holder byte out of canonical queue */
359     getc(&tp->t_canq);
360 
361     /* Get the packet from the input queue */
362     IF_DEQUEUE(&sc->sc_inq, m0);
363     splx(s);
364 
365     for (m = m0; m && uio->uio_resid; m = m->m_next)
366 	if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
367 	    break;
368     m_freem(m0);
369     return (error);
370 }
371 
372 /*
373  * Line specific (tty) write routine.
374  */
375 static int
376 pppwrite(struct tty *tp, struct uio *uio, int flag)
377 {
378     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
379     struct mbuf *m, *m0;
380     struct sockaddr dst;
381     int len, error;
382 
383     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
384 	return 0;		/* wrote 0 bytes */
385     if (tp->t_linesw != &ppp_disc)
386 	return (EINVAL);
387     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
388 	return EIO;
389     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
390 	uio->uio_resid < PPP_HDRLEN)
391 	return (EMSGSIZE);
392 
393     MGETHDR(m0, M_WAIT, MT_DATA);
394     if (m0 == NULL)
395 	return ENOBUFS;
396 
397     m0->m_len = 0;
398     m0->m_pkthdr.len = uio->uio_resid;
399     m0->m_pkthdr.rcvif = NULL;
400 
401     if (uio->uio_resid >= MCLBYTES / 2)
402 	MCLGET(m0, M_DONTWAIT);
403 
404     for (m = m0; uio->uio_resid;) {
405 	len = M_TRAILINGSPACE(m);
406 	if (len > uio->uio_resid)
407 	    len = uio->uio_resid;
408 	if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
409 	    m_freem(m0);
410 	    return (error);
411 	}
412 	m->m_len = len;
413 
414 	if (uio->uio_resid == 0)
415 	    break;
416 
417 	MGET(m->m_next, M_WAIT, MT_DATA);
418 	if (m->m_next == NULL) {
419 	    m_freem(m0);
420 	    return ENOBUFS;
421 	}
422 	m = m->m_next;
423 	m->m_len = 0;
424     }
425     dst.sa_family = AF_UNSPEC;
426     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
427     m_adj(m0, PPP_HDRLEN);
428     return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
429 }
430 
431 /*
432  * Line specific (tty) ioctl routine.
433  * This discipline requires that tty device drivers call
434  * the line specific l_ioctl routine from their ioctl routines.
435  */
436 /* ARGSUSED */
437 static int
438 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct lwp *l)
439 {
440     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
441     int error, s;
442     struct proc *p = l->l_proc;
443 
444     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
445 	return (EPASSTHROUGH);
446 
447     error = 0;
448     switch (cmd) {
449     case TIOCRCVFRAME:
450     	ppprcvframe(sc,*((struct mbuf **)data));
451 	break;
452 
453     case PPPIOCSASYNCMAP:
454 	if ((error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag)) != 0)
455 	    break;
456 	sc->sc_asyncmap[0] = *(u_int *)data;
457 	break;
458 
459     case PPPIOCGASYNCMAP:
460 	*(u_int *)data = sc->sc_asyncmap[0];
461 	break;
462 
463     case PPPIOCSRASYNCMAP:
464 	if ((error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag)) != 0)
465 	    break;
466 	sc->sc_rasyncmap = *(u_int *)data;
467 	break;
468 
469     case PPPIOCGRASYNCMAP:
470 	*(u_int *)data = sc->sc_rasyncmap;
471 	break;
472 
473     case PPPIOCSXASYNCMAP:
474 	if ((error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, &p->p_acflag)) != 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, p);
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 u_int16_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 u_int16_t
646 pppfcs(u_int16_t fcs, u_char *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, (caddr_t)&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     int s;
703 
704     if (sc->sc_flags & SC_SYNC){
705 	pppsyncstart(sc);
706 	return;
707     }
708 
709     idle = 0;
710     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
711 	/*
712 	 * See if we have an existing packet partly sent.
713 	 * If not, get a new packet and start sending it.
714 	 */
715 	m = sc->sc_outm;
716 	if (m == NULL) {
717 	    /*
718 	     * Get another packet to be sent.
719 	     */
720 	    m = ppp_dequeue(sc);
721 	    if (m == NULL) {
722 		idle = 1;
723 		break;
724 	    }
725 
726 	    /*
727 	     * The extra PPP_FLAG will start up a new packet, and thus
728 	     * will flush any accumulated garbage.  We do this whenever
729 	     * the line may have been idle for some time.
730 	     */
731 	    if (CCOUNT(&tp->t_outq) == 0) {
732 		++sc->sc_stats.ppp_obytes;
733 		(void) putc(PPP_FLAG, &tp->t_outq);
734 	    }
735 
736 	    /* Calculate the FCS for the first mbuf's worth. */
737 	    sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
738 	}
739 
740 	for (;;) {
741 	    start = mtod(m, u_char *);
742 	    len = m->m_len;
743 	    stop = start + len;
744 	    while (len > 0) {
745 		/*
746 		 * Find out how many bytes in the string we can
747 		 * handle without doing something special.
748 		 */
749 		for (cp = start; cp < stop; cp++)
750 		    if (ESCAPE_P(*cp))
751 			break;
752 		n = cp - start;
753 		if (n) {
754 		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
755 		    ndone = n - b_to_q(start, n, &tp->t_outq);
756 		    len -= ndone;
757 		    start += ndone;
758 		    sc->sc_stats.ppp_obytes += ndone;
759 
760 		    if (ndone < n)
761 			break;	/* packet doesn't fit */
762 		}
763 		/*
764 		 * If there are characters left in the mbuf,
765 		 * the first one must be special.
766 		 * Put it out in a different form.
767 		 */
768 		if (len) {
769 		    s = spltty();
770 		    if (putc(PPP_ESCAPE, &tp->t_outq)) {
771 			splx(s);
772 			break;
773 		    }
774 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
775 			(void) unputc(&tp->t_outq);
776 			splx(s);
777 			break;
778 		    }
779 		    splx(s);
780 		    sc->sc_stats.ppp_obytes += 2;
781 		    start++;
782 		    len--;
783 		}
784 	    }
785 
786 	    /*
787 	     * If we didn't empty this mbuf, remember where we're up to.
788 	     * If we emptied the last mbuf, try to add the FCS and closing
789 	     * flag, and if we can't, leave sc_outm pointing to m, but with
790 	     * m->m_len == 0, to remind us to output the FCS and flag later.
791 	     */
792 	    done = len == 0;
793 	    if (done && m->m_next == NULL) {
794 		u_char *p, *q;
795 		int c;
796 		u_char endseq[8];
797 
798 		/*
799 		 * We may have to escape the bytes in the FCS.
800 		 */
801 		p = endseq;
802 		c = ~sc->sc_outfcs & 0xFF;
803 		if (ESCAPE_P(c)) {
804 		    *p++ = PPP_ESCAPE;
805 		    *p++ = c ^ PPP_TRANS;
806 		} else
807 		    *p++ = c;
808 		c = (~sc->sc_outfcs >> 8) & 0xFF;
809 		if (ESCAPE_P(c)) {
810 		    *p++ = PPP_ESCAPE;
811 		    *p++ = c ^ PPP_TRANS;
812 		} else
813 		    *p++ = c;
814 		*p++ = PPP_FLAG;
815 
816 		/*
817 		 * Try to output the FCS and flag.  If the bytes
818 		 * don't all fit, back out.
819 		 */
820 		s = spltty();
821 		for (q = endseq; q < p; ++q)
822 		    if (putc(*q, &tp->t_outq)) {
823 			done = 0;
824 			for (; q > endseq; --q)
825 			    unputc(&tp->t_outq);
826 			break;
827 		    }
828 		splx(s);
829 		if (done)
830 		    sc->sc_stats.ppp_obytes += q - endseq;
831 	    }
832 
833 	    if (!done) {
834 		/* remember where we got to */
835 		m->m_data = start;
836 		m->m_len = len;
837 		break;
838 	    }
839 
840 	    /* Finished with this mbuf; free it and move on. */
841 	    MFREE(m, m2);
842 	    m = m2;
843 	    if (m == NULL) {
844 		/* Finished a packet */
845 		break;
846 	    }
847 	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
848 	}
849 
850 	/*
851 	 * If m == NULL, we have finished a packet.
852 	 * If m != NULL, we've either done as much work this time
853 	 * as we need to, or else we've filled up the output queue.
854 	 */
855 	sc->sc_outm = m;
856 	if (m)
857 	    break;
858     }
859 
860     /* Call pppstart to start output again if necessary. */
861     s = spltty();
862     pppstart(tp);
863 
864     /*
865      * This timeout is needed for operation on a pseudo-tty,
866      * because the pty code doesn't call pppstart after it has
867      * drained the t_outq.
868      */
869     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
870 	callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
871 	sc->sc_flags |= SC_TIMEOUT;
872     }
873 
874     splx(s);
875 }
876 
877 /*
878  * This gets called when a received packet is placed on
879  * the inq, at splsoftnet.
880  */
881 static void
882 pppasyncctlp(struct ppp_softc *sc)
883 {
884     struct tty *tp;
885     int s;
886 
887     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
888     s = spltty();
889     tp = (struct tty *) sc->sc_devp;
890     putc(0, &tp->t_canq);
891     ttwakeup(tp);
892     splx(s);
893 }
894 
895 /*
896  * Start output on async tty interface.  If the transmit queue
897  * has drained sufficiently, arrange for pppasyncstart to be
898  * called later at splsoftnet.
899  * Called at spltty or higher.
900  */
901 static int
902 pppstart(struct tty *tp)
903 {
904     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
905 
906     /*
907      * If there is stuff in the output queue, send it now.
908      * We are being called in lieu of ttstart and must do what it would.
909      */
910     if (tp->t_oproc != NULL)
911 	(*tp->t_oproc)(tp);
912 
913     /*
914      * If the transmit queue has drained and the tty has not hung up
915      * or been disconnected from the ppp unit, then tell if_ppp.c that
916      * we need more output.
917      */
918     if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
919 	&& ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
920 	return 0;
921 #ifdef ALTQ
922     /*
923      * if ALTQ is enabled, don't invoke NETISR_PPP.
924      * pppintr() could loop without doing anything useful
925      * under rate-limiting.
926      */
927     if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
928 	return 0;
929 #endif
930     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
931 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
932 	ppp_restart(sc);
933     }
934 
935     return 0;
936 }
937 
938 /*
939  * Timeout routine - try to start some more output.
940  */
941 static void
942 ppp_timeout(void *x)
943 {
944     struct ppp_softc *sc = (struct ppp_softc *) x;
945     struct tty *tp = (struct tty *) sc->sc_devp;
946     int s;
947 
948     s = spltty();
949     sc->sc_flags &= ~SC_TIMEOUT;
950     pppstart(tp);
951     splx(s);
952 }
953 
954 /*
955  * Allocate enough mbuf to handle current MRU.
956  */
957 static void
958 pppgetm(struct ppp_softc *sc)
959 {
960     struct mbuf *m, **mp;
961     int len;
962 
963     mp = &sc->sc_m;
964     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
965 	if ((m = *mp) == NULL) {
966 	    MGETHDR(m, M_DONTWAIT, MT_DATA);
967 	    if (m == NULL)
968 		break;
969 	    *mp = m;
970 	    MCLGET(m, M_DONTWAIT);
971 	}
972 	len -= M_DATASIZE(m);
973 	mp = &m->m_next;
974     }
975 }
976 
977 /*
978  * tty interface receiver interrupt.
979  */
980 static const unsigned paritytab[8] = {
981     0x96696996, 0x69969669, 0x69969669, 0x96696996,
982     0x69969669, 0x96696996, 0x96696996, 0x69969669
983 };
984 
985 static int
986 pppinput(int c, struct tty *tp)
987 {
988     struct ppp_softc *sc;
989     struct mbuf *m;
990     const struct cdevsw *cdev;
991     int ilen, s;
992 
993     sc = (struct ppp_softc *) tp->t_sc;
994     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
995 	return 0;
996 
997     ++tk_nin;
998     ++sc->sc_stats.ppp_ibytes;
999 
1000     if (c & TTY_FE) {
1001 	/* framing error or overrun on this char - abort packet */
1002 	if (sc->sc_flags & SC_DEBUG)
1003 	    printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
1004 	goto flush;
1005     }
1006 
1007     c &= 0xff;
1008 
1009     /*
1010      * Handle software flow control of output.
1011      */
1012     if (tp->t_iflag & IXON) {
1013 	if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
1014 	    if ((tp->t_state & TS_TTSTOP) == 0) {
1015 		tp->t_state |= TS_TTSTOP;
1016 		cdev = cdevsw_lookup(tp->t_dev);
1017 		if (cdev != NULL)
1018 			(*cdev->d_stop)(tp, 0);
1019 	    }
1020 	    return 0;
1021 	}
1022 	if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
1023 	    tp->t_state &= ~TS_TTSTOP;
1024 	    if (tp->t_oproc != NULL)
1025 		(*tp->t_oproc)(tp);
1026 	    return 0;
1027 	}
1028     }
1029 
1030     s = spltty();
1031     if (c & 0x80)
1032 	sc->sc_flags |= SC_RCV_B7_1;
1033     else
1034 	sc->sc_flags |= SC_RCV_B7_0;
1035     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
1036 	sc->sc_flags |= SC_RCV_ODDP;
1037     else
1038 	sc->sc_flags |= SC_RCV_EVNP;
1039     splx(s);
1040 
1041     ppplogchar(sc, c);
1042 
1043     if (c == PPP_FLAG) {
1044 	ilen = sc->sc_ilen;
1045 	sc->sc_ilen = 0;
1046 
1047 	if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
1048 	    ppplogchar(sc, -1);
1049 
1050 	/*
1051 	 * If SC_ESCAPED is set, then we've seen the packet
1052 	 * abort sequence "}~".
1053 	 */
1054 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
1055 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
1056 	    s = spltty();
1057 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
1058 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
1059 		if (sc->sc_flags & SC_DEBUG)
1060 		    printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
1061 			sc->sc_fcs);
1062 		sc->sc_if.if_ierrors++;
1063 		sc->sc_stats.ppp_ierrors++;
1064 	    } else
1065 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1066 	    splx(s);
1067 	    return 0;
1068 	}
1069 
1070 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
1071 	    if (ilen) {
1072 		if (sc->sc_flags & SC_DEBUG)
1073 		    printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
1074 		s = spltty();
1075 		sc->sc_if.if_ierrors++;
1076 		sc->sc_stats.ppp_ierrors++;
1077 		sc->sc_flags |= SC_PKTLOST;
1078 		splx(s);
1079 	    }
1080 	    return 0;
1081 	}
1082 
1083 	/*
1084 	 * Remove FCS trailer.  Somewhat painful...
1085 	 */
1086 	ilen -= 2;
1087 	if (--sc->sc_mc->m_len == 0) {
1088 	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
1089 		;
1090 	    sc->sc_mc = m;
1091 	}
1092 	sc->sc_mc->m_len--;
1093 
1094 	/* excise this mbuf chain */
1095 	m = sc->sc_m;
1096 	sc->sc_m = sc->sc_mc->m_next;
1097 	sc->sc_mc->m_next = NULL;
1098 
1099 	ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1100 	if (sc->sc_flags & SC_PKTLOST) {
1101 	    s = spltty();
1102 	    sc->sc_flags &= ~SC_PKTLOST;
1103 	    splx(s);
1104 	}
1105 
1106 	pppgetm(sc);
1107 	return 0;
1108     }
1109 
1110     if (sc->sc_flags & SC_FLUSH) {
1111 	if (sc->sc_flags & SC_LOG_FLUSH)
1112 	    ppplogchar(sc, c);
1113 	return 0;
1114     }
1115 
1116     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
1117 	return 0;
1118 
1119     s = spltty();
1120     if (sc->sc_flags & SC_ESCAPED) {
1121 	sc->sc_flags &= ~SC_ESCAPED;
1122 	c ^= PPP_TRANS;
1123     } else if (c == PPP_ESCAPE) {
1124 	sc->sc_flags |= SC_ESCAPED;
1125 	splx(s);
1126 	return 0;
1127     }
1128     splx(s);
1129 
1130     /*
1131      * Initialize buffer on first octet received.
1132      * First octet could be address or protocol (when compressing
1133      * address/control).
1134      * Second octet is control.
1135      * Third octet is first or second (when compressing protocol)
1136      * octet of protocol.
1137      * Fourth octet is second octet of protocol.
1138      */
1139     if (sc->sc_ilen == 0) {
1140 	/* reset the first input mbuf */
1141 	if (sc->sc_m == NULL) {
1142 	    pppgetm(sc);
1143 	    if (sc->sc_m == NULL) {
1144 		if (sc->sc_flags & SC_DEBUG)
1145 		    printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
1146 		goto flush;
1147 	    }
1148 	}
1149 	m = sc->sc_m;
1150 	m->m_len = 0;
1151 	m->m_data = M_DATASTART(sc->sc_m);
1152 	sc->sc_mc = m;
1153 	sc->sc_mp = mtod(m, char *);
1154 	sc->sc_fcs = PPP_INITFCS;
1155 	if (c != PPP_ALLSTATIONS) {
1156 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
1157 		if (sc->sc_flags & SC_DEBUG)
1158 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
1159 		    sc->sc_if.if_xname, c);
1160 		goto flush;
1161 	    }
1162 	    *sc->sc_mp++ = PPP_ALLSTATIONS;
1163 	    *sc->sc_mp++ = PPP_UI;
1164 	    sc->sc_ilen += 2;
1165 	    m->m_len += 2;
1166 	}
1167     }
1168     if (sc->sc_ilen == 1 && c != PPP_UI) {
1169 	if (sc->sc_flags & SC_DEBUG)
1170 	    printf("%s: missing UI (0x3), got 0x%x\n",
1171 		sc->sc_if.if_xname, c);
1172 	goto flush;
1173     }
1174     if (sc->sc_ilen == 2 && (c & 1) == 1) {
1175 	/* a compressed protocol */
1176 	*sc->sc_mp++ = 0;
1177 	sc->sc_ilen++;
1178 	sc->sc_mc->m_len++;
1179     }
1180     if (sc->sc_ilen == 3 && (c & 1) == 0) {
1181 	if (sc->sc_flags & SC_DEBUG)
1182 	    printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
1183 		(sc->sc_mp[-1] << 8) + c);
1184 	goto flush;
1185     }
1186 
1187     /* packet beyond configured mru? */
1188     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1189 	if (sc->sc_flags & SC_DEBUG)
1190 	    printf("%s: packet too big\n", sc->sc_if.if_xname);
1191 	goto flush;
1192     }
1193 
1194     /* is this mbuf full? */
1195     m = sc->sc_mc;
1196     if (M_TRAILINGSPACE(m) <= 0) {
1197 	if (m->m_next == NULL) {
1198 	    pppgetm(sc);
1199 	    if (m->m_next == NULL) {
1200 		if (sc->sc_flags & SC_DEBUG)
1201 		    printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
1202 		goto flush;
1203 	    }
1204 	}
1205 	sc->sc_mc = m = m->m_next;
1206 	m->m_len = 0;
1207 	m->m_data = M_DATASTART(m);
1208 	sc->sc_mp = mtod(m, char *);
1209     }
1210 
1211     ++m->m_len;
1212     *sc->sc_mp++ = c;
1213     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1214     return 0;
1215 
1216  flush:
1217     if (!(sc->sc_flags & SC_FLUSH)) {
1218 	s = spltty();
1219 	sc->sc_if.if_ierrors++;
1220 	sc->sc_stats.ppp_ierrors++;
1221 	sc->sc_flags |= SC_FLUSH;
1222 	splx(s);
1223 	if (sc->sc_flags & SC_LOG_FLUSH)
1224 	    ppplogchar(sc, c);
1225     }
1226     return 0;
1227 }
1228 
1229 #define MAX_DUMP_BYTES	128
1230 
1231 static void
1232 ppplogchar(struct ppp_softc *sc, int c)
1233 {
1234     if (c >= 0) {
1235 	sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
1236 	if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
1237 	    sc->sc_rawin.count++;
1238     }
1239     if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
1240 	|| (c < 0 && sc->sc_rawin_start > 0)) {
1241 	if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
1242 	    printf("%s input: ", sc->sc_if.if_xname);
1243 	    pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
1244 	}
1245 	if (c < 0)
1246 	    sc->sc_rawin.count = 0;
1247 	sc->sc_rawin_start = 0;
1248     }
1249 }
1250 
1251 static void
1252 pppdumpb(u_char *b, int l)
1253 {
1254     char bf[3*MAX_DUMP_BYTES+4];
1255     char *bp = bf;
1256 
1257     while (l--) {
1258 	if (bp >= bf + sizeof(bf) - 3) {
1259 	    *bp++ = '>';
1260 	    break;
1261 	}
1262 	*bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
1263 	*bp++ = hexdigits[*b++ & 0xf];
1264 	*bp++ = ' ';
1265     }
1266 
1267     *bp = 0;
1268     printf("%s\n", bf);
1269 }
1270 
1271 static void
1272 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit)
1273 {
1274 	int i,lcount,copycount,count;
1275 	char lbuf[16];
1276 	char *data;
1277 
1278 	if (m == NULL)
1279 		return;
1280 
1281 	for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
1282 		/* build a line of output */
1283 		for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
1284 			if (!count) {
1285 				m = m->m_next;
1286 				if (m == NULL)
1287 					break;
1288 				count = m->m_len;
1289 				data  = mtod(m,char*);
1290 			}
1291 			copycount = (count > sizeof(lbuf)-lcount) ?
1292 					sizeof(lbuf)-lcount : count;
1293 			bcopy(data,&lbuf[lcount],copycount);
1294 			data  += copycount;
1295 			count -= copycount;
1296 		}
1297 
1298 		/* output line (hex 1st, then ascii) */
1299 		printf("%s %s:", sc->sc_if.if_xname,
1300 		    xmit ? "output" : "input ");
1301 		for(i=0;i<lcount;i++)
1302 			printf("%02x ",(u_char)lbuf[i]);
1303 		for(;i<sizeof(lbuf);i++)
1304 			printf("   ");
1305 		for(i=0;i<lcount;i++)
1306 			printf("%c",(lbuf[i] >= 040 &&
1307 			    lbuf[i] <= 0176) ? lbuf[i] : '.');
1308 		printf("\n");
1309 	}
1310 }
1311