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