Home | History | Annotate | Line # | Download | only in net
ppp_tty.c revision 1.23.2.3
      1 /*	$NetBSD: ppp_tty.c,v 1.23.2.3 2001/06/21 20:08:19 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->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 ||
    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->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 		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     struct ppp_softc *sc;
    668 {
    669     struct tty *tp = (struct tty *) sc->sc_devp;
    670     struct mbuf *m;
    671     int len;
    672     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 	}
    712 
    713 	for (;;) {
    714 	    start = mtod(m, u_char *);
    715 	    len = m->m_len;
    716 	    stop = start + len;
    717 	    while (len > 0) {
    718 		/*
    719 		 * Find out how many bytes in the string we can
    720 		 * handle without doing something special.
    721 		 */
    722 		for (cp = start; cp < stop; cp++)
    723 		    if (ESCAPE_P(*cp))
    724 			break;
    725 		n = cp - start;
    726 		if (n) {
    727 		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
    728 		    ndone = n - b_to_q(start, n, &tp->t_outq);
    729 		    len -= ndone;
    730 		    start += ndone;
    731 		    sc->sc_stats.ppp_obytes += ndone;
    732 
    733 		    if (ndone < n)
    734 			break;	/* packet doesn't fit */
    735 		}
    736 		/*
    737 		 * If there are characters left in the mbuf,
    738 		 * the first one must be special.
    739 		 * Put it out in a different form.
    740 		 */
    741 		if (len) {
    742 		    s = spltty();
    743 		    if (putc(PPP_ESCAPE, &tp->t_outq)) {
    744 			splx(s);
    745 			break;
    746 		    }
    747 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
    748 			(void) unputc(&tp->t_outq);
    749 			splx(s);
    750 			break;
    751 		    }
    752 		    splx(s);
    753 		    sc->sc_stats.ppp_obytes += 2;
    754 		    start++;
    755 		    len--;
    756 		}
    757 	    }
    758 
    759 	    /*
    760 	     * If we didn't empty this mbuf, remember where we're up to.
    761 	     * If we emptied the last mbuf, try to add the FCS and closing
    762 	     * flag, and if we can't, leave sc_outm pointing to m, but with
    763 	     * m->m_len == 0, to remind us to output the FCS and flag later.
    764 	     */
    765 	    done = len == 0;
    766 	    if (done && m->m_next == NULL) {
    767 		u_char *p, *q;
    768 		int c;
    769 		u_char endseq[8];
    770 
    771 		/*
    772 		 * We may have to escape the bytes in the FCS.
    773 		 */
    774 		p = endseq;
    775 		c = ~sc->sc_outfcs & 0xFF;
    776 		if (ESCAPE_P(c)) {
    777 		    *p++ = PPP_ESCAPE;
    778 		    *p++ = c ^ PPP_TRANS;
    779 		} else
    780 		    *p++ = c;
    781 		c = (~sc->sc_outfcs >> 8) & 0xFF;
    782 		if (ESCAPE_P(c)) {
    783 		    *p++ = PPP_ESCAPE;
    784 		    *p++ = c ^ PPP_TRANS;
    785 		} else
    786 		    *p++ = c;
    787 		*p++ = PPP_FLAG;
    788 
    789 		/*
    790 		 * Try to output the FCS and flag.  If the bytes
    791 		 * don't all fit, back out.
    792 		 */
    793 		s = spltty();
    794 		for (q = endseq; q < p; ++q)
    795 		    if (putc(*q, &tp->t_outq)) {
    796 			done = 0;
    797 			for (; q > endseq; --q)
    798 			    unputc(&tp->t_outq);
    799 			break;
    800 		    }
    801 		splx(s);
    802 		if (done)
    803 		    sc->sc_stats.ppp_obytes += q - endseq;
    804 	    }
    805 
    806 	    if (!done) {
    807 		/* remember where we got to */
    808 		m->m_data = start;
    809 		m->m_len = len;
    810 		break;
    811 	    }
    812 
    813 	    /* Finished with this mbuf; free it and move on. */
    814 	    MFREE(m, m2);
    815 	    m = m2;
    816 	    if (m == NULL) {
    817 		/* Finished a packet */
    818 		break;
    819 	    }
    820 	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
    821 	}
    822 
    823 	/*
    824 	 * If m == NULL, we have finished a packet.
    825 	 * If m != NULL, we've either done as much work this time
    826 	 * as we need to, or else we've filled up the output queue.
    827 	 */
    828 	sc->sc_outm = m;
    829 	if (m)
    830 	    break;
    831     }
    832 
    833     /* Call pppstart to start output again if necessary. */
    834     s = spltty();
    835     pppstart(tp);
    836 
    837     /*
    838      * This timeout is needed for operation on a pseudo-tty,
    839      * because the pty code doesn't call pppstart after it has
    840      * drained the t_outq.
    841      */
    842     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
    843 	callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
    844 	sc->sc_flags |= SC_TIMEOUT;
    845     }
    846 
    847     splx(s);
    848 }
    849 
    850 /*
    851  * This gets called when a received packet is placed on
    852  * the inq, at splsoftnet.
    853  */
    854 static void
    855 pppasyncctlp(sc)
    856     struct ppp_softc *sc;
    857 {
    858     struct tty *tp;
    859     int s;
    860 
    861     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
    862     s = spltty();
    863     tp = (struct tty *) sc->sc_devp;
    864     putc(0, &tp->t_canq);
    865     ttwakeup(tp);
    866     splx(s);
    867 }
    868 
    869 /*
    870  * Start output on async tty interface.  If the transmit queue
    871  * has drained sufficiently, arrange for pppasyncstart to be
    872  * called later at splsoftnet.
    873  * Called at spltty or higher.
    874  */
    875 int
    876 pppstart(tp)
    877     struct tty *tp;
    878 {
    879     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
    880 
    881     /*
    882      * If there is stuff in the output queue, send it now.
    883      * We are being called in lieu of ttstart and must do what it would.
    884      */
    885     if (tp->t_oproc != NULL)
    886 	(*tp->t_oproc)(tp);
    887 
    888     /*
    889      * If the transmit queue has drained and the tty has not hung up
    890      * or been disconnected from the ppp unit, then tell if_ppp.c that
    891      * we need more output.
    892      */
    893     if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
    894 	&& ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
    895 	return 0;
    896     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
    897 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
    898 	ppp_restart(sc);
    899     }
    900 
    901     return 0;
    902 }
    903 
    904 /*
    905  * Timeout routine - try to start some more output.
    906  */
    907 static void
    908 ppp_timeout(x)
    909     void *x;
    910 {
    911     struct ppp_softc *sc = (struct ppp_softc *) x;
    912     struct tty *tp = (struct tty *) sc->sc_devp;
    913     int s;
    914 
    915     s = spltty();
    916     sc->sc_flags &= ~SC_TIMEOUT;
    917     pppstart(tp);
    918     splx(s);
    919 }
    920 
    921 /*
    922  * Allocate enough mbuf to handle current MRU.
    923  */
    924 static void
    925 pppgetm(sc)
    926     struct ppp_softc *sc;
    927 {
    928     struct mbuf *m, **mp;
    929     int len;
    930 
    931     mp = &sc->sc_m;
    932     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
    933 	if ((m = *mp) == NULL) {
    934 	    MGETHDR(m, M_DONTWAIT, MT_DATA);
    935 	    if (m == NULL)
    936 		break;
    937 	    *mp = m;
    938 	    MCLGET(m, M_DONTWAIT);
    939 	}
    940 	len -= M_DATASIZE(m);
    941 	mp = &m->m_next;
    942     }
    943 }
    944 
    945 /*
    946  * tty interface receiver interrupt.
    947  */
    948 static const unsigned paritytab[8] = {
    949     0x96696996, 0x69969669, 0x69969669, 0x96696996,
    950     0x69969669, 0x96696996, 0x96696996, 0x69969669
    951 };
    952 
    953 int
    954 pppinput(c, tp)
    955     int c;
    956     struct tty *tp;
    957 {
    958     struct ppp_softc *sc;
    959     struct mbuf *m;
    960     int ilen, s;
    961 
    962     sc = (struct ppp_softc *) tp->t_sc;
    963     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
    964 	return 0;
    965 
    966     ++tk_nin;
    967     ++sc->sc_stats.ppp_ibytes;
    968 
    969     if (c & TTY_FE) {
    970 	/* framing error or overrun on this char - abort packet */
    971 	if (sc->sc_flags & SC_DEBUG)
    972 	    printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
    973 	goto flush;
    974     }
    975 
    976     c &= 0xff;
    977 
    978     /*
    979      * Handle software flow control of output.
    980      */
    981     if (tp->t_iflag & IXON) {
    982 	if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
    983 	    if ((tp->t_state & TS_TTSTOP) == 0) {
    984 		tp->t_state |= TS_TTSTOP;
    985 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
    986 	    }
    987 	    return 0;
    988 	}
    989 	if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
    990 	    tp->t_state &= ~TS_TTSTOP;
    991 	    if (tp->t_oproc != NULL)
    992 		(*tp->t_oproc)(tp);
    993 	    return 0;
    994 	}
    995     }
    996 
    997     s = spltty();
    998     if (c & 0x80)
    999 	sc->sc_flags |= SC_RCV_B7_1;
   1000     else
   1001 	sc->sc_flags |= SC_RCV_B7_0;
   1002     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
   1003 	sc->sc_flags |= SC_RCV_ODDP;
   1004     else
   1005 	sc->sc_flags |= SC_RCV_EVNP;
   1006     splx(s);
   1007 
   1008     if (sc->sc_flags & SC_LOG_RAWIN)
   1009 	ppplogchar(sc, c);
   1010 
   1011     if (c == PPP_FLAG) {
   1012 	ilen = sc->sc_ilen;
   1013 	sc->sc_ilen = 0;
   1014 
   1015 	if (sc->sc_rawin_count > 0)
   1016 	    ppplogchar(sc, -1);
   1017 
   1018 	/*
   1019 	 * If SC_ESCAPED is set, then we've seen the packet
   1020 	 * abort sequence "}~".
   1021 	 */
   1022 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
   1023 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
   1024 	    s = spltty();
   1025 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
   1026 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
   1027 		if (sc->sc_flags & SC_DEBUG)
   1028 		    printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
   1029 			sc->sc_fcs);
   1030 		sc->sc_if.if_ierrors++;
   1031 		sc->sc_stats.ppp_ierrors++;
   1032 	    } else
   1033 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
   1034 	    splx(s);
   1035 	    return 0;
   1036 	}
   1037 
   1038 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
   1039 	    if (ilen) {
   1040 		if (sc->sc_flags & SC_DEBUG)
   1041 		    printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
   1042 		s = spltty();
   1043 		sc->sc_if.if_ierrors++;
   1044 		sc->sc_stats.ppp_ierrors++;
   1045 		sc->sc_flags |= SC_PKTLOST;
   1046 		splx(s);
   1047 	    }
   1048 	    return 0;
   1049 	}
   1050 
   1051 	/*
   1052 	 * Remove FCS trailer.  Somewhat painful...
   1053 	 */
   1054 	ilen -= 2;
   1055 	if (--sc->sc_mc->m_len == 0) {
   1056 	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
   1057 		;
   1058 	    sc->sc_mc = m;
   1059 	}
   1060 	sc->sc_mc->m_len--;
   1061 
   1062 	/* excise this mbuf chain */
   1063 	m = sc->sc_m;
   1064 	sc->sc_m = sc->sc_mc->m_next;
   1065 	sc->sc_mc->m_next = NULL;
   1066 
   1067 	ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
   1068 	if (sc->sc_flags & SC_PKTLOST) {
   1069 	    s = spltty();
   1070 	    sc->sc_flags &= ~SC_PKTLOST;
   1071 	    splx(s);
   1072 	}
   1073 
   1074 	pppgetm(sc);
   1075 	return 0;
   1076     }
   1077 
   1078     if (sc->sc_flags & SC_FLUSH) {
   1079 	if (sc->sc_flags & SC_LOG_FLUSH)
   1080 	    ppplogchar(sc, c);
   1081 	return 0;
   1082     }
   1083 
   1084     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
   1085 	return 0;
   1086 
   1087     s = spltty();
   1088     if (sc->sc_flags & SC_ESCAPED) {
   1089 	sc->sc_flags &= ~SC_ESCAPED;
   1090 	c ^= PPP_TRANS;
   1091     } else if (c == PPP_ESCAPE) {
   1092 	sc->sc_flags |= SC_ESCAPED;
   1093 	splx(s);
   1094 	return 0;
   1095     }
   1096     splx(s);
   1097 
   1098     /*
   1099      * Initialize buffer on first octet received.
   1100      * First octet could be address or protocol (when compressing
   1101      * address/control).
   1102      * Second octet is control.
   1103      * Third octet is first or second (when compressing protocol)
   1104      * octet of protocol.
   1105      * Fourth octet is second octet of protocol.
   1106      */
   1107     if (sc->sc_ilen == 0) {
   1108 	/* reset the first input mbuf */
   1109 	if (sc->sc_m == NULL) {
   1110 	    pppgetm(sc);
   1111 	    if (sc->sc_m == NULL) {
   1112 		if (sc->sc_flags & SC_DEBUG)
   1113 		    printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
   1114 		goto flush;
   1115 	    }
   1116 	}
   1117 	m = sc->sc_m;
   1118 	m->m_len = 0;
   1119 	m->m_data = M_DATASTART(sc->sc_m);
   1120 	sc->sc_mc = m;
   1121 	sc->sc_mp = mtod(m, char *);
   1122 	sc->sc_fcs = PPP_INITFCS;
   1123 	if (c != PPP_ALLSTATIONS) {
   1124 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
   1125 		if (sc->sc_flags & SC_DEBUG)
   1126 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
   1127 		    sc->sc_if.if_xname, c);
   1128 		goto flush;
   1129 	    }
   1130 	    *sc->sc_mp++ = PPP_ALLSTATIONS;
   1131 	    *sc->sc_mp++ = PPP_UI;
   1132 	    sc->sc_ilen += 2;
   1133 	    m->m_len += 2;
   1134 	}
   1135     }
   1136     if (sc->sc_ilen == 1 && c != PPP_UI) {
   1137 	if (sc->sc_flags & SC_DEBUG)
   1138 	    printf("%s: missing UI (0x3), got 0x%x\n",
   1139 		sc->sc_if.if_xname, c);
   1140 	goto flush;
   1141     }
   1142     if (sc->sc_ilen == 2 && (c & 1) == 1) {
   1143 	/* a compressed protocol */
   1144 	*sc->sc_mp++ = 0;
   1145 	sc->sc_ilen++;
   1146 	sc->sc_mc->m_len++;
   1147     }
   1148     if (sc->sc_ilen == 3 && (c & 1) == 0) {
   1149 	if (sc->sc_flags & SC_DEBUG)
   1150 	    printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
   1151 		(sc->sc_mp[-1] << 8) + c);
   1152 	goto flush;
   1153     }
   1154 
   1155     /* packet beyond configured mru? */
   1156     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
   1157 	if (sc->sc_flags & SC_DEBUG)
   1158 	    printf("%s: packet too big\n", sc->sc_if.if_xname);
   1159 	goto flush;
   1160     }
   1161 
   1162     /* is this mbuf full? */
   1163     m = sc->sc_mc;
   1164     if (M_TRAILINGSPACE(m) <= 0) {
   1165 	if (m->m_next == NULL) {
   1166 	    pppgetm(sc);
   1167 	    if (m->m_next == NULL) {
   1168 		if (sc->sc_flags & SC_DEBUG)
   1169 		    printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
   1170 		goto flush;
   1171 	    }
   1172 	}
   1173 	sc->sc_mc = m = m->m_next;
   1174 	m->m_len = 0;
   1175 	m->m_data = M_DATASTART(m);
   1176 	sc->sc_mp = mtod(m, char *);
   1177     }
   1178 
   1179     ++m->m_len;
   1180     *sc->sc_mp++ = c;
   1181     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
   1182     return 0;
   1183 
   1184  flush:
   1185     if (!(sc->sc_flags & SC_FLUSH)) {
   1186 	s = spltty();
   1187 	sc->sc_if.if_ierrors++;
   1188 	sc->sc_stats.ppp_ierrors++;
   1189 	sc->sc_flags |= SC_FLUSH;
   1190 	splx(s);
   1191 	if (sc->sc_flags & SC_LOG_FLUSH)
   1192 	    ppplogchar(sc, c);
   1193     }
   1194     return 0;
   1195 }
   1196 
   1197 #define MAX_DUMP_BYTES	128
   1198 
   1199 static void
   1200 ppplogchar(sc, c)
   1201     struct ppp_softc *sc;
   1202     int c;
   1203 {
   1204     if (c >= 0)
   1205 	sc->sc_rawin[sc->sc_rawin_count++] = c;
   1206     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
   1207 	|| (c < 0 && sc->sc_rawin_count > 0)) {
   1208 	printf("%s input: ", sc->sc_if.if_xname);
   1209 	pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
   1210 	sc->sc_rawin_count = 0;
   1211     }
   1212 }
   1213 
   1214 static void
   1215 pppdumpb(b, l)
   1216     u_char *b;
   1217     int l;
   1218 {
   1219     char buf[3*MAX_DUMP_BYTES+4];
   1220     char *bp = buf;
   1221     static char digits[] = "0123456789abcdef";
   1222 
   1223     while (l--) {
   1224 	if (bp >= buf + sizeof(buf) - 3) {
   1225 	    *bp++ = '>';
   1226 	    break;
   1227 	}
   1228 	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
   1229 	*bp++ = digits[*b++ & 0xf];
   1230 	*bp++ = ' ';
   1231     }
   1232 
   1233     *bp = 0;
   1234     printf("%s\n", buf);
   1235 }
   1236 
   1237 static void
   1238 pppdumpframe(sc, m, xmit)
   1239 	struct ppp_softc *sc;
   1240 	struct mbuf* m;
   1241 	int xmit;
   1242 {
   1243 	int i,lcount,copycount,count;
   1244 	char lbuf[16];
   1245 	char *data;
   1246 
   1247 	if (m == NULL)
   1248 		return;
   1249 
   1250 	for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
   1251 		/* build a line of output */
   1252 		for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
   1253 			if (!count) {
   1254 				m = m->m_next;
   1255 				if (m == NULL)
   1256 					break;
   1257 				count = m->m_len;
   1258 				data  = mtod(m,char*);
   1259 			}
   1260 			copycount = (count > sizeof(lbuf)-lcount) ?
   1261 					sizeof(lbuf)-lcount : count;
   1262 			bcopy(data,&lbuf[lcount],copycount);
   1263 			data  += copycount;
   1264 			count -= copycount;
   1265 		}
   1266 
   1267 		/* output line (hex 1st, then ascii) */
   1268 		printf("%s %s:", sc->sc_if.if_xname,
   1269 		    xmit ? "output" : "input ");
   1270 		for(i=0;i<lcount;i++)
   1271 			printf("%02x ",(u_char)lbuf[i]);
   1272 		for(;i<sizeof(lbuf);i++)
   1273 			printf("   ");
   1274 		for(i=0;i<lcount;i++)
   1275 			printf("%c",(lbuf[i] >= 040 &&
   1276 			    lbuf[i] <= 0176) ? lbuf[i] : '.');
   1277 		printf("\n");
   1278 	}
   1279 }
   1280 
   1281 #endif	/* NPPP > 0 */
   1282