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