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