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