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