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