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