Home | History | Annotate | Line # | Download | only in net
ppp_tty.c revision 1.14.4.1
      1 /*	$NetBSD: ppp_tty.c,v 1.14.4.1 1998/12/11 04:53:06 kenh 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 #define VJC
     83 #define PPP_COMPRESS
     84 
     85 #include <sys/param.h>
     86 #include <sys/proc.h>
     87 #include <sys/mbuf.h>
     88 #include <sys/dkstat.h>
     89 #include <sys/socket.h>
     90 #include <sys/ioctl.h>
     91 #include <sys/file.h>
     92 #include <sys/tty.h>
     93 #include <sys/kernel.h>
     94 #include <sys/conf.h>
     95 #include <sys/vnode.h>
     96 #include <sys/systm.h>
     97 
     98 #include <net/if.h>
     99 #include <net/if_types.h>
    100 
    101 #ifdef VJC
    102 #include <netinet/in.h>
    103 #include <netinet/in_systm.h>
    104 #include <netinet/ip.h>
    105 #include <net/slcompress.h>
    106 #endif
    107 
    108 #ifdef PPP_FILTER
    109 #include <net/bpf.h>
    110 #endif
    111 #include <net/ppp_defs.h>
    112 #include <net/if_ppp.h>
    113 #include <net/if_pppvar.h>
    114 
    115 int	pppopen __P((dev_t dev, struct tty *tp));
    116 int	pppclose __P((struct tty *tp, int flag));
    117 int	pppread __P((struct tty *tp, struct uio *uio, int flag));
    118 int	pppwrite __P((struct tty *tp, struct uio *uio, int flag));
    119 int	ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag,
    120 		       struct proc *));
    121 int	pppinput __P((int c, struct tty *tp));
    122 int	pppstart __P((struct tty *tp));
    123 
    124 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
    125 static void	pppasyncstart __P((struct ppp_softc *));
    126 static void	pppasyncctlp __P((struct ppp_softc *));
    127 static void	pppasyncrelinq __P((struct ppp_softc *));
    128 static void	ppp_timeout __P((void *));
    129 static void	pppgetm __P((struct ppp_softc *sc));
    130 static void	pppdumpb __P((u_char *b, int l));
    131 static void	ppplogchar __P((struct ppp_softc *, int));
    132 
    133 /*
    134  * Some useful mbuf macros not in mbuf.h.
    135  */
    136 #define M_IS_CLUSTER(m)	((m)->m_flags & M_EXT)
    137 
    138 #define M_DATASTART(m)	\
    139 	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
    140 	    (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
    141 
    142 #define M_DATASIZE(m)	\
    143 	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
    144 	    (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
    145 
    146 /*
    147  * Does c need to be escaped?
    148  */
    149 #define ESCAPE_P(c)	(sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
    150 
    151 /*
    152  * Procedures for using an async tty interface for PPP.
    153  */
    154 
    155 /* This is a NetBSD-1.0 or later kernel. */
    156 #define CCOUNT(q)	((q)->c_cc)
    157 
    158 #define PPP_LOWAT	100	/* Process more output when < LOWAT on queue */
    159 #define	PPP_HIWAT	400	/* Don't start a new packet if HIWAT on que */
    160 
    161 /*
    162  * Line specific open routine for async tty devices.
    163  * Attach the given tty to the first available ppp unit.
    164  * Called from device open routine or ttioctl.
    165  */
    166 /* ARGSUSED */
    167 int
    168 pppopen(dev, tp)
    169     dev_t dev;
    170     register struct tty *tp;
    171 {
    172     struct proc *p = curproc;		/* XXX */
    173     register struct ppp_softc *sc;
    174     int error, s;
    175 
    176     if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    177 	return (error);
    178 
    179     s = spltty();
    180 
    181     if (tp->t_line == PPPDISC) {
    182 	sc = (struct ppp_softc *) tp->t_sc;
    183 	if (sc != NULL && sc->sc_devp == (void *) tp) {
    184 	    splx(s);
    185 	    return (0);
    186 	}
    187     }
    188 
    189     if ((sc = pppalloc(p->p_pid)) == NULL) {
    190 	splx(s);
    191 	return ENXIO;
    192     }
    193 
    194     if (sc->sc_relinq)
    195 	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
    196 
    197     sc->sc_ilen = 0;
    198     sc->sc_m = NULL;
    199     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
    200     sc->sc_asyncmap[0] = 0xffffffff;
    201     sc->sc_asyncmap[3] = 0x60000000;
    202     sc->sc_rasyncmap = 0;
    203     sc->sc_devp = (void *) tp;
    204     sc->sc_start = pppasyncstart;
    205     sc->sc_ctlp = pppasyncctlp;
    206     sc->sc_relinq = pppasyncrelinq;
    207     sc->sc_outm = NULL;
    208     pppgetm(sc);
    209 #ifdef _HAS_IF_ALLOC
    210     sc->sc_if->if_flags |= IFF_RUNNING;
    211     sc->sc_if->if_baudrate = tp->t_ospeed;
    212 #else
    213     sc->sc_if.if_flags |= IFF_RUNNING;
    214     sc->sc_if.if_baudrate = tp->t_ospeed;
    215 #endif
    216 
    217     tp->t_sc = (caddr_t) sc;
    218     ttyflush(tp, FREAD | FWRITE);
    219 
    220     splx(s);
    221     return (0);
    222 }
    223 
    224 /*
    225  * Line specific close routine, called from device close routine
    226  * and from ttioctl.
    227  * Detach the tty from the ppp unit.
    228  * Mimics part of ttyclose().
    229  */
    230 int
    231 pppclose(tp, flag)
    232     struct tty *tp;
    233     int flag;
    234 {
    235     register struct ppp_softc *sc;
    236     int s;
    237 
    238     s = spltty();
    239     ttyflush(tp, FREAD|FWRITE);
    240     tp->t_line = 0;
    241     sc = (struct ppp_softc *) tp->t_sc;
    242     if (sc != NULL) {
    243 	tp->t_sc = NULL;
    244 	if (tp == (struct tty *) sc->sc_devp) {
    245 	    pppasyncrelinq(sc);
    246 	    pppdealloc(sc);
    247 	}
    248     }
    249     splx(s);
    250     return 0;
    251 }
    252 
    253 /*
    254  * Relinquish the interface unit to another device.
    255  */
    256 static void
    257 pppasyncrelinq(sc)
    258     struct ppp_softc *sc;
    259 {
    260     int s;
    261 
    262     s = spltty();
    263     if (sc->sc_outm) {
    264 	m_freem(sc->sc_outm);
    265 	sc->sc_outm = NULL;
    266     }
    267     if (sc->sc_m) {
    268 	m_freem(sc->sc_m);
    269 	sc->sc_m = NULL;
    270     }
    271     if (sc->sc_flags & SC_TIMEOUT) {
    272 	untimeout(ppp_timeout, (void *) sc);
    273 	sc->sc_flags &= ~SC_TIMEOUT;
    274     }
    275     splx(s);
    276 }
    277 
    278 /*
    279  * Line specific (tty) read routine.
    280  */
    281 int
    282 pppread(tp, uio, flag)
    283     register struct tty *tp;
    284     struct uio *uio;
    285     int flag;
    286 {
    287     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
    288     struct mbuf *m, *m0;
    289     register int s;
    290     int error = 0;
    291 
    292     if (sc == NULL)
    293 	return 0;
    294     /*
    295      * Loop waiting for input, checking that nothing disasterous
    296      * happens in the meantime.
    297      */
    298     s = spltty();
    299     for (;;) {
    300 	if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
    301 	    splx(s);
    302 	    return 0;
    303 	}
    304 	if (sc->sc_inq.ifq_head != NULL)
    305 	    break;
    306 	if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
    307 	    && (tp->t_state & TS_ISOPEN)) {
    308 	    splx(s);
    309 	    return 0;		/* end of file */
    310 	}
    311 	if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
    312 	    splx(s);
    313 	    return (EWOULDBLOCK);
    314 	}
    315 	error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
    316 	if (error) {
    317 	    splx(s);
    318 	    return error;
    319 	}
    320     }
    321 
    322     /* Pull place-holder byte out of canonical queue */
    323     getc(&tp->t_canq);
    324 
    325     /* Get the packet from the input queue */
    326     IF_DEQUEUE(&sc->sc_inq, m0);
    327     splx(s);
    328 
    329     for (m = m0; m && uio->uio_resid; m = m->m_next)
    330 	if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
    331 	    break;
    332     m_freem(m0);
    333     return (error);
    334 }
    335 
    336 /*
    337  * Line specific (tty) write routine.
    338  */
    339 int
    340 pppwrite(tp, uio, flag)
    341     register struct tty *tp;
    342     struct uio *uio;
    343     int flag;
    344 {
    345     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
    346 #ifdef _HAS_IF_ALLOC
    347     struct ifnet *ifp = sc->sc_if;
    348 #else
    349     struct ifnet *ifp = &sc->sc_if;
    350 #endif
    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 > ifp->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 ((*ifp->if_output)(ifp, 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 #ifdef _HAS_IF_ALLOC
    553 	    sc->sc_if->if_lastchange = time;
    554 #else
    555 	    sc->sc_if.if_lastchange = time;
    556 #endif
    557 	}
    558 
    559 	for (;;) {
    560 	    start = mtod(m, u_char *);
    561 	    len = m->m_len;
    562 	    stop = start + len;
    563 	    while (len > 0) {
    564 		/*
    565 		 * Find out how many bytes in the string we can
    566 		 * handle without doing something special.
    567 		 */
    568 		for (cp = start; cp < stop; cp++)
    569 		    if (ESCAPE_P(*cp))
    570 			break;
    571 		n = cp - start;
    572 		if (n) {
    573 		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
    574 		    ndone = n - b_to_q(start, n, &tp->t_outq);
    575 		    len -= ndone;
    576 		    start += ndone;
    577 		    sc->sc_stats.ppp_obytes += ndone;
    578 
    579 		    if (ndone < n)
    580 			break;	/* packet doesn't fit */
    581 		}
    582 		/*
    583 		 * If there are characters left in the mbuf,
    584 		 * the first one must be special.
    585 		 * Put it out in a different form.
    586 		 */
    587 		if (len) {
    588 		    s = spltty();
    589 		    if (putc(PPP_ESCAPE, &tp->t_outq)) {
    590 			splx(s);
    591 			break;
    592 		    }
    593 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
    594 			(void) unputc(&tp->t_outq);
    595 			splx(s);
    596 			break;
    597 		    }
    598 		    splx(s);
    599 		    sc->sc_stats.ppp_obytes += 2;
    600 		    start++;
    601 		    len--;
    602 		}
    603 	    }
    604 
    605 	    /*
    606 	     * If we didn't empty this mbuf, remember where we're up to.
    607 	     * If we emptied the last mbuf, try to add the FCS and closing
    608 	     * flag, and if we can't, leave sc_outm pointing to m, but with
    609 	     * m->m_len == 0, to remind us to output the FCS and flag later.
    610 	     */
    611 	    done = len == 0;
    612 	    if (done && m->m_next == NULL) {
    613 		u_char *p, *q;
    614 		int c;
    615 		u_char endseq[8];
    616 
    617 		/*
    618 		 * We may have to escape the bytes in the FCS.
    619 		 */
    620 		p = endseq;
    621 		c = ~sc->sc_outfcs & 0xFF;
    622 		if (ESCAPE_P(c)) {
    623 		    *p++ = PPP_ESCAPE;
    624 		    *p++ = c ^ PPP_TRANS;
    625 		} else
    626 		    *p++ = c;
    627 		c = (~sc->sc_outfcs >> 8) & 0xFF;
    628 		if (ESCAPE_P(c)) {
    629 		    *p++ = PPP_ESCAPE;
    630 		    *p++ = c ^ PPP_TRANS;
    631 		} else
    632 		    *p++ = c;
    633 		*p++ = PPP_FLAG;
    634 
    635 		/*
    636 		 * Try to output the FCS and flag.  If the bytes
    637 		 * don't all fit, back out.
    638 		 */
    639 		s = spltty();
    640 		for (q = endseq; q < p; ++q)
    641 		    if (putc(*q, &tp->t_outq)) {
    642 			done = 0;
    643 			for (; q > endseq; --q)
    644 			    unputc(&tp->t_outq);
    645 			break;
    646 		    }
    647 		splx(s);
    648 		if (done)
    649 		    sc->sc_stats.ppp_obytes += q - endseq;
    650 	    }
    651 
    652 	    if (!done) {
    653 		/* remember where we got to */
    654 		m->m_data = start;
    655 		m->m_len = len;
    656 		break;
    657 	    }
    658 
    659 	    /* Finished with this mbuf; free it and move on. */
    660 	    MFREE(m, m2);
    661 	    m = m2;
    662 	    if (m == NULL) {
    663 		/* Finished a packet */
    664 		break;
    665 	    }
    666 	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
    667 	}
    668 
    669 	/*
    670 	 * If m == NULL, we have finished a packet.
    671 	 * If m != NULL, we've either done as much work this time
    672 	 * as we need to, or else we've filled up the output queue.
    673 	 */
    674 	sc->sc_outm = m;
    675 	if (m)
    676 	    break;
    677     }
    678 
    679     /* Call pppstart to start output again if necessary. */
    680     s = spltty();
    681     pppstart(tp);
    682 
    683     /*
    684      * This timeout is needed for operation on a pseudo-tty,
    685      * because the pty code doesn't call pppstart after it has
    686      * drained the t_outq.
    687      */
    688     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
    689 	timeout(ppp_timeout, (void *) sc, 1);
    690 	sc->sc_flags |= SC_TIMEOUT;
    691     }
    692 
    693     splx(s);
    694 }
    695 
    696 /*
    697  * This gets called when a received packet is placed on
    698  * the inq, at splsoftnet.
    699  */
    700 static void
    701 pppasyncctlp(sc)
    702     struct ppp_softc *sc;
    703 {
    704     struct tty *tp;
    705     int s;
    706 
    707     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
    708     s = spltty();
    709     tp = (struct tty *) sc->sc_devp;
    710     putc(0, &tp->t_canq);
    711     ttwakeup(tp);
    712     splx(s);
    713 }
    714 
    715 /*
    716  * Start output on async tty interface.  If the transmit queue
    717  * has drained sufficiently, arrange for pppasyncstart to be
    718  * called later at splsoftnet.
    719  * Called at spltty or higher.
    720  */
    721 int
    722 pppstart(tp)
    723     register struct tty *tp;
    724 {
    725     register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
    726 
    727     /*
    728      * If there is stuff in the output queue, send it now.
    729      * We are being called in lieu of ttstart and must do what it would.
    730      */
    731     if (tp->t_oproc != NULL)
    732 	(*tp->t_oproc)(tp);
    733 
    734     /*
    735      * If the transmit queue has drained and the tty has not hung up
    736      * or been disconnected from the ppp unit, then tell if_ppp.c that
    737      * we need more output.
    738      */
    739     if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
    740 	&& ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
    741 	return 0;
    742     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
    743 	&& sc != NULL && tp == (struct tty *) sc->sc_devp) {
    744 	ppp_restart(sc);
    745     }
    746 
    747     return 0;
    748 }
    749 
    750 /*
    751  * Timeout routine - try to start some more output.
    752  */
    753 static void
    754 ppp_timeout(x)
    755     void *x;
    756 {
    757     struct ppp_softc *sc = (struct ppp_softc *) x;
    758     struct tty *tp = (struct tty *) sc->sc_devp;
    759     int s;
    760 
    761     s = spltty();
    762     sc->sc_flags &= ~SC_TIMEOUT;
    763     pppstart(tp);
    764     splx(s);
    765 }
    766 
    767 /*
    768  * Allocate enough mbuf to handle current MRU.
    769  */
    770 static void
    771 pppgetm(sc)
    772     register struct ppp_softc *sc;
    773 {
    774     struct mbuf *m, **mp;
    775     int len;
    776 
    777     mp = &sc->sc_m;
    778     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
    779 	if ((m = *mp) == NULL) {
    780 	    MGETHDR(m, M_DONTWAIT, MT_DATA);
    781 	    if (m == NULL)
    782 		break;
    783 	    *mp = m;
    784 	    MCLGET(m, M_DONTWAIT);
    785 	}
    786 	len -= M_DATASIZE(m);
    787 	mp = &m->m_next;
    788     }
    789 }
    790 
    791 /*
    792  * tty interface receiver interrupt.
    793  */
    794 static unsigned paritytab[8] = {
    795     0x96696996, 0x69969669, 0x69969669, 0x96696996,
    796     0x69969669, 0x96696996, 0x96696996, 0x69969669
    797 };
    798 
    799 int
    800 pppinput(c, tp)
    801     int c;
    802     register struct tty *tp;
    803 {
    804     register struct ppp_softc *sc;
    805     register struct ifnet *ifp;
    806     struct mbuf *m;
    807     int ilen, s;
    808 
    809     sc = (struct ppp_softc *) tp->t_sc;
    810     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
    811 	return 0;
    812 
    813 #ifdef _HAS_IF_ALLOC
    814     ifp = sc->sc_if;
    815 #else
    816     ifp = &sc->sc_if;
    817 #endif
    818 
    819     ++tk_nin;
    820     ++sc->sc_stats.ppp_ibytes;
    821 
    822     if (c & TTY_FE) {
    823 	/* framing error or overrun on this char - abort packet */
    824 	if (sc->sc_flags & SC_DEBUG)
    825 	    printf("%s: bad char %x\n", ifp->if_xname, c);
    826 	goto flush;
    827     }
    828 
    829     c &= 0xff;
    830 
    831     /*
    832      * Handle software flow control of output.
    833      */
    834     if (tp->t_iflag & IXON) {
    835 	if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
    836 	    if ((tp->t_state & TS_TTSTOP) == 0) {
    837 		tp->t_state |= TS_TTSTOP;
    838 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
    839 	    }
    840 	    return 0;
    841 	}
    842 	if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
    843 	    tp->t_state &= ~TS_TTSTOP;
    844 	    if (tp->t_oproc != NULL)
    845 		(*tp->t_oproc)(tp);
    846 	    return 0;
    847 	}
    848     }
    849 
    850     s = spltty();
    851     if (c & 0x80)
    852 	sc->sc_flags |= SC_RCV_B7_1;
    853     else
    854 	sc->sc_flags |= SC_RCV_B7_0;
    855     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
    856 	sc->sc_flags |= SC_RCV_ODDP;
    857     else
    858 	sc->sc_flags |= SC_RCV_EVNP;
    859     splx(s);
    860 
    861     if (sc->sc_flags & SC_LOG_RAWIN)
    862 	ppplogchar(sc, c);
    863 
    864     if (c == PPP_FLAG) {
    865 	ilen = sc->sc_ilen;
    866 	sc->sc_ilen = 0;
    867 
    868 	if (sc->sc_rawin_count > 0)
    869 	    ppplogchar(sc, -1);
    870 
    871 	/*
    872 	 * If SC_ESCAPED is set, then we've seen the packet
    873 	 * abort sequence "}~".
    874 	 */
    875 	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
    876 	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
    877 	    s = spltty();
    878 	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
    879 	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
    880 		if (sc->sc_flags & SC_DEBUG)
    881 		    printf("%s: bad fcs %x\n", ifp->if_xname,
    882 			sc->sc_fcs);
    883 		ifp->if_ierrors++;
    884 		sc->sc_stats.ppp_ierrors++;
    885 	    } else
    886 		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
    887 	    splx(s);
    888 	    return 0;
    889 	}
    890 
    891 	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
    892 	    if (ilen) {
    893 		if (sc->sc_flags & SC_DEBUG)
    894 		    printf("%s: too short (%d)\n", ifp->if_xname, ilen);
    895 		s = spltty();
    896 		ifp->if_ierrors++;
    897 		sc->sc_stats.ppp_ierrors++;
    898 		sc->sc_flags |= SC_PKTLOST;
    899 		splx(s);
    900 	    }
    901 	    return 0;
    902 	}
    903 
    904 	/*
    905 	 * Remove FCS trailer.  Somewhat painful...
    906 	 */
    907 	ilen -= 2;
    908 	if (--sc->sc_mc->m_len == 0) {
    909 	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
    910 		;
    911 	    sc->sc_mc = m;
    912 	}
    913 	sc->sc_mc->m_len--;
    914 
    915 	/* excise this mbuf chain */
    916 	m = sc->sc_m;
    917 	sc->sc_m = sc->sc_mc->m_next;
    918 	sc->sc_mc->m_next = NULL;
    919 
    920 	ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
    921 	if (sc->sc_flags & SC_PKTLOST) {
    922 	    s = spltty();
    923 	    sc->sc_flags &= ~SC_PKTLOST;
    924 	    splx(s);
    925 	}
    926 
    927 	pppgetm(sc);
    928 	return 0;
    929     }
    930 
    931     if (sc->sc_flags & SC_FLUSH) {
    932 	if (sc->sc_flags & SC_LOG_FLUSH)
    933 	    ppplogchar(sc, c);
    934 	return 0;
    935     }
    936 
    937     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
    938 	return 0;
    939 
    940     s = spltty();
    941     if (sc->sc_flags & SC_ESCAPED) {
    942 	sc->sc_flags &= ~SC_ESCAPED;
    943 	c ^= PPP_TRANS;
    944     } else if (c == PPP_ESCAPE) {
    945 	sc->sc_flags |= SC_ESCAPED;
    946 	splx(s);
    947 	return 0;
    948     }
    949     splx(s);
    950 
    951     /*
    952      * Initialize buffer on first octet received.
    953      * First octet could be address or protocol (when compressing
    954      * address/control).
    955      * Second octet is control.
    956      * Third octet is first or second (when compressing protocol)
    957      * octet of protocol.
    958      * Fourth octet is second octet of protocol.
    959      */
    960     if (sc->sc_ilen == 0) {
    961 	/* reset the first input mbuf */
    962 	if (sc->sc_m == NULL) {
    963 	    pppgetm(sc);
    964 	    if (sc->sc_m == NULL) {
    965 		if (sc->sc_flags & SC_DEBUG)
    966 		    printf("%s: no input mbufs!\n", ifp->if_xname);
    967 		goto flush;
    968 	    }
    969 	}
    970 	m = sc->sc_m;
    971 	m->m_len = 0;
    972 	m->m_data = M_DATASTART(sc->sc_m);
    973 	sc->sc_mc = m;
    974 	sc->sc_mp = mtod(m, char *);
    975 	sc->sc_fcs = PPP_INITFCS;
    976 	if (c != PPP_ALLSTATIONS) {
    977 	    if (sc->sc_flags & SC_REJ_COMP_AC) {
    978 		if (sc->sc_flags & SC_DEBUG)
    979 		    printf("%s: garbage received: 0x%x (need 0xFF)\n",
    980 		    ifp->if_xname, c);
    981 		goto flush;
    982 	    }
    983 	    *sc->sc_mp++ = PPP_ALLSTATIONS;
    984 	    *sc->sc_mp++ = PPP_UI;
    985 	    sc->sc_ilen += 2;
    986 	    m->m_len += 2;
    987 	}
    988     }
    989     if (sc->sc_ilen == 1 && c != PPP_UI) {
    990 	if (sc->sc_flags & SC_DEBUG)
    991 	    printf("%s: missing UI (0x3), got 0x%x\n",
    992 		ifp->if_xname, c);
    993 	goto flush;
    994     }
    995     if (sc->sc_ilen == 2 && (c & 1) == 1) {
    996 	/* a compressed protocol */
    997 	*sc->sc_mp++ = 0;
    998 	sc->sc_ilen++;
    999 	sc->sc_mc->m_len++;
   1000     }
   1001     if (sc->sc_ilen == 3 && (c & 1) == 0) {
   1002 	if (sc->sc_flags & SC_DEBUG)
   1003 	    printf("%s: bad protocol %x\n", ifp->if_xname,
   1004 		(sc->sc_mp[-1] << 8) + c);
   1005 	goto flush;
   1006     }
   1007 
   1008     /* packet beyond configured mru? */
   1009     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
   1010 	if (sc->sc_flags & SC_DEBUG)
   1011 	    printf("%s: packet too big\n", ifp->if_xname);
   1012 	goto flush;
   1013     }
   1014 
   1015     /* is this mbuf full? */
   1016     m = sc->sc_mc;
   1017     if (M_TRAILINGSPACE(m) <= 0) {
   1018 	if (m->m_next == NULL) {
   1019 	    pppgetm(sc);
   1020 	    if (m->m_next == NULL) {
   1021 		if (sc->sc_flags & SC_DEBUG)
   1022 		    printf("%s: too few input mbufs!\n", ifp->if_xname);
   1023 		goto flush;
   1024 	    }
   1025 	}
   1026 	sc->sc_mc = m = m->m_next;
   1027 	m->m_len = 0;
   1028 	m->m_data = M_DATASTART(m);
   1029 	sc->sc_mp = mtod(m, char *);
   1030     }
   1031 
   1032     ++m->m_len;
   1033     *sc->sc_mp++ = c;
   1034     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
   1035     return 0;
   1036 
   1037  flush:
   1038     if (!(sc->sc_flags & SC_FLUSH)) {
   1039 	s = spltty();
   1040 	ifp->if_ierrors++;
   1041 	sc->sc_stats.ppp_ierrors++;
   1042 	sc->sc_flags |= SC_FLUSH;
   1043 	splx(s);
   1044 	if (sc->sc_flags & SC_LOG_FLUSH)
   1045 	    ppplogchar(sc, c);
   1046     }
   1047     return 0;
   1048 }
   1049 
   1050 #define MAX_DUMP_BYTES	128
   1051 
   1052 static void
   1053 ppplogchar(sc, c)
   1054     struct ppp_softc *sc;
   1055     int c;
   1056 {
   1057     if (c >= 0)
   1058 	sc->sc_rawin[sc->sc_rawin_count++] = c;
   1059     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
   1060 	|| (c < 0 && sc->sc_rawin_count > 0)) {
   1061 #ifdef _HAS_IF_ALLOC
   1062 	printf("%s input: ", sc->sc_if->if_xname);
   1063 #else
   1064 	printf("%s input: ", sc->sc_if.if_xname);
   1065 #endif
   1066 	pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
   1067 	sc->sc_rawin_count = 0;
   1068     }
   1069 }
   1070 
   1071 static void
   1072 pppdumpb(b, l)
   1073     u_char *b;
   1074     int l;
   1075 {
   1076     char buf[3*MAX_DUMP_BYTES+4];
   1077     char *bp = buf;
   1078     static char digits[] = "0123456789abcdef";
   1079 
   1080     while (l--) {
   1081 	if (bp >= buf + sizeof(buf) - 3) {
   1082 	    *bp++ = '>';
   1083 	    break;
   1084 	}
   1085 	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
   1086 	*bp++ = digits[*b++ & 0xf];
   1087 	*bp++ = ' ';
   1088     }
   1089 
   1090     *bp = 0;
   1091     printf("%s\n", buf);
   1092 }
   1093 
   1094 #endif	/* NPPP > 0 */
   1095