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