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