Home | History | Annotate | Line # | Download | only in net
if_ppp.c revision 1.1
      1 /*
      2  * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
      3  *
      4  * Copyright (c) 1989 Carnegie Mellon University.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms are permitted
      8  * provided that the above copyright notice and this paragraph are
      9  * duplicated in all such forms and that any documentation,
     10  * advertising materials, and other materials related to such
     11  * distribution and use acknowledge that the software was developed
     12  * by Carnegie Mellon University.  The name of the
     13  * University may not be used to endorse or promote products derived
     14  * from this software without specific prior written permission.
     15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     18  *
     19  * Drew D. Perkins
     20  * Carnegie Mellon University
     21  * 4910 Forbes Ave.
     22  * Pittsburgh, PA 15213
     23  * (412) 268-8576
     24  * ddp (at) andrew.cmu.edu
     25  *
     26  * Based on:
     27  *	@(#)if_sl.c	7.6.1.2 (Berkeley) 2/15/89
     28  *
     29  * Copyright (c) 1987 Regents of the University of California.
     30  * All rights reserved.
     31  *
     32  * Redistribution and use in source and binary forms are permitted
     33  * provided that the above copyright notice and this paragraph are
     34  * duplicated in all such forms and that any documentation,
     35  * advertising materials, and other materials related to such
     36  * distribution and use acknowledge that the software was developed
     37  * by the University of California, Berkeley.  The name of the
     38  * University may not be used to endorse or promote products derived
     39  * from this software without specific prior written permission.
     40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     41  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     42  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     43  *
     44  * Serial Line interface
     45  *
     46  * Rick Adams
     47  * Center for Seismic Studies
     48  * 1300 N 17th Street, Suite 1450
     49  * Arlington, Virginia 22209
     50  * (703)276-7900
     51  * rick (at) seismo.ARPA
     52  * seismo!rick
     53  *
     54  * Pounded on heavily by Chris Torek (chris (at) mimsy.umd.edu, umcp-cs!chris).
     55  * Converted to 4.3BSD Beta by Chris Torek.
     56  * Other changes made at Berkeley, based in part on code by Kirk Smith.
     57  *
     58  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad (at) cayman.com)
     59  * Added VJ tcp header compression; more unified ioctls
     60  *
     61  * Extensively modified by Paul Mackerras (paulus (at) cs.anu.edu.au).
     62  * Cleaned up a lot of the mbuf-related code to fix bugs that
     63  * caused system crashes and packet corruption.  Changed pppstart
     64  * so that it doesn't just give up with a collision if the whole
     65  * packet doesn't fit in the output ring buffer.
     66  *
     67  *	from: if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp
     68  *	$Id: if_ppp.c,v 1.1 1993/08/14 06:38:37 deraadt Exp $
     69  */
     70 
     71 #include "ppp.h"
     72 #if NPPP > 0
     73 
     74 #define VJC
     75 
     76 #include "param.h"
     77 #include "proc.h"
     78 #include "mbuf.h"
     79 #include "buf.h"
     80 #include "dkstat.h"
     81 #include "socket.h"
     82 #include "ioctl.h"
     83 #include "file.h"
     84 #include "tty.h"
     85 #include "kernel.h"
     86 #include "conf.h"
     87 
     88 #include "if.h"
     89 #include "if_types.h"
     90 #include "netisr.h"
     91 #include "route.h"
     92 #if INET
     93 #include "../netinet/in.h"
     94 #include "../netinet/in_systm.h"
     95 #include "../netinet/in_var.h"
     96 #include "../netinet/ip.h"
     97 #endif
     98 
     99 /*
    100  * Here we try to tell whether we are in a 386BSD kernel, or
    101  * in a NetBSD/Net-2/4.3-Reno kernel.
    102  */
    103 #ifndef	RB_LEN
    104 /* NetBSD, 4.3-Reno or similar */
    105 #define CCOUNT(q)	((q)->c_cc)
    106 
    107 #else
    108 /* 386BSD, Jolitz-style ring buffers */
    109 #define t_outq		t_out
    110 #define t_rawq		t_raw
    111 #define t_canq		t_can
    112 #define CCOUNT(q)	(RB_LEN(q))
    113 #endif
    114 
    115 #ifdef VJC
    116 #include "slcompress.h"
    117 #define HDROFF	MAX_HDR
    118 /* HDROFF should really be 128, but other parts of the system will
    119    panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */
    120 
    121 #else
    122 #define	HDROFF	(0)
    123 #endif
    124 
    125 #include "if_ppp.h"
    126 #include "machine/mtpr.h"
    127 
    128 struct ppp_softc ppp_softc[NPPP];
    129 int ppp_async_out_debug = 0;
    130 int ppp_async_in_debug = 0;
    131 int ppp_debug = 0;
    132 
    133 void	pppattach __P((void));
    134 int	pppopen __P((dev_t dev, struct tty *tp));
    135 void	pppclose __P((struct tty *tp, int flag));
    136 int	pppread __P((struct tty *tp, struct uio *uio, int flag));
    137 int	pppwrite __P((struct tty *tp, struct uio *uio, int flag));
    138 int	ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag));
    139 int	pppoutput __P((struct ifnet *ifp, struct mbuf *m0,
    140 		       struct sockaddr *dst));
    141 void	pppstart __P((struct tty *tp));
    142 void	pppinput __P((int c, struct tty *tp));
    143 int	pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data));
    144 
    145 static u_short	pppfcs __P((u_short fcs, u_char *cp, int len));
    146 static int	pppinit __P((struct ppp_softc *sc));
    147 static struct	mbuf *ppp_btom __P((struct ppp_softc *sc));
    148 static void	pppdumpm __P((struct mbuf *m0, int pktlen));
    149 static void	pppdumpb __P((u_char *b, int l));
    150 
    151 /*
    152  * Some useful mbuf macros not in mbuf.h.
    153  */
    154 #define M_DATASTART(m)	\
    155 	((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \
    156 	    (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
    157 
    158 #define M_DATASIZE(m)	\
    159 	((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \
    160 	    (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
    161 
    162 /*
    163  * Called from boot code to establish ppp interfaces.
    164  */
    165 void
    166 pppattach()
    167 {
    168     register struct ppp_softc *sc;
    169     register int i = 0;
    170 
    171     for (sc = ppp_softc; i < NPPP; sc++) {
    172 	sc->sc_if.if_name = "ppp";
    173 	sc->sc_if.if_unit = i++;
    174 	sc->sc_if.if_mtu = PPP_MTU;
    175 	sc->sc_if.if_flags = IFF_POINTOPOINT;
    176 	sc->sc_if.if_type = IFT_PPP;
    177 	sc->sc_if.if_hdrlen = sizeof(struct ppp_header);
    178 	sc->sc_if.if_ioctl = pppioctl;
    179 	sc->sc_if.if_output = pppoutput;
    180 	sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
    181 	sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
    182 	if_attach(&sc->sc_if);
    183     }
    184 }
    185 
    186 /*
    187  * Line specific open routine.
    188  * Attach the given tty to the first available ppp unit.
    189  */
    190 /* ARGSUSED */
    191 int
    192 pppopen(dev, tp)
    193     dev_t dev;
    194     register struct tty *tp;
    195 {
    196     struct proc *p = curproc;		/* XXX */
    197     register struct ppp_softc *sc;
    198     register int nppp;
    199     int error, s;
    200 
    201     if (error = suser(p->p_ucred, &p->p_acflag))
    202 	return (error);
    203 
    204     if (tp->t_line == PPPDISC)
    205 	return (0);
    206 
    207     for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
    208 	if (sc->sc_ttyp == NULL) {
    209 	    sc->sc_flags = 0;
    210 	    sc->sc_ilen = 0;
    211 	    sc->sc_asyncmap = 0xffffffff;
    212 #ifdef VJC
    213 	    sl_compress_init(&sc->sc_comp);
    214 #endif
    215 	    if (pppinit(sc) == 0) {
    216 		sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
    217 		return (ENOBUFS);
    218 	    }
    219 	    tp->t_sc = (caddr_t)sc;
    220 	    sc->sc_ttyp = tp;
    221 	    sc->sc_outm = NULL;
    222 	    ttyflush(tp, FREAD | FWRITE);
    223 	    sc->sc_if.if_flags |= IFF_RUNNING;
    224 
    225 #ifdef	PPP_OUTQ_SIZE
    226 	    /* N.B. this code is designed *only* for use in NetBSD */
    227 	    s = spltty();
    228 	    /* get rid of the default outq clist buffer */
    229 	    clfree(&tp->t_outq);
    230 	    /* and get a new one, without quoting support, much larger */
    231 	    clalloc(&tp->t_outq, PPP_OUTQ_SIZE, 0);
    232 	    splx (s);
    233 #endif	/* PPP_OUTQ_SIZE */
    234 
    235 	    return (0);
    236 	}
    237 
    238     return (ENXIO);
    239 }
    240 
    241 /*
    242  * Line specific close routine.
    243  * Detach the tty from the ppp unit.
    244  * Mimics part of ttyclose().
    245  */
    246 void
    247 pppclose(tp, flag)
    248     struct tty *tp;
    249     int flag;
    250 {
    251     register struct ppp_softc *sc;
    252     struct mbuf *m;
    253     int s;
    254 
    255     ttywflush(tp);
    256     s = splimp();		/* paranoid; splnet probably ok */
    257     tp->t_line = 0;
    258     sc = (struct ppp_softc *)tp->t_sc;
    259     if (sc != NULL) {
    260 	if_down(&sc->sc_if);
    261 	sc->sc_ttyp = NULL;
    262 	tp->t_sc = NULL;
    263 	m_freem(sc->sc_outm);
    264 	sc->sc_outm = NULL;
    265 	m_freem(sc->sc_m);
    266 	sc->sc_m = NULL;
    267 	for (;;) {
    268 	    IF_DEQUEUE(&sc->sc_inq, m);
    269 	    if (m == NULL)
    270 		break;
    271 	    m_freem(m);
    272 	}
    273 	sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
    274 
    275 #ifdef	PPP_OUTQ_SIZE
    276 	/* reinstall default clist-buffer for outq
    277 	   XXXX should really remember old value and restore that!! */
    278 	clfree(&tp->t_outq);
    279 	clalloc(&tp->t_outq, 1024, 0);
    280 #endif	/* PPP_OUTQ_SIZE */
    281 
    282     }
    283     splx(s);
    284 }
    285 
    286 /*
    287  * Line specific (tty) read routine.
    288  */
    289 int
    290 pppread(tp, uio, flag)
    291     register struct tty *tp;
    292     struct uio *uio;
    293     int flag;
    294 {
    295     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
    296     struct mbuf *m, *m0;
    297     register int s;
    298     int error;
    299 
    300     if ((tp->t_state & TS_CARR_ON)==0)
    301 	return (EIO);
    302     s = splimp();
    303     while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) {
    304 	if (tp->t_state & TS_ASYNC) {
    305 	    splx(s);
    306 	    return (EWOULDBLOCK);
    307 	}
    308 	error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
    309 	if (error)
    310 	    return error;
    311     }
    312     if (tp->t_line != PPPDISC) {
    313 	splx(s);
    314 	return (-1);
    315     }
    316 
    317     /* Pull place-holder byte out of canonical queue */
    318     getc(&tp->t_canq);
    319 
    320     /* Get the packet from the input queue */
    321     IF_DEQUEUE(&sc->sc_inq, m0);
    322     splx(s);
    323 
    324     for (m = m0; m && uio->uio_resid; m = m->m_next)
    325 	if (error = uiomove(mtod(m, u_char *), m->m_len, uio))
    326 	    break;
    327     m_freem(m0);
    328     return (error);
    329 }
    330 
    331 /*
    332  * Line specific (tty) write routine.
    333  */
    334 int
    335 pppwrite(tp, uio, flag)
    336     register struct tty *tp;
    337     struct uio *uio;
    338     int flag;
    339 {
    340     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
    341     struct mbuf *m, *m0, **mp;
    342     struct sockaddr dst;
    343     struct ppp_header *ph1, *ph2;
    344     int len, error;
    345 
    346     if ((tp->t_state & TS_CARR_ON)==0)
    347 	return (EIO);
    348     if (tp->t_line != PPPDISC)
    349 	return (EINVAL);
    350     if (uio->uio_resid > sc->sc_if.if_mtu + sizeof (struct ppp_header) ||
    351 	uio->uio_resid < sizeof (struct ppp_header))
    352 	return (EMSGSIZE);
    353     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
    354 	MGET(m, M_WAIT, MT_DATA);
    355 	if ((*mp = m) == NULL) {
    356 	    m_freem(m0);
    357 	    return (ENOBUFS);
    358 	}
    359 	if (uio->uio_resid >= MCLBYTES / 2)
    360 	    MCLGET(m, M_DONTWAIT);
    361 	len = MIN(M_TRAILINGSPACE(m), uio->uio_resid);
    362 	if (error = uiomove(mtod(m, u_char *), len, uio)) {
    363 	    m_freem(m0);
    364 	    return (error);
    365 	}
    366 	m->m_len = len;
    367     }
    368     dst.sa_family = AF_UNSPEC;
    369     ph1 = (struct ppp_header *) &dst.sa_data;
    370     ph2 = mtod(m0, struct ppp_header *);
    371     *ph1 = *ph2;
    372     m0->m_data += sizeof (struct ppp_header);
    373     m0->m_len -= sizeof (struct ppp_header);
    374     return (pppoutput(&sc->sc_if, m0, &dst));
    375 }
    376 
    377 /*
    378  * Line specific (tty) ioctl routine.
    379  * Provide a way to get the ppp unit number.
    380  * This discipline requires that tty device drivers call
    381  * the line specific l_ioctl routine from their ioctl routines.
    382  */
    383 /* ARGSUSED */
    384 int
    385 ppptioctl(tp, cmd, data, flag)
    386     struct tty *tp;
    387     caddr_t data;
    388     int cmd, flag;
    389 {
    390     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
    391     struct proc *p = curproc;		/* XXX */
    392     int s, error;
    393 
    394     switch (cmd) {
    395 #if 0			/* this is handled (properly) by ttioctl */
    396     case TIOCGETD:
    397 	*(int *)data = sc->sc_if.if_unit;
    398 	break;
    399 #endif
    400     case FIONREAD:
    401 	*(int *)data = sc->sc_inq.ifq_len;
    402 	break;
    403 
    404     case PPPIOCGUNIT:
    405 	*(int *)data = sc->sc_if.if_unit;
    406 	break;
    407 
    408     case PPPIOCGFLAGS:
    409 	*(u_int *)data = sc->sc_flags;
    410 	break;
    411 
    412     case PPPIOCSFLAGS:
    413 	if (error = suser(p->p_ucred, &p->p_acflag))
    414 	    return (error);
    415 #define	SC_MASK	0xffff
    416 	s = splimp();
    417 	sc->sc_flags =
    418 	    (sc->sc_flags & ~SC_MASK) | ((*(int *)data) & SC_MASK);
    419 	splx(s);
    420 	break;
    421 
    422     case PPPIOCSASYNCMAP:
    423 	if (error = suser(p->p_ucred, &p->p_acflag))
    424 	    return (error);
    425 	sc->sc_asyncmap = *(u_int *)data;
    426 	break;
    427 
    428     case PPPIOCGASYNCMAP:
    429 	*(u_int *)data = sc->sc_asyncmap;
    430 	break;
    431 
    432     default:
    433 	return (-1);
    434     }
    435     return (0);
    436 }
    437 
    438 /*
    439  * FCS lookup table as calculated by genfcstab.
    440  */
    441 static u_short fcstab[256] = {
    442 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
    443 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
    444 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
    445 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
    446 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
    447 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
    448 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
    449 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
    450 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
    451 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
    452 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
    453 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
    454 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
    455 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
    456 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
    457 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
    458 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
    459 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
    460 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
    461 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
    462 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
    463 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
    464 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
    465 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
    466 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
    467 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
    468 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
    469 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
    470 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
    471 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
    472 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
    473 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
    474 };
    475 
    476 /*
    477  * Calculate a new FCS given the current FCS and the new data.
    478  */
    479 static u_short
    480 pppfcs(fcs, cp, len)
    481     register u_short fcs;
    482     register u_char *cp;
    483     register int len;
    484 {
    485     while (len--)
    486 	fcs = PPP_FCS(fcs, *cp++);
    487     return (fcs);
    488 }
    489 
    490 /*
    491  * Queue a packet.  Start transmission if not active.
    492  * Packet is placed in Information field of PPP frame.
    493  */
    494 int
    495 pppoutput(ifp, m0, dst)
    496     struct ifnet *ifp;
    497     struct mbuf *m0;
    498     struct sockaddr *dst;
    499 {
    500     register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
    501     struct mbuf *m, *m1;
    502     struct ppp_header *ph;
    503     u_short protocol, fcs;
    504     u_char address, control, *cp;
    505     int s, error, compac, compprot;
    506 
    507     if (sc->sc_ttyp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
    508 	|| (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
    509 	error = ENETDOWN;	/* sort of */
    510 	goto bad;
    511     }
    512     if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
    513 	error = EHOSTUNREACH;
    514 	goto bad;
    515     }
    516 
    517     /*
    518      * Compute PPP header.
    519      */
    520     address = PPP_ALLSTATIONS;
    521     control = PPP_UI;
    522     switch (dst->sa_family) {
    523 #ifdef INET
    524     case AF_INET:
    525 	protocol = PPP_IP;
    526 #ifdef VJC
    527 	if (sc->sc_flags & SC_COMP_TCP) {
    528 	    register struct ip *ip;
    529 
    530 	    if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
    531 		int type = sl_compress_tcp(m0, ip, &sc->sc_comp, 1);
    532 		switch (type) {
    533 		case TYPE_UNCOMPRESSED_TCP:
    534 		    protocol = PPP_VJC_UNCOMP;
    535 		    break;
    536 		case TYPE_COMPRESSED_TCP:
    537 		    protocol = PPP_VJC_COMP;
    538 		    break;
    539 		}
    540 	    }
    541 	}
    542 #endif
    543 	break;
    544 #endif
    545 #ifdef NS
    546     case AF_NS:
    547 	protocol = PPP_XNS;
    548 	break;
    549 #endif
    550     case AF_UNSPEC:
    551 	ph = (struct ppp_header *) dst->sa_data;
    552 	address = ph->ph_address;
    553 	control = ph->ph_control;
    554 	protocol = ntohs(ph->ph_protocol);
    555 	break;
    556     default:
    557 	printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
    558 	error = EAFNOSUPPORT;
    559 	goto bad;
    560     }
    561     compac = sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
    562 	    control == PPP_UI && protocol != PPP_ALLSTATIONS &&
    563 	    protocol != PPP_LCP;
    564     compprot = sc->sc_flags & SC_COMP_PROT && protocol < 0x100;
    565 
    566     /*
    567      * Add PPP header.  If no space in first mbuf, allocate another.
    568      */
    569     if (M_LEADINGSPACE(m0) < sizeof(struct ppp_header)) {
    570 	m0 = m_prepend(m0, sizeof(struct ppp_header), M_DONTWAIT);
    571 	if (m0 == 0) {
    572 	    error = ENOBUFS;
    573 	    goto bad;
    574 	}
    575 	m0->m_len = 0;
    576     } else
    577 	m0->m_data -= (compac ? 0 : 2) + (compprot ? 1 : 2);
    578 
    579     cp = mtod(m0, u_char *);
    580     if (!compac) {
    581 	*cp++ = address;
    582 	*cp++ = control;
    583 	m0->m_len += 2;
    584     }
    585     if (!compprot) {
    586 	*cp++ = protocol >> 8;
    587 	m0->m_len++;
    588     }
    589     *cp++ = protocol & 0xff;
    590     m0->m_len++;
    591 
    592     /*
    593      * Add PPP trailer.  Compute one's complement of FCS over frame
    594      * and attach to mbuf chain least significant byte first.
    595      */
    596     fcs = PPP_INITFCS;
    597     for (m = m0; m; m = m->m_next) {
    598 	fcs = pppfcs(fcs, mtod(m, u_char *), m->m_len);
    599 	m1 = m;
    600     }
    601     fcs ^= 0xffff;
    602 
    603     /*
    604      * If the last mbuf is a cluster, we can't just store the
    605      * FCS in it (other mbufs might point to the same cluster).
    606      */
    607     if (M_TRAILINGSPACE(m1) < sizeof(short) || m1->m_flags & M_EXT) {
    608 	MGET(m, M_DONTWAIT, MT_HEADER);
    609 	if (m == 0) {
    610 	    error = ENOBUFS;
    611 	    goto bad;
    612 	}
    613 	m->m_next = NULL;
    614 	m->m_len = 0;
    615 	m1->m_next = m;
    616 	m1 = m;
    617     }
    618     cp = mtod(m1, u_char *) + m1->m_len;
    619 
    620     *cp++ = fcs & 0xff;
    621     *cp++ = fcs >> 8;
    622     m1->m_len += 2;
    623 
    624     if (ppp_async_out_debug) {
    625 	printf("ppp%d output: ", ifp->if_unit);
    626 	pppdumpm(m0, -1);
    627     }
    628 
    629     s = splimp();
    630     if (IF_QFULL(&ifp->if_snd)) {
    631 	IF_DROP(&ifp->if_snd);
    632 	splx(s);
    633 	sc->sc_if.if_oerrors++;
    634 	error = ENOBUFS;
    635 	goto bad;
    636     }
    637     IF_ENQUEUE(&ifp->if_snd, m0);
    638     if (CCOUNT(&sc->sc_ttyp->t_outq) == 0)
    639 	pppstart(sc->sc_ttyp);
    640     splx(s);
    641     return (0);
    642 
    643 bad:
    644     m_freem(m0);
    645     return (error);
    646 }
    647 
    648 /*
    649  * Start output on interface.  Get another datagram
    650  * to send from the interface queue and map it to
    651  * the interface before starting output.
    652  */
    653 void
    654 pppstart(tp)
    655     register struct tty *tp;
    656 {
    657     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
    658     register struct mbuf *m;
    659     register int len;
    660     register u_char *start, *stop, *cp;
    661     int n, s, ndone;
    662     struct mbuf *m2;
    663 
    664     for (;;) {
    665 	/*
    666 	 * If there is more in the output queue, just send it now.
    667 	 * We are being called in lieu of ttstart and must do what
    668 	 * it would.
    669 	 */
    670 	if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) {
    671 	    (*tp->t_oproc)(tp);
    672 	    if (CCOUNT(&tp->t_outq) > PPP_HIWAT)
    673 		return;
    674 	}
    675 	/*
    676 	 * This happens briefly when the line shuts down.
    677 	 */
    678 	if (sc == NULL)
    679 	    return;
    680 
    681 	/*
    682 	 * See if we have an existing packet partly sent.
    683 	 * If not, get a new packet and start sending it.
    684 	 */
    685 	m = sc->sc_outm;
    686 	if (m == NULL) {
    687 	    s = splimp();
    688 	    IF_DEQUEUE(&sc->sc_if.if_snd, m);
    689 	    splx(s);
    690 	    if (m == NULL)
    691 		return;
    692 
    693 	    /*
    694 	     * The extra PPP_FLAG will start up a new packet, and thus
    695 	     * will flush any accumulated garbage.  We do this whenever
    696 	     * the line may have been idle for some time.
    697 	     */
    698 	    if (CCOUNT(&tp->t_outq) == 0) {
    699 		++sc->sc_bytessent;
    700 		(void) putc(PPP_FLAG, &tp->t_outq);
    701 	    }
    702 	}
    703 
    704 	do {
    705 	    start = mtod(m, u_char *);
    706 	    len = m->m_len;
    707 	    stop = start + len;
    708 	    while (len > 0) {
    709 		/*
    710 		 * Find out how many bytes in the string we can
    711 		 * handle without doing something special.
    712 		 */
    713 		for (cp = start; cp < stop; cp++)
    714 		    if ((*cp == PPP_FLAG) || (*cp == PPP_ESCAPE) ||
    715 			(*cp < 0x20 && (sc->sc_asyncmap & (1 << *cp))))
    716 			break;
    717 		n = cp - start;
    718 		if (n) {
    719 #ifndef	RB_LEN
    720 		    /* NetBSD, 4.3-Reno or similar. */
    721 		    ndone = n - b_to_q(start, n, &tp->t_outq);
    722 #else
    723 		    /* 386BSD */
    724 		    int cc, nleft;
    725 		    for (nleft = n; nleft > 0; nleft -= cc) {
    726 			if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0)
    727 			    break;
    728 			cc = min (cc, nleft);
    729 			bcopy((char *)start, tp->t_out.rb_tl, cc);
    730 			tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
    731 						      tp->t_out.rb_tl + cc);
    732 		    }
    733 		    ndone = n - nleft;
    734 #endif	/* RB_LEN */
    735 		    len -= ndone;
    736 		    start += ndone;
    737 		    sc->sc_bytessent += ndone;
    738 
    739 		    if (ndone < n)
    740 			break;	/* packet doesn't fit */
    741 		}
    742 		/*
    743 		 * If there are characters left in the mbuf,
    744 		 * the first one must be special..
    745 		 * Put it out in a different form.
    746 		 */
    747 		if (len) {
    748 		    if (putc(PPP_ESCAPE, &tp->t_outq))
    749 			break;
    750 		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
    751 			(void) unputc(&tp->t_outq);
    752 			break;
    753 		    }
    754 		    sc->sc_bytessent += 2;
    755 		    start++;
    756 		    len--;
    757 		}
    758 	    }
    759 	    /*
    760 	     * If we didn't empty this mbuf, remember where we're up to.
    761 	     * If we emptied the last mbuf, try to add the closing flag,
    762 	     * and if we can't, leave sc_outm pointing to m, but with
    763 	     * m->m_len == 0, to remind us to output the flag later.
    764 	     */
    765 	    if (len > 0 || m->m_next == NULL && putc(PPP_FLAG, &tp->t_outq)) {
    766 		m->m_data = start;
    767 		m->m_len = len;
    768 		sc->sc_outm = m;
    769 		if (tp->t_oproc != NULL)
    770 		    (*tp->t_oproc)(tp);
    771 		return;		/* can't do any more at the moment */
    772 	    }
    773 
    774 	    /* Finished with this mbuf; free it and move on. */
    775 	    MFREE(m, m2);
    776 	    m = m2;
    777 	} while (m);
    778 
    779 	/* Finished a packet */
    780 	sc->sc_outm = NULL;
    781 	sc->sc_bytessent++;	/* account for closing flag */
    782 	sc->sc_if.if_opackets++;
    783 	sc->sc_if.if_obytes = sc->sc_bytessent;
    784     }
    785 }
    786 
    787 /*
    788  * Allocate enough mbuf to handle current MTU.
    789  */
    790 static int
    791 pppinit(sc)
    792     register struct ppp_softc *sc;
    793 {
    794     struct mbuf *m, **mp;
    795     int len = HDROFF + MAX(sc->sc_if.if_mtu, PPP_MRU) +
    796 	sizeof (struct ppp_header) + sizeof (u_short);
    797     int s;
    798 
    799     s = splimp();
    800     for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next)
    801 	if ((len -= M_DATASIZE(m)) <= 0) {
    802 	    splx(s);
    803 	    return (1);
    804 	}
    805 
    806     for (;; mp = &m->m_next) {
    807 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    808 	if (m == 0) {
    809 	    m_freem(sc->sc_m);
    810 	    sc->sc_m = NULL;
    811 	    splx(s);
    812 	    printf("ppp%d: can't allocate mbuf\n", sc - ppp_softc);
    813 	    return (0);
    814 	}
    815 	*mp = m;
    816 	MCLGET(m, M_DONTWAIT);
    817 	if ((len -= M_DATASIZE(m)) <= 0) {
    818 	    splx(s);
    819 	    return (1);
    820 	}
    821     }
    822 }
    823 
    824 /*
    825  * Copy mbuf chain.  Would like to use m_copy(), but we need a real copy
    826  * of the data, not just copies of pointers to the data.
    827  */
    828 static struct mbuf *
    829 ppp_btom(sc)
    830     struct ppp_softc *sc;
    831 {
    832     register struct mbuf *m, **mp;
    833     struct mbuf *top = sc->sc_m;
    834 
    835     /*
    836      * First check current mbuf.  If we have more than a small mbuf,
    837      * return the whole cluster and set beginning of buffer to the
    838      * next mbuf.
    839      * Else, copy the current bytes into a small mbuf, attach the new
    840      * mbuf to the end of the chain and set beginning of buffer to the
    841      * current mbuf.
    842      */
    843 
    844     if (sc->sc_mc->m_len > MHLEN) {
    845 	sc->sc_m = sc->sc_mc->m_next;
    846 	sc->sc_mc->m_next = NULL;
    847     }
    848     else {
    849 	/* rather than waste a whole cluster on <= MHLEN bytes,
    850 	   alloc a small mbuf and copy to it */
    851 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    852 	if (m == NULL)
    853 	    return (NULL);
    854 
    855 	bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t),
    856 	      sc->sc_mc->m_len);
    857 	m->m_len = sc->sc_mc->m_len;
    858 	for (mp = &top; *mp != sc->sc_mc; mp = &(*mp)->m_next)
    859 	    ;
    860 	*mp = m;
    861 	sc->sc_m = sc->sc_mc;
    862     }
    863 
    864     /*
    865      * Try to allocate enough extra mbufs to handle the next packet.
    866      */
    867     if (pppinit(sc) == 0) {
    868 	m_freem(top);
    869 	if (pppinit(sc) == 0)
    870 	    sc->sc_if.if_flags &= ~IFF_UP;
    871 	return (NULL);
    872     }
    873 
    874     return (top);
    875 }
    876 
    877 /*
    878  * tty interface receiver interrupt.
    879  */
    880 #define COMPTYPE(proto)	((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
    881 			 TYPE_UNCOMPRESSED_TCP)
    882 
    883 void
    884 pppinput(c, tp)
    885     int c;
    886     register struct tty *tp;
    887 {
    888     register struct ppp_softc *sc;
    889     struct mbuf *m;
    890     struct ifqueue *inq;
    891     int s, ilen, xlen, proto;
    892     char *pkttype;
    893 
    894     tk_nin++;
    895     sc = (struct ppp_softc *)tp->t_sc;
    896     if (sc == NULL)
    897 	return;
    898 
    899     ++sc->sc_if.if_ibytes;
    900 
    901     if (c & TTY_FE)
    902 	/* framing error or overrun on this char - abort packet */
    903 	goto flush;
    904 
    905     c &= 0xff;
    906     if (c == PPP_FLAG) {
    907 	ilen = sc->sc_ilen;
    908 	sc->sc_ilen = 0;
    909 
    910 	if (sc->sc_flags & SC_FLUSH
    911 	    || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) {
    912 #ifdef VJC
    913 	    /*
    914 	     * If we've missed a packet, we must toss subsequent compressed
    915 	     * packets which don't have an explicit connection ID.
    916 	     */
    917 	    sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
    918 #endif
    919 	    if ((sc->sc_flags & SC_FLUSH) == 0){
    920 		if (ppp_debug)
    921 		    printf("ppp: bad fcs\n");
    922 		sc->sc_if.if_ierrors++;
    923 	    } else
    924 		sc->sc_flags &= ~SC_FLUSH;
    925 	    return;
    926 	}
    927 
    928 	if (ilen < sizeof (struct ppp_header) + 2) {
    929 	    if (ilen) {
    930 		if (ppp_debug)
    931 		    printf("ppp: too short (%d)\n", ilen);
    932 		sc->sc_if.if_ierrors++;
    933 	    }
    934 	    return;
    935 	}
    936 
    937 	/*
    938 	 * Remove FCS trailer.  Somewhat painful...
    939 	 */
    940 	ilen -= 2;
    941 	if (--sc->sc_mc->m_len == 0) {
    942 	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
    943 		;
    944 	    sc->sc_mc = m;
    945 	}
    946 	sc->sc_mc->m_len--;
    947 
    948 	sc->sc_if.if_ipackets++;
    949 	m = sc->sc_m;
    950 
    951 	if (ppp_async_in_debug) {
    952 	    printf("ppp%d: got %d bytes\n", sc - ppp_softc, ilen);
    953 	    pppdumpm(m, ilen);
    954 	}
    955 
    956 	proto = ntohs(mtod(m, struct ppp_header *)->ph_protocol);
    957 	switch (proto) {
    958 #ifdef INET
    959 	case PPP_IP:
    960 	    ilen -= sizeof (struct ppp_header);
    961 	    m->m_data += sizeof (struct ppp_header);
    962 	    m->m_len -= sizeof (struct ppp_header);
    963 	    break;
    964 
    965 #ifdef VJC
    966 	case PPP_VJC_COMP:
    967 	case PPP_VJC_UNCOMP:
    968 	    pkttype = proto == PPP_VJC_COMP? "": "un";
    969 	    if (sc->sc_flags & SC_COMP_TCP) {
    970 
    971 		m->m_data += sizeof (struct ppp_header);
    972 		m->m_len -= sizeof (struct ppp_header);
    973 		ilen -= sizeof(struct ppp_header);
    974 
    975 		xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data),
    976 					      m->m_len, ilen,
    977 					      COMPTYPE(proto), &sc->sc_comp);
    978 
    979 		if (xlen) {
    980 		    /* adjust the first mbuf by the decompressed amt */
    981 		    m->m_len += xlen - ilen;
    982 		    ilen = xlen;
    983 		    proto = PPP_IP;
    984 		    break;
    985 		}
    986 
    987 		if (ppp_debug)
    988 		    printf("ppp%d: sl_uncompress failed on type %scomp\n",
    989 		       sc->sc_if.if_unit, pkttype);
    990 
    991 	    } else {
    992 		if (ppp_debug)
    993 		    printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n",
    994 			   sc->sc_if.if_unit, pkttype, sc->sc_flags);
    995 	    }
    996 	    if (ppp_debug)
    997 		printf("ppp: packet rejected, protocol 0x%x\n", proto);
    998 	    sc->sc_if.if_ierrors++;
    999 	    return;
   1000 #endif
   1001 #endif
   1002 	}
   1003 
   1004 	/* get this packet as an mbuf chain */
   1005 	if ((m = ppp_btom(sc)) == NULL) {
   1006 	    sc->sc_if.if_ierrors++;
   1007 	    return;
   1008 	}
   1009 	m->m_pkthdr.len = ilen;
   1010 	m->m_pkthdr.rcvif = &sc->sc_if;
   1011 
   1012 	if (proto == PPP_IP) {
   1013 	    /* IP packet - pass it up to IP */
   1014 	    if ((sc->sc_if.if_flags & IFF_UP) == 0) {
   1015 		/* interface is down - drop the packet. */
   1016 		m_freem(m);
   1017 		sc->sc_if.if_ierrors++;
   1018 		return;
   1019 	    }
   1020 	    schednetisr(NETISR_IP);
   1021 	    inq = &ipintrq;
   1022 
   1023 	} else {
   1024 	    /* some other protocol - place on input queue for read() */
   1025 	    /* Put a placeholder byte in canq for ttselect()/ttnread() */
   1026 	    putc(0, &tp->t_canq);
   1027 	    ttwakeup(tp);
   1028 	    inq = &sc->sc_inq;
   1029 	}
   1030 
   1031 	s = splimp();
   1032 	if (IF_QFULL(inq)) {
   1033 	    IF_DROP(inq);
   1034 	    if (ppp_debug)
   1035 		printf("ppp: queue full\n");
   1036 	    sc->sc_if.if_ierrors++;
   1037 	    sc->sc_if.if_iqdrops++;
   1038 	    m_freem(m);
   1039 	} else
   1040 	    IF_ENQUEUE(inq, m);
   1041 
   1042 	splx(s);
   1043 	return;
   1044     }
   1045     if (sc->sc_flags & SC_FLUSH)
   1046 	return;
   1047     if (c == PPP_ESCAPE) {
   1048 	sc->sc_flags |= SC_ESCAPED;
   1049 	return;
   1050     }
   1051 
   1052     if (sc->sc_flags & SC_ESCAPED) {
   1053 	sc->sc_flags &= ~SC_ESCAPED;
   1054 	c ^= PPP_TRANS;
   1055     }
   1056 
   1057     /*
   1058      * Initialize buffer on first octet received.
   1059      * First octet could be address or protocol (when compressing
   1060      * address/control).
   1061      * Second octet is control.
   1062      * Third octet is first or second (when compressing protocol)
   1063      * octet of protocol.
   1064      * Fourth octet is second octet of protocol.
   1065      */
   1066     if (sc->sc_ilen == 0) {
   1067 	/* reset the first input mbuf */
   1068 	m = sc->sc_m;
   1069 	m->m_len = 0;
   1070 	m->m_data = M_DATASTART(sc->sc_m) + HDROFF;
   1071 	sc->sc_mc = m;
   1072 	sc->sc_mp = mtod(m, char *);
   1073 	sc->sc_fcs = PPP_INITFCS;
   1074 	if (c != PPP_ALLSTATIONS) {
   1075 	    if ((sc->sc_flags & SC_COMP_AC) == 0) {
   1076 		if (ppp_debug)
   1077 		    printf("ppp: missing ALLSTATIONS, got 0x%x; flags %x\n",
   1078 			   c, sc->sc_flags);
   1079 		goto flush;
   1080 	    }
   1081 	    *sc->sc_mp++ = PPP_ALLSTATIONS;
   1082 	    *sc->sc_mp++ = PPP_UI;
   1083 	    sc->sc_ilen += 2;
   1084 	    m->m_len += 2;
   1085 	}
   1086     }
   1087     if (sc->sc_ilen == 1 && c != PPP_UI) {
   1088 	if (ppp_debug)
   1089 	    printf("ppp: missing UI, got 0x%x\n", c);
   1090 	goto flush;
   1091     }
   1092     if (sc->sc_ilen == 2 && (c & 1) == 1) {
   1093 	if ((sc->sc_flags & SC_COMP_PROT) == 0) {
   1094 	    if (ppp_debug)
   1095 		printf("ppp: compressed protocol %x, but compression off\n",
   1096 		       c);
   1097 	    goto flush;
   1098 	}
   1099 	*sc->sc_mp++ = 0;
   1100 	sc->sc_ilen++;
   1101 	sc->sc_mc->m_len++;
   1102     }
   1103     if (sc->sc_ilen == 3 && (c & 1) == 0) {
   1104 	if (ppp_debug)
   1105 	    printf("ppp: bad protocol %x\n", c);
   1106 	goto flush;
   1107     }
   1108 
   1109     /* packet beyond configured mtu? */
   1110     if (++sc->sc_ilen > MAX(sc->sc_if.if_mtu, PPP_MRU) +
   1111 	sizeof (struct ppp_header) + sizeof (u_short)) {
   1112 	if (ppp_debug)
   1113 	    printf("ppp: packet too big\n");
   1114 	goto flush;
   1115     }
   1116 
   1117     /* is this mbuf full? */
   1118     m = sc->sc_mc;
   1119     if (M_TRAILINGSPACE(m) <= 0) {
   1120 	sc->sc_mc = m = m->m_next;
   1121 	if (m == NULL) {
   1122 	    printf("ppp%d: too few input mbufs!\n");
   1123 	    goto flush;
   1124 	}
   1125 	m->m_len = 0;
   1126 	m->m_data = M_DATASTART(m);
   1127 	sc->sc_mp = mtod(m, char *);
   1128     }
   1129 
   1130     ++m->m_len;
   1131     *sc->sc_mp++ = c;
   1132     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
   1133     return;
   1134 
   1135  flush:
   1136     sc->sc_if.if_ierrors++;
   1137     sc->sc_flags |= SC_FLUSH;
   1138 }
   1139 
   1140 /*
   1141  * Process an ioctl request to interface.
   1142  */
   1143 pppioctl(ifp, cmd, data)
   1144     register struct ifnet *ifp;
   1145     int cmd;
   1146     caddr_t data;
   1147 {
   1148     struct proc *p = curproc;	/* XXX */
   1149     register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
   1150     register struct ifaddr *ifa = (struct ifaddr *)data;
   1151     register struct ifreq *ifr = (struct ifreq *)data;
   1152     int s = splimp(), error = 0;
   1153 
   1154 
   1155     switch (cmd) {
   1156     case SIOCSIFFLAGS:
   1157 	if ((ifp->if_flags & IFF_RUNNING) == 0)
   1158 	    ifp->if_flags &= ~IFF_UP;
   1159 	break;
   1160 
   1161     case SIOCSIFADDR:
   1162 	if (ifa->ifa_addr->sa_family != AF_INET)
   1163 	    error = EAFNOSUPPORT;
   1164 	break;
   1165 
   1166     case SIOCSIFDSTADDR:
   1167 	if (ifa->ifa_addr->sa_family != AF_INET)
   1168 	    error = EAFNOSUPPORT;
   1169 	break;
   1170 
   1171     case SIOCSIFMTU:
   1172 	if (error = suser(p->p_ucred, &p->p_acflag))
   1173 	    return (error);
   1174 	sc->sc_if.if_mtu = ifr->ifr_mtu;
   1175 	if (pppinit(sc) == 0)
   1176 	    error = ENOBUFS;
   1177 	break;
   1178 
   1179     case SIOCGIFMTU:
   1180 	ifr->ifr_mtu = sc->sc_if.if_mtu;
   1181 	break;
   1182 
   1183     default:
   1184 	error = EINVAL;
   1185     }
   1186     splx(s);
   1187     return (error);
   1188 }
   1189 
   1190 #define MAX_DUMP_BYTES	128
   1191 
   1192 static void
   1193 pppdumpm(m0, pktlen)
   1194     struct mbuf *m0;
   1195     int pktlen;
   1196 {
   1197     char buf[2*MAX_DUMP_BYTES+4];
   1198     char *bp = buf;
   1199     struct mbuf *m;
   1200     static char digits[] = "0123456789abcdef";
   1201 
   1202     for (m = m0; m && pktlen; m = m->m_next) {
   1203 	int l = m->m_len;
   1204 	u_char *rptr = (u_char *)m->m_data;
   1205 
   1206 	if (pktlen > 0) {
   1207 	    l = min(l, pktlen);
   1208 	    pktlen -= l;
   1209 	}
   1210 	while (l--) {
   1211 	    if (bp > buf + sizeof(buf) - 4)
   1212 		goto done;
   1213 	    *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
   1214 	    *bp++ = digits[*rptr++ & 0xf];
   1215 	}
   1216 
   1217 	if (m->m_next) {
   1218 	    if (bp > buf + sizeof(buf) - 3)
   1219 		goto done;
   1220 	    *bp++ = '|';
   1221 	}
   1222     }
   1223 done:
   1224     if (m && pktlen)
   1225 	*bp++ = '>';
   1226     *bp = 0;
   1227     printf("%s\n", buf);
   1228 }
   1229 
   1230 static void
   1231 pppdumpb(b, l)
   1232     u_char *b;
   1233     int l;
   1234 {
   1235     char buf[2*MAX_DUMP_BYTES+4];
   1236     char *bp = buf;
   1237     static char digits[] = "0123456789abcdef";
   1238 
   1239     while (l--) {
   1240 	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
   1241 	*bp++ = digits[*b++ & 0xf];
   1242 	if (bp >= buf + sizeof(buf) - 2) {
   1243 	    *bp++ = '>';
   1244 	    break;
   1245 	}
   1246     }
   1247 
   1248     *bp = 0;
   1249     printf("%s\n", buf);
   1250 }
   1251 
   1252 
   1253 #endif	/* NPPP > 0 */
   1254