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