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