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