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