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