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