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