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