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