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