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