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