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