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