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