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