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