Merge from vendor branch TNF:
[pkgsrcv2.git] / net / ppp-mppe / patches / patch-ap
1 $NetBSD$
2
3 --- /dev/null   Sat Sep 18 04:00:15 1999
4 +++ netbsd-1.4/if_ppp.c Sat Sep 18 04:06:21 1999
5 @@ -0,0 +1,1616 @@
6 +/*     NetBSD: if_ppp.c,v 1.55 1999/07/30 10:35:38 itojun Exp  */
7 +/*     Id: if_ppp.c,v 1.6 1997/03/04 03:33:00 paulus Exp       */
8 +
9 +/*
10 + * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
11 + *
12 + * Copyright (c) 1989 Carnegie Mellon University.
13 + * All rights reserved.
14 + *
15 + * Redistribution and use in source and binary forms are permitted
16 + * provided that the above copyright notice and this paragraph are
17 + * duplicated in all such forms and that any documentation,
18 + * advertising materials, and other materials related to such
19 + * distribution and use acknowledge that the software was developed
20 + * by Carnegie Mellon University.  The name of the
21 + * University may not be used to endorse or promote products derived
22 + * from this software without specific prior written permission.
23 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 + *
27 + * Drew D. Perkins
28 + * Carnegie Mellon University
29 + * 4910 Forbes Ave.
30 + * Pittsburgh, PA 15213
31 + * (412) 268-8576
32 + * ddp@andrew.cmu.edu
33 + *
34 + * Based on:
35 + *     @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
36 + *
37 + * Copyright (c) 1987 Regents of the University of California.
38 + * All rights reserved.
39 + *
40 + * Redistribution and use in source and binary forms are permitted
41 + * provided that the above copyright notice and this paragraph are
42 + * duplicated in all such forms and that any documentation,
43 + * advertising materials, and other materials related to such
44 + * distribution and use acknowledge that the software was developed
45 + * by the University of California, Berkeley.  The name of the
46 + * University may not be used to endorse or promote products derived
47 + * from this software without specific prior written permission.
48 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
49 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
50 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51 + *
52 + * Serial Line interface
53 + *
54 + * Rick Adams
55 + * Center for Seismic Studies
56 + * 1300 N 17th Street, Suite 1450
57 + * Arlington, Virginia 22209
58 + * (703)276-7900
59 + * rick@seismo.ARPA
60 + * seismo!rick
61 + *
62 + * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
63 + * Converted to 4.3BSD Beta by Chris Torek.
64 + * Other changes made at Berkeley, based in part on code by Kirk Smith.
65 + *
66 + * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
67 + * Added VJ tcp header compression; more unified ioctls
68 + *
69 + * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
70 + * Cleaned up a lot of the mbuf-related code to fix bugs that
71 + * caused system crashes and packet corruption.  Changed pppstart
72 + * so that it doesn't just give up with a collision if the whole
73 + * packet doesn't fit in the output ring buffer.
74 + *
75 + * Added priority queueing for interactive IP packets, following
76 + * the model of if_sl.c, plus hooks for bpf.
77 + * Paul Mackerras (paulus@cs.anu.edu.au).
78 + */
79 +
80 +/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
81 +/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
82 +
83 +#include "ppp.h"
84 +#if NPPP > 0
85 +
86 +#define VJC
87 +#define PPP_COMPRESS
88 +
89 +#include "opt_inet.h"
90 +#include "opt_gateway.h"
91 +#include "opt_ppp.h"
92 +
93 +#include <sys/param.h>
94 +#include <sys/proc.h>
95 +#include <sys/mbuf.h>
96 +#include <sys/socket.h>
97 +#include <sys/ioctl.h>
98 +#include <sys/kernel.h>
99 +#include <sys/systm.h>
100 +#include <sys/time.h>
101 +#include <sys/malloc.h>
102 +
103 +#include <net/if.h>
104 +#include <net/if_types.h>
105 +#include <net/netisr.h>
106 +#include <net/route.h>
107 +#ifdef PPP_FILTER
108 +#include <net/bpf.h>
109 +#endif
110 +
111 +#ifdef INET
112 +#include <netinet/in.h>
113 +#include <netinet/in_systm.h>
114 +#include <netinet/in_var.h>
115 +#include <netinet/ip.h>
116 +#else
117 +#ifdef _KERNEL
118 +#ifdef VJC
119 +#error ppp device with VJC assumes INET
120 +#endif
121 +#endif
122 +#endif
123 +
124 +#include "bpfilter.h"
125 +#if NBPFILTER > 0
126 +#include <sys/time.h>
127 +#include <net/bpf.h>
128 +#endif
129 +
130 +#if defined(PPP_FILTER) || NBPFILTER > 0
131 +#include <net/slip.h>
132 +#endif
133 +
134 +#ifdef VJC
135 +#include <net/slcompress.h>
136 +#endif
137 +
138 +#include <net/ppp_defs.h>
139 +#include <net/if_ppp.h>
140 +#include <net/if_pppvar.h>
141 +#include <machine/cpu.h>
142 +
143 +#ifdef PPP_COMPRESS
144 +#define PACKETPTR      struct mbuf *
145 +#include <net/ppp-comp.h>
146 +#endif
147 +
148 +static int     pppsioctl __P((struct ifnet *, u_long, caddr_t));
149 +static void    ppp_requeue __P((struct ppp_softc *));
150 +static void    ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd));
151 +static void    ppp_ccp_closed __P((struct ppp_softc *));
152 +static void    ppp_inproc __P((struct ppp_softc *, struct mbuf *));
153 +static void    pppdumpm __P((struct mbuf *m0));
154 +
155 +/*
156 + * Some useful mbuf macros not in mbuf.h.
157 + */
158 +#define M_IS_CLUSTER(m)        ((m)->m_flags & M_EXT)
159 +
160 +#define M_DATASTART(m) \
161 +       (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
162 +           (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
163 +
164 +#define M_DATASIZE(m)  \
165 +       (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
166 +           (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
167 +
168 +/*
169 + * We define two link layer specific mbuf flags, to mark high-priority
170 + * packets for output, and received packets following lost/corrupted
171 + * packets.
172 + */
173 +#define        M_HIGHPRI       M_LINK0 /* output packet for sc_fastq */
174 +#define        M_ERRMARK       M_LINK1 /* rx packet following lost/corrupted pkt */
175 +
176 +#ifdef PPP_COMPRESS
177 +/*
178 + * List of compressors we know about.
179 + * We leave some space so maybe we can modload compressors.
180 + */
181 +
182 +extern struct compressor ppp_bsd_compress;
183 +extern struct compressor ppp_deflate, ppp_deflate_draft;
184 +
185 +struct compressor *ppp_compressors[8] = {
186 +#if DO_BSD_COMPRESS && defined(PPP_BSDCOMP)
187 +    &ppp_bsd_compress,
188 +#endif
189 +#if DO_DEFLATE && defined(PPP_DEFLATE)
190 +    &ppp_deflate,
191 +    &ppp_deflate_draft,
192 +#endif
193 +    NULL
194 +};
195 +#endif /* PPP_COMPRESS */
196 +
197 +
198 +/*
199 + * Called from boot code to establish ppp interfaces.
200 + */
201 +void
202 +pppattach()
203 +{
204 +    register struct ppp_softc *sc;
205 +    register int i = 0;
206 +
207 +    for (sc = ppp_softc; i < NPPP; sc++) {
208 +       sc->sc_unit = i;        /* XXX */
209 +       sprintf(sc->sc_if.if_xname, "ppp%d", i++);
210 +       sc->sc_if.if_softc = sc;
211 +       sc->sc_if.if_mtu = PPP_MTU;
212 +       sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
213 +       sc->sc_if.if_type = IFT_PPP;
214 +       sc->sc_if.if_hdrlen = PPP_HDRLEN;
215 +       sc->sc_if.if_ioctl = pppsioctl;
216 +       sc->sc_if.if_output = pppoutput;
217 +       sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
218 +       sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
219 +       sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
220 +       sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
221 +       if_attach(&sc->sc_if);
222 +#if NBPFILTER > 0
223 +       bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_NULL, 0);
224 +#endif
225 +    }
226 +}
227 +
228 +/*
229 + * Allocate a ppp interface unit and initialize it.
230 + */
231 +struct ppp_softc *
232 +pppalloc(pid)
233 +    pid_t pid;
234 +{
235 +    int nppp, i;
236 +    struct ppp_softc *sc;
237 +
238 +    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
239 +       if (sc->sc_xfer == pid) {
240 +           sc->sc_xfer = 0;
241 +           return sc;
242 +       }
243 +    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
244 +       if (sc->sc_devp == NULL)
245 +           break;
246 +    if (nppp >= NPPP)
247 +       return NULL;
248 +
249 +    sc->sc_flags = 0;
250 +    sc->sc_mru = PPP_MRU;
251 +    sc->sc_relinq = NULL;
252 +    bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats));
253 +#ifdef VJC
254 +    MALLOC(sc->sc_comp, struct slcompress *, sizeof(struct slcompress),
255 +          M_DEVBUF, M_NOWAIT);
256 +    if (sc->sc_comp)
257 +       sl_compress_init(sc->sc_comp);
258 +#endif
259 +#ifdef PPP_COMPRESS
260 +    sc->sc_xc_state = NULL;
261 +    sc->sc_rc_state = NULL;
262 +#endif /* PPP_COMPRESS */
263 +    for (i = 0; i < NUM_NP; ++i)
264 +       sc->sc_npmode[i] = NPMODE_ERROR;
265 +    sc->sc_npqueue = NULL;
266 +    sc->sc_npqtail = &sc->sc_npqueue;
267 +    sc->sc_last_sent = sc->sc_last_recv = time.tv_sec;
268 +
269 +    return sc;
270 +}
271 +
272 +/*
273 + * Deallocate a ppp unit.  Must be called at splsoftnet or higher.
274 + */
275 +void
276 +pppdealloc(sc)
277 +    struct ppp_softc *sc;
278 +{
279 +    struct mbuf *m;
280 +
281 +    if_down(&sc->sc_if);
282 +    sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
283 +    sc->sc_devp = NULL;
284 +    sc->sc_xfer = 0;
285 +    for (;;) {
286 +       IF_DEQUEUE(&sc->sc_rawq, m);
287 +       if (m == NULL)
288 +           break;
289 +       m_freem(m);
290 +    }
291 +    for (;;) {
292 +       IF_DEQUEUE(&sc->sc_inq, m);
293 +       if (m == NULL)
294 +           break;
295 +       m_freem(m);
296 +    }
297 +    for (;;) {
298 +       IF_DEQUEUE(&sc->sc_fastq, m);
299 +       if (m == NULL)
300 +           break;
301 +       m_freem(m);
302 +    }
303 +    while ((m = sc->sc_npqueue) != NULL) {
304 +       sc->sc_npqueue = m->m_nextpkt;
305 +       m_freem(m);
306 +    }
307 +    if (sc->sc_togo != NULL) {
308 +       m_freem(sc->sc_togo);
309 +       sc->sc_togo = NULL;
310 +    }
311 +#ifdef PPP_COMPRESS
312 +    ppp_ccp_closed(sc);
313 +    sc->sc_xc_state = NULL;
314 +    sc->sc_rc_state = NULL;
315 +#endif /* PPP_COMPRESS */
316 +#ifdef PPP_FILTER
317 +    if (sc->sc_pass_filt_in.bf_insns != 0) {
318 +       FREE(sc->sc_pass_filt_in.bf_insns, M_DEVBUF);
319 +       sc->sc_pass_filt_in.bf_insns = 0;
320 +       sc->sc_pass_filt_in.bf_len = 0;
321 +    }
322 +    if (sc->sc_pass_filt_out.bf_insns != 0) {
323 +       FREE(sc->sc_pass_filt_out.bf_insns, M_DEVBUF);
324 +       sc->sc_pass_filt_out.bf_insns = 0;
325 +       sc->sc_pass_filt_out.bf_len = 0;
326 +    }
327 +    if (sc->sc_active_filt_in.bf_insns != 0) {
328 +       FREE(sc->sc_active_filt_in.bf_insns, M_DEVBUF);
329 +       sc->sc_active_filt_in.bf_insns = 0;
330 +       sc->sc_active_filt_in.bf_len = 0;
331 +    }
332 +    if (sc->sc_active_filt_out.bf_insns != 0) {
333 +       FREE(sc->sc_active_filt_out.bf_insns, M_DEVBUF);
334 +       sc->sc_active_filt_out.bf_insns = 0;
335 +       sc->sc_active_filt_out.bf_len = 0;
336 +    }
337 +#endif /* PPP_FILTER */
338 +#ifdef VJC
339 +    if (sc->sc_comp != 0) {
340 +       FREE(sc->sc_comp, M_DEVBUF);
341 +       sc->sc_comp = 0;
342 +    }
343 +#endif
344 +}
345 +
346 +/*
347 + * Ioctl routine for generic ppp devices.
348 + */
349 +int
350 +pppioctl(sc, cmd, data, flag, p)
351 +    struct ppp_softc *sc;
352 +    u_long cmd;
353 +    caddr_t data;
354 +    int flag;
355 +    struct proc *p;
356 +{
357 +    int s, error, flags, mru, nb, npx;
358 +    struct ppp_option_data *odp;
359 +    struct compressor **cp;
360 +    struct npioctl *npi;
361 +    time_t t;
362 +#ifdef PPP_FILTER
363 +    struct bpf_program *bp, *nbp;
364 +    struct bpf_insn *newcode, *oldcode;
365 +    int newcodelen;
366 +#endif /* PPP_FILTER */
367 +#ifdef PPP_COMPRESS
368 +    u_char ccp_option[CCP_MAX_OPTION_LENGTH];
369 +#endif
370 +
371 +    switch (cmd) {
372 +    case FIONREAD:
373 +       *(int *)data = sc->sc_inq.ifq_len;
374 +       break;
375 +
376 +    case PPPIOCGUNIT:
377 +       *(int *)data = sc->sc_unit;     /* XXX */
378 +       break;
379 +
380 +    case PPPIOCGFLAGS:
381 +       *(u_int *)data = sc->sc_flags;
382 +       break;
383 +
384 +    case PPPIOCSFLAGS:
385 +       if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
386 +           return (error);
387 +       flags = *(int *)data & SC_MASK;
388 +       s = splsoftnet();
389 +#ifdef PPP_COMPRESS
390 +       if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
391 +           ppp_ccp_closed(sc);
392 +#endif
393 +       splimp();
394 +       sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
395 +       splx(s);
396 +       break;
397 +
398 +    case PPPIOCSMRU:
399 +       if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
400 +           return (error);
401 +       mru = *(int *)data;
402 +       if (mru >= PPP_MRU && mru <= PPP_MAXMRU)
403 +           sc->sc_mru = mru;
404 +       break;
405 +
406 +    case PPPIOCGMRU:
407 +       *(int *)data = sc->sc_mru;
408 +       break;
409 +
410 +#ifdef VJC
411 +    case PPPIOCSMAXCID:
412 +       if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
413 +           return (error);
414 +       if (sc->sc_comp) {
415 +           s = splsoftnet();
416 +           sl_compress_setup(sc->sc_comp, *(int *)data);
417 +           splx(s);
418 +       }
419 +       break;
420 +#endif
421 +
422 +    case PPPIOCXFERUNIT:
423 +       if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
424 +           return (error);
425 +       sc->sc_xfer = p->p_pid;
426 +       break;
427 +
428 +#ifdef PPP_COMPRESS
429 +    case PPPIOCSCOMPRESS:
430 +       if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
431 +           return (error);
432 +       odp = (struct ppp_option_data *) data;
433 +       nb = odp->length;
434 +       if (nb > sizeof(ccp_option))
435 +           nb = sizeof(ccp_option);
436 +       if ((error = copyin(odp->ptr, ccp_option, nb)) != 0)
437 +           return (error);
438 +       if (ccp_option[1] < 2)  /* preliminary check on the length byte */
439 +           return (EINVAL);
440 +       for (cp = ppp_compressors; *cp != NULL; ++cp)
441 +           if ((*cp)->compress_proto == ccp_option[0]) {
442 +               /*
443 +                * Found a handler for the protocol - try to allocate
444 +                * a compressor or decompressor.
445 +                */
446 +               error = 0;
447 +               if (odp->transmit) {
448 +                   s = splsoftnet();
449 +                   if (sc->sc_xc_state != NULL)
450 +                       (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
451 +                   sc->sc_xcomp = *cp;
452 +                   sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb);
453 +                   if (sc->sc_xc_state == NULL) {
454 +                       if (sc->sc_flags & SC_DEBUG)
455 +                           printf("%s: comp_alloc failed\n",
456 +                               sc->sc_if.if_xname);
457 +                       error = ENOBUFS;
458 +                   }
459 +                   splimp();
460 +                   sc->sc_flags &= ~SC_COMP_RUN;
461 +                   splx(s);
462 +               } else {
463 +                   s = splsoftnet();
464 +                   if (sc->sc_rc_state != NULL)
465 +                       (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
466 +                   sc->sc_rcomp = *cp;
467 +                   sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb);
468 +                   if (sc->sc_rc_state == NULL) {
469 +                       if (sc->sc_flags & SC_DEBUG)
470 +                           printf("%s: decomp_alloc failed\n",
471 +                               sc->sc_if.if_xname);
472 +                       error = ENOBUFS;
473 +                   }
474 +                   splimp();
475 +                   sc->sc_flags &= ~SC_DECOMP_RUN;
476 +                   splx(s);
477 +               }
478 +               return (error);
479 +           }
480 +       if (sc->sc_flags & SC_DEBUG)
481 +           printf("%s: no compressor for [%x %x %x], %x\n",
482 +               sc->sc_if.if_xname, ccp_option[0], ccp_option[1],
483 +               ccp_option[2], nb);
484 +       return (EINVAL);        /* no handler found */
485 +#endif /* PPP_COMPRESS */
486 +
487 +    case PPPIOCGNPMODE:
488 +    case PPPIOCSNPMODE:
489 +       npi = (struct npioctl *) data;
490 +       switch (npi->protocol) {
491 +       case PPP_IP:
492 +           npx = NP_IP;
493 +           break;
494 +       case PPP_IPV6:
495 +           npx = NP_IPV6;
496 +           break;
497 +       default:
498 +           return EINVAL;
499 +       }
500 +       if (cmd == PPPIOCGNPMODE) {
501 +           npi->mode = sc->sc_npmode[npx];
502 +       } else {
503 +           if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
504 +               return (error);
505 +           if (npi->mode != sc->sc_npmode[npx]) {
506 +               s = splimp();
507 +               sc->sc_npmode[npx] = npi->mode;
508 +               if (npi->mode != NPMODE_QUEUE) {
509 +                   ppp_requeue(sc);
510 +                   ppp_restart(sc);
511 +               }
512 +               splx(s);
513 +           }
514 +       }
515 +       break;
516 +
517 +    case PPPIOCGIDLE:
518 +       s = splsoftnet();
519 +       t = time.tv_sec;
520 +       ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent;
521 +       ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv;
522 +       splx(s);
523 +       break;
524 +
525 +#ifdef PPP_FILTER
526 +    case PPPIOCSPASS:
527 +    case PPPIOCSACTIVE:
528 +       /* These are no longer supported. */
529 +       return EOPNOTSUPP;
530 +
531 +    case PPPIOCSIPASS:
532 +    case PPPIOCSOPASS:
533 +    case PPPIOCSIACTIVE:
534 +    case PPPIOCSOACTIVE:
535 +       nbp = (struct bpf_program *) data;
536 +       if ((unsigned) nbp->bf_len > BPF_MAXINSNS)
537 +           return EINVAL;
538 +       newcodelen = nbp->bf_len * sizeof(struct bpf_insn);
539 +       if (newcodelen != 0) {
540 +           newcode = malloc(newcodelen, M_DEVBUF, M_WAITOK);
541 +           /* WAITOK -- malloc() never fails. */
542 +           if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode,
543 +                              newcodelen)) != 0) {
544 +               free(newcode, M_DEVBUF);
545 +               return error;
546 +           }
547 +           if (!bpf_validate(newcode, nbp->bf_len)) {
548 +               free(newcode, M_DEVBUF);
549 +               return EINVAL;
550 +           }
551 +       } else
552 +           newcode = 0;
553 +       switch (cmd) {
554 +       case PPPIOCSIPASS:
555 +           bp = &sc->sc_pass_filt_in;
556 +           break;
557 +
558 +       case PPPIOCSOPASS:
559 +           bp = &sc->sc_pass_filt_out;
560 +           break;
561 +
562 +       case PPPIOCSIACTIVE:
563 +           bp = &sc->sc_active_filt_in;
564 +           break;
565 +
566 +       case PPPIOCSOACTIVE:
567 +           bp = &sc->sc_active_filt_out;
568 +           break;
569 +       }
570 +       oldcode = bp->bf_insns;
571 +       s = splimp();
572 +       bp->bf_len = nbp->bf_len;
573 +       bp->bf_insns = newcode;
574 +       splx(s);
575 +       if (oldcode != 0)
576 +           free(oldcode, M_DEVBUF);
577 +       break;
578 +#endif /* PPP_FILTER */
579 +
580 +    default:
581 +       return (-1);
582 +    }
583 +    return (0);
584 +}
585 +
586 +/*
587 + * Process an ioctl request to the ppp network interface.
588 + */
589 +static int
590 +pppsioctl(ifp, cmd, data)
591 +    register struct ifnet *ifp;
592 +    u_long cmd;
593 +    caddr_t data;
594 +{
595 +    register struct proc *p = curproc; /* XXX */
596 +    register struct ppp_softc *sc = ifp->if_softc;
597 +    register struct ifaddr *ifa = (struct ifaddr *)data;
598 +    register struct ifreq *ifr = (struct ifreq *)data;
599 +    struct ppp_stats *psp;
600 +#ifdef PPP_COMPRESS
601 +    struct ppp_comp_stats *pcp;
602 +#endif
603 +    int s = splimp(), error = 0;
604 +
605 +    switch (cmd) {
606 +    case SIOCSIFFLAGS:
607 +       if ((ifp->if_flags & IFF_RUNNING) == 0)
608 +           ifp->if_flags &= ~IFF_UP;
609 +       break;
610 +
611 +    case SIOCSIFADDR:
612 +       switch (ifa->ifa_addr->sa_family) {
613 +#ifdef INET
614 +       case AF_INET:
615 +           break;
616 +#endif
617 +#ifdef INET6
618 +       case AF_INET6:
619 +           break;
620 +#endif
621 +       default:
622 +           error = EAFNOSUPPORT;
623 +           break;
624 +       }
625 +       break;
626 +
627 +    case SIOCSIFDSTADDR:
628 +       switch (ifa->ifa_addr->sa_family) {
629 +#ifdef INET
630 +       case AF_INET:
631 +           break;
632 +#endif
633 +#ifdef INET6
634 +       case AF_INET6:
635 +           break;
636 +#endif
637 +       default:
638 +           error = EAFNOSUPPORT;
639 +           break;
640 +       }
641 +       break;
642 +
643 +    case SIOCSIFMTU:
644 +       if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
645 +           break;
646 +       sc->sc_if.if_mtu = ifr->ifr_mtu;
647 +       break;
648 +
649 +    case SIOCGIFMTU:
650 +       ifr->ifr_mtu = sc->sc_if.if_mtu;
651 +       break;
652 +
653 +    case SIOCADDMULTI:
654 +    case SIOCDELMULTI:
655 +       if (ifr == 0) {
656 +           error = EAFNOSUPPORT;
657 +           break;
658 +       }
659 +       switch(ifr->ifr_addr.sa_family) {
660 +#ifdef INET
661 +       case AF_INET:
662 +           break;
663 +#endif
664 +#ifdef INET6
665 +       case AF_INET6:
666 +           break;
667 +#endif
668 +       default:
669 +           error = EAFNOSUPPORT;
670 +           break;
671 +       }
672 +       break;
673 +
674 +    case SIOCGPPPSTATS:
675 +       psp = &((struct ifpppstatsreq *) data)->stats;
676 +       bzero(psp, sizeof(*psp));
677 +       psp->p = sc->sc_stats;
678 +#if defined(VJC) && !defined(SL_NO_STATS)
679 +       if (sc->sc_comp) {
680 +           psp->vj.vjs_packets = sc->sc_comp->sls_packets;
681 +           psp->vj.vjs_compressed = sc->sc_comp->sls_compressed;
682 +           psp->vj.vjs_searches = sc->sc_comp->sls_searches;
683 +           psp->vj.vjs_misses = sc->sc_comp->sls_misses;
684 +           psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin;
685 +           psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin;
686 +           psp->vj.vjs_errorin = sc->sc_comp->sls_errorin;
687 +           psp->vj.vjs_tossed = sc->sc_comp->sls_tossed;
688 +       }
689 +#endif /* VJC */
690 +       break;
691 +
692 +#ifdef PPP_COMPRESS
693 +    case SIOCGPPPCSTATS:
694 +       pcp = &((struct ifpppcstatsreq *) data)->stats;
695 +       bzero(pcp, sizeof(*pcp));
696 +       if (sc->sc_xc_state != NULL)
697 +           (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c);
698 +       if (sc->sc_rc_state != NULL)
699 +           (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d);
700 +       break;
701 +#endif /* PPP_COMPRESS */
702 +
703 +    default:
704 +       error = EINVAL;
705 +    }
706 +    splx(s);
707 +    return (error);
708 +}
709 +
710 +/*
711 + * Queue a packet.  Start transmission if not active.
712 + * Packet is placed in Information field of PPP frame.
713 + */
714 +int
715 +pppoutput(ifp, m0, dst, rtp)
716 +    struct ifnet *ifp;
717 +    struct mbuf *m0;
718 +    struct sockaddr *dst;
719 +    struct rtentry *rtp;
720 +{
721 +    register struct ppp_softc *sc = ifp->if_softc;
722 +    int protocol, address, control;
723 +    u_char *cp;
724 +    int s, error;
725 +    struct ip *ip;
726 +    struct ifqueue *ifq;
727 +    enum NPmode mode;
728 +    int len;
729 +    struct mbuf *m;
730 +
731 +    if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
732 +       || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
733 +       error = ENETDOWN;       /* sort of */
734 +       goto bad;
735 +    }
736 +
737 +    /*
738 +     * Compute PPP header.
739 +     */
740 +    m0->m_flags &= ~M_HIGHPRI;
741 +    switch (dst->sa_family) {
742 +#ifdef INET
743 +    case AF_INET:
744 +       address = PPP_ALLSTATIONS;
745 +       control = PPP_UI;
746 +       protocol = PPP_IP;
747 +       mode = sc->sc_npmode[NP_IP];
748 +
749 +       /*
750 +        * If this packet has the "low delay" bit set in the IP header,
751 +        * put it on the fastq instead.
752 +        */
753 +       ip = mtod(m0, struct ip *);
754 +       if (ip->ip_tos & IPTOS_LOWDELAY)
755 +           m0->m_flags |= M_HIGHPRI;
756 +       break;
757 +#endif
758 +#ifdef INET6
759 +    case AF_INET6:
760 +       address = PPP_ALLSTATIONS;      /*XXX*/
761 +       control = PPP_UI;               /*XXX*/
762 +       protocol = PPP_IPV6;
763 +       mode = sc->sc_npmode[NP_IPV6];
764 +
765 +#if 0  /* XXX flowinfo/traffic class, maybe? */
766 +       /*
767 +        * If this packet has the "low delay" bit set in the IP header,
768 +        * put it on the fastq instead.
769 +        */
770 +       ip = mtod(m0, struct ip *);
771 +       if (ip->ip_tos & IPTOS_LOWDELAY)
772 +           m0->m_flags |= M_HIGHPRI;
773 +       break;
774 +#endif
775 +#endif
776 +    case AF_UNSPEC:
777 +       address = PPP_ADDRESS(dst->sa_data);
778 +       control = PPP_CONTROL(dst->sa_data);
779 +       protocol = PPP_PROTOCOL(dst->sa_data);
780 +       mode = NPMODE_PASS;
781 +       break;
782 +    default:
783 +       printf("%s: af%d not supported\n", ifp->if_xname, dst->sa_family);
784 +       error = EAFNOSUPPORT;
785 +       goto bad;
786 +    }
787 +
788 +    /*
789 +     * Drop this packet, or return an error, if necessary.
790 +     */
791 +    if (mode == NPMODE_ERROR) {
792 +       error = ENETDOWN;
793 +       goto bad;
794 +    }
795 +    if (mode == NPMODE_DROP) {
796 +       error = 0;
797 +       goto bad;
798 +    }
799 +
800 +    /*
801 +     * Add PPP header.  If no space in first mbuf, allocate another.
802 +     * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
803 +     */
804 +    if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
805 +       m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
806 +       if (m0 == 0) {
807 +           error = ENOBUFS;
808 +           goto bad;
809 +       }
810 +       m0->m_len = 0;
811 +    } else
812 +       m0->m_data -= PPP_HDRLEN;
813 +
814 +    cp = mtod(m0, u_char *);
815 +    *cp++ = address;
816 +    *cp++ = control;
817 +    *cp++ = protocol >> 8;
818 +    *cp++ = protocol & 0xff;
819 +    m0->m_len += PPP_HDRLEN;
820 +
821 +    len = 0;
822 +    for (m = m0; m != 0; m = m->m_next)
823 +       len += m->m_len;
824 +
825 +    if (sc->sc_flags & SC_LOG_OUTPKT) {
826 +       printf("%s output: ", ifp->if_xname);
827 +       pppdumpm(m0);
828 +    }
829 +
830 +    if ((protocol & 0x8000) == 0) {
831 +#ifdef PPP_FILTER
832 +       /*
833 +        * Apply the pass and active filters to the packet,
834 +        * but only if it is a data packet.
835 +        */
836 +       if (sc->sc_pass_filt_out.bf_insns != 0
837 +           && bpf_filter(sc->sc_pass_filt_out.bf_insns, (u_char *) m0,
838 +                         len, 0) == 0) {
839 +           error = 0;          /* drop this packet */
840 +           goto bad;
841 +       }
842 +
843 +       /*
844 +        * Update the time we sent the most recent packet.
845 +        */
846 +       if (sc->sc_active_filt_out.bf_insns == 0
847 +           || bpf_filter(sc->sc_active_filt_out.bf_insns, (u_char *) m0,
848 +                         len, 0))
849 +           sc->sc_last_sent = time.tv_sec;
850 +#else
851 +       /*
852 +        * Update the time we sent the most recent packet.
853 +        */
854 +       sc->sc_last_sent = time.tv_sec;
855 +#endif /* PPP_FILTER */
856 +    }
857 +
858 +#if NBPFILTER > 0
859 +    /*
860 +     * See if bpf wants to look at the packet.
861 +     */
862 +    if (sc->sc_bpf)
863 +       bpf_mtap(sc->sc_bpf, m0);
864 +#endif
865 +
866 +    /*
867 +     * Put the packet on the appropriate queue.
868 +     */
869 +    s = splimp();
870 +    if (mode == NPMODE_QUEUE) {
871 +       /* XXX we should limit the number of packets on this queue */
872 +       *sc->sc_npqtail = m0;
873 +       m0->m_nextpkt = NULL;
874 +       sc->sc_npqtail = &m0->m_nextpkt;
875 +    } else {
876 +       ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd;
877 +       if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
878 +           IF_DROP(ifq);
879 +           splx(s);
880 +           sc->sc_if.if_oerrors++;
881 +           sc->sc_stats.ppp_oerrors++;
882 +           error = ENOBUFS;
883 +           goto bad;
884 +       }
885 +       IF_ENQUEUE(ifq, m0);
886 +       ppp_restart(sc);
887 +    }
888 +    ifp->if_lastchange = time;
889 +    ifp->if_opackets++;
890 +    ifp->if_obytes += len;
891 +
892 +    splx(s);
893 +    return (0);
894 +
895 +bad:
896 +    m_freem(m0);
897 +    return (error);
898 +}
899 +
900 +/*
901 + * After a change in the NPmode for some NP, move packets from the
902 + * npqueue to the send queue or the fast queue as appropriate.
903 + * Should be called at splimp, since we muck with the queues.
904 + */
905 +static void
906 +ppp_requeue(sc)
907 +    struct ppp_softc *sc;
908 +{
909 +    struct mbuf *m, **mpp;
910 +    struct ifqueue *ifq;
911 +    enum NPmode mode;
912 +
913 +    for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
914 +       switch (PPP_PROTOCOL(mtod(m, u_char *))) {
915 +       case PPP_IP:
916 +           mode = sc->sc_npmode[NP_IP];
917 +           break;
918 +       case PPP_IPV6:
919 +           mode = sc->sc_npmode[NP_IPV6];
920 +           break;
921 +       default:
922 +           mode = NPMODE_PASS;
923 +       }
924 +
925 +       switch (mode) {
926 +       case NPMODE_PASS:
927 +           /*
928 +            * This packet can now go on one of the queues to be sent.
929 +            */
930 +           *mpp = m->m_nextpkt;
931 +           m->m_nextpkt = NULL;
932 +           ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd;
933 +           if (IF_QFULL(ifq)) {
934 +               IF_DROP(ifq);
935 +               sc->sc_if.if_oerrors++;
936 +               sc->sc_stats.ppp_oerrors++;
937 +           } else
938 +               IF_ENQUEUE(ifq, m);
939 +           break;
940 +
941 +       case NPMODE_DROP:
942 +       case NPMODE_ERROR:
943 +           *mpp = m->m_nextpkt;
944 +           m_freem(m);
945 +           break;
946 +
947 +       case NPMODE_QUEUE:
948 +           mpp = &m->m_nextpkt;
949 +           break;
950 +       }
951 +    }
952 +    sc->sc_npqtail = mpp;
953 +}
954 +
955 +/*
956 + * Transmitter has finished outputting some stuff;
957 + * remember to call sc->sc_start later at splsoftnet.
958 + */
959 +void
960 +ppp_restart(sc)
961 +    struct ppp_softc *sc;
962 +{
963 +    int s = splimp();
964 +
965 +    sc->sc_flags &= ~SC_TBUSY;
966 +    schednetisr(NETISR_PPP);
967 +    splx(s);
968 +}
969 +
970 +/*
971 + * Get a packet to send.  This procedure is intended to be called at
972 + * splsoftnet, since it may involve time-consuming operations such as
973 + * applying VJ compression, packet compression, address/control and/or
974 + * protocol field compression to the packet.
975 + */
976 +struct mbuf *
977 +ppp_dequeue(sc)
978 +    struct ppp_softc *sc;
979 +{
980 +    struct mbuf *m, *mp;
981 +    u_char *cp;
982 +    int address, control, protocol;
983 +    int s;
984 +
985 +    /*
986 +     * Grab a packet to send: first try the fast queue, then the
987 +     * normal queue.
988 +     */
989 +    s = splimp();    
990 +    IF_DEQUEUE(&sc->sc_fastq, m);
991 +    if (m == NULL)
992 +       IF_DEQUEUE(&sc->sc_if.if_snd, m);
993 +    splx(s);
994 +    
995 +    if (m == NULL)
996 +       return NULL;
997 +
998 +    ++sc->sc_stats.ppp_opackets;
999 +
1000 +    /*
1001 +     * Extract the ppp header of the new packet.
1002 +     * The ppp header will be in one mbuf.
1003 +     */
1004 +    cp = mtod(m, u_char *);
1005 +    address = PPP_ADDRESS(cp);
1006 +    control = PPP_CONTROL(cp);
1007 +    protocol = PPP_PROTOCOL(cp);
1008 +
1009 +    switch (protocol) {
1010 +    case PPP_IP:
1011 +#ifdef VJC
1012 +       /*
1013 +        * If the packet is a TCP/IP packet, see if we can compress it.
1014 +        */
1015 +       if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) {
1016 +           struct ip *ip;
1017 +           int type;
1018 +
1019 +           mp = m;
1020 +           ip = (struct ip *) (cp + PPP_HDRLEN);
1021 +           if (mp->m_len <= PPP_HDRLEN) {
1022 +               mp = mp->m_next;
1023 +               if (mp == NULL)
1024 +                   break;
1025 +               ip = mtod(mp, struct ip *);
1026 +           }
1027 +           /* this code assumes the IP/TCP header is in one non-shared mbuf */
1028 +           if (ip->ip_p == IPPROTO_TCP) {
1029 +               type = sl_compress_tcp(mp, ip, sc->sc_comp,
1030 +                                      !(sc->sc_flags & SC_NO_TCP_CCID));
1031 +               switch (type) {
1032 +               case TYPE_UNCOMPRESSED_TCP:
1033 +                   protocol = PPP_VJC_UNCOMP;
1034 +                   break;
1035 +               case TYPE_COMPRESSED_TCP:
1036 +                   protocol = PPP_VJC_COMP;
1037 +                   cp = mtod(m, u_char *);
1038 +                   cp[0] = address;    /* header has moved */
1039 +                   cp[1] = control;
1040 +                   cp[2] = 0;
1041 +                   break;
1042 +               }
1043 +               cp[3] = protocol;       /* update protocol in PPP header */
1044 +           }
1045 +       }
1046 +#endif /* VJC */
1047 +       break;
1048 +
1049 +#ifdef PPP_COMPRESS
1050 +    case PPP_CCP:
1051 +       ppp_ccp(sc, m, 0);
1052 +       break;
1053 +#endif /* PPP_COMPRESS */
1054 +    }
1055 +
1056 +#ifdef PPP_COMPRESS
1057 +    if (protocol != PPP_LCP && protocol != PPP_CCP
1058 +       && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
1059 +       struct mbuf *mcomp = NULL;
1060 +       int slen, clen;
1061 +
1062 +       slen = 0;
1063 +       for (mp = m; mp != NULL; mp = mp->m_next)
1064 +           slen += mp->m_len;
1065 +       clen = (*sc->sc_xcomp->compress)
1066 +           (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN);
1067 +       if (mcomp != NULL) {
1068 +           if (sc->sc_flags & SC_CCP_UP) {
1069 +               /* Send the compressed packet instead of the original. */
1070 +               m_freem(m);
1071 +               m = mcomp;
1072 +               cp = mtod(m, u_char *);
1073 +               protocol = cp[3];
1074 +           } else {
1075 +               /* Can't transmit compressed packets until CCP is up. */
1076 +               m_freem(mcomp);
1077 +           }
1078 +       }
1079 +    }
1080 +#endif /* PPP_COMPRESS */
1081 +
1082 +    /*
1083 +     * Compress the address/control and protocol, if possible.
1084 +     */
1085 +    if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
1086 +       control == PPP_UI && protocol != PPP_ALLSTATIONS &&
1087 +       protocol != PPP_LCP) {
1088 +       /* can compress address/control */
1089 +       m->m_data += 2;
1090 +       m->m_len -= 2;
1091 +    }
1092 +    if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
1093 +       /* can compress protocol */
1094 +       if (mtod(m, u_char *) == cp) {
1095 +           cp[2] = cp[1];      /* move address/control up */
1096 +           cp[1] = cp[0];
1097 +       }
1098 +       ++m->m_data;
1099 +       --m->m_len;
1100 +    }
1101 +
1102 +    return m;
1103 +}
1104 +
1105 +/*
1106 + * Software interrupt routine, called at splsoftnet.
1107 + */
1108 +void
1109 +pppintr()
1110 +{
1111 +    struct ppp_softc *sc;
1112 +    int i, s, s2;
1113 +    struct mbuf *m;
1114 +
1115 +    sc = ppp_softc;
1116 +    s = splsoftnet();
1117 +    for (i = 0; i < NPPP; ++i, ++sc) {
1118 +       if (!(sc->sc_flags & SC_TBUSY)
1119 +           && (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head
1120 +               || sc->sc_outm)) {
1121 +           s2 = splimp();
1122 +           sc->sc_flags |= SC_TBUSY;
1123 +           splx(s2);
1124 +           (*sc->sc_start)(sc);
1125 +       }
1126 +       for (;;) {
1127 +           s2 = splimp();
1128 +           IF_DEQUEUE(&sc->sc_rawq, m);
1129 +           splx(s2);
1130 +           if (m == NULL)
1131 +               break;
1132 +           ppp_inproc(sc, m);
1133 +       }
1134 +    }
1135 +    splx(s);
1136 +}
1137 +
1138 +#ifdef PPP_COMPRESS
1139 +/*
1140 + * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
1141 + * 0 if it is about to be transmitted.
1142 + */
1143 +static void
1144 +ppp_ccp(sc, m, rcvd)
1145 +    struct ppp_softc *sc;
1146 +    struct mbuf *m;
1147 +    int rcvd;
1148 +{
1149 +    u_char *dp, *ep;
1150 +    struct mbuf *mp;
1151 +    int slen, s;
1152 +
1153 +    /*
1154 +     * Get a pointer to the data after the PPP header.
1155 +     */
1156 +    if (m->m_len <= PPP_HDRLEN) {
1157 +       mp = m->m_next;
1158 +       if (mp == NULL)
1159 +           return;
1160 +       dp = (mp != NULL)? mtod(mp, u_char *): NULL;
1161 +    } else {
1162 +       mp = m;
1163 +       dp = mtod(mp, u_char *) + PPP_HDRLEN;
1164 +    }
1165 +
1166 +    ep = mtod(mp, u_char *) + mp->m_len;
1167 +    if (dp + CCP_HDRLEN > ep)
1168 +       return;
1169 +    slen = CCP_LENGTH(dp);
1170 +    if (dp + slen > ep) {
1171 +       if (sc->sc_flags & SC_DEBUG)
1172 +           printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n",
1173 +               dp, slen, mtod(mp, u_char *), mp->m_len);
1174 +       return;
1175 +    }
1176 +
1177 +    switch (CCP_CODE(dp)) {
1178 +    case CCP_CONFREQ:
1179 +    case CCP_TERMREQ:
1180 +    case CCP_TERMACK:
1181 +       /* CCP must be going down - disable compression */
1182 +       if (sc->sc_flags & SC_CCP_UP) {
1183 +           s = splimp();
1184 +           sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
1185 +           splx(s);
1186 +       }
1187 +       break;
1188 +
1189 +    case CCP_CONFACK:
1190 +       if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP)
1191 +           && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
1192 +           && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
1193 +           if (!rcvd) {
1194 +               /* we're agreeing to send compressed packets. */
1195 +               if (sc->sc_xc_state != NULL
1196 +                   && (*sc->sc_xcomp->comp_init)
1197 +                       (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
1198 +                        sc->sc_unit, 0, sc->sc_flags & SC_DEBUG)) {
1199 +                   s = splimp();
1200 +                   sc->sc_flags |= SC_COMP_RUN;
1201 +                   splx(s);
1202 +               }
1203 +           } else {
1204 +               /* peer is agreeing to send compressed packets. */
1205 +               if (sc->sc_rc_state != NULL
1206 +                   && (*sc->sc_rcomp->decomp_init)
1207 +                       (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
1208 +                        sc->sc_unit, 0, sc->sc_mru,
1209 +                        sc->sc_flags & SC_DEBUG)) {
1210 +                   s = splimp();
1211 +                   sc->sc_flags |= SC_DECOMP_RUN;
1212 +                   sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
1213 +                   splx(s);
1214 +               }
1215 +           }
1216 +       }
1217 +       break;
1218 +
1219 +    case CCP_RESETACK:
1220 +       if (sc->sc_flags & SC_CCP_UP) {
1221 +           if (!rcvd) {
1222 +               if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN))
1223 +                   (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state);
1224 +           } else {
1225 +               if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1226 +                   (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state);
1227 +                   s = splimp();
1228 +                   sc->sc_flags &= ~SC_DC_ERROR;
1229 +                   splx(s);
1230 +               }
1231 +           }
1232 +       }
1233 +       break;
1234 +    }
1235 +}
1236 +
1237 +/*
1238 + * CCP is down; free (de)compressor state if necessary.
1239 + */
1240 +static void
1241 +ppp_ccp_closed(sc)
1242 +    struct ppp_softc *sc;
1243 +{
1244 +    if (sc->sc_xc_state) {
1245 +       (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
1246 +       sc->sc_xc_state = NULL;
1247 +    }
1248 +    if (sc->sc_rc_state) {
1249 +       (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
1250 +       sc->sc_rc_state = NULL;
1251 +    }
1252 +}
1253 +#endif /* PPP_COMPRESS */
1254 +
1255 +/*
1256 + * PPP packet input routine.
1257 + * The caller has checked and removed the FCS and has inserted
1258 + * the address/control bytes and the protocol high byte if they
1259 + * were omitted.
1260 + */
1261 +void
1262 +ppppktin(sc, m, lost)
1263 +    struct ppp_softc *sc;
1264 +    struct mbuf *m;
1265 +    int lost;
1266 +{
1267 +    int s = splimp();
1268 +
1269 +    if (lost)
1270 +       m->m_flags |= M_ERRMARK;
1271 +    IF_ENQUEUE(&sc->sc_rawq, m);
1272 +    schednetisr(NETISR_PPP);
1273 +    splx(s);
1274 +}
1275 +
1276 +/*
1277 + * Process a received PPP packet, doing decompression as necessary.
1278 + * Should be called at splsoftnet.
1279 + */
1280 +#define COMPTYPE(proto)        ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1281 +                        TYPE_UNCOMPRESSED_TCP)
1282 +
1283 +static void
1284 +ppp_inproc(sc, m)
1285 +    struct ppp_softc *sc;
1286 +    struct mbuf *m;
1287 +{
1288 +    struct ifnet *ifp = &sc->sc_if;
1289 +    struct ifqueue *inq;
1290 +    int s, ilen, xlen, proto, rv;
1291 +    u_char *cp, adrs, ctrl;
1292 +    struct mbuf *mp, *dmp = NULL;
1293 +    u_char *iphdr;
1294 +    u_int hlen;
1295 +
1296 +    sc->sc_stats.ppp_ipackets++;
1297 +
1298 +    if (sc->sc_flags & SC_LOG_INPKT) {
1299 +       ilen = 0;
1300 +       for (mp = m; mp != NULL; mp = mp->m_next)
1301 +           ilen += mp->m_len;
1302 +       printf("%s: got %d bytes\n", ifp->if_xname, ilen);
1303 +       pppdumpm(m);
1304 +    }
1305 +
1306 +    cp = mtod(m, u_char *);
1307 +    adrs = PPP_ADDRESS(cp);
1308 +    ctrl = PPP_CONTROL(cp);
1309 +    proto = PPP_PROTOCOL(cp);
1310 +
1311 +    if (m->m_flags & M_ERRMARK) {
1312 +       m->m_flags &= ~M_ERRMARK;
1313 +       s = splimp();
1314 +       sc->sc_flags |= SC_VJ_RESET;
1315 +       splx(s);
1316 +    }
1317 +
1318 +#ifdef PPP_COMPRESS
1319 +    /*
1320 +     * Decompress this packet if necessary, update the receiver's
1321 +     * dictionary, or take appropriate action on a CCP packet.
1322 +     */
1323 +    if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)
1324 +       && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
1325 +       /* decompress this packet */
1326 +       rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
1327 +       if (rv == DECOMP_OK) {
1328 +           m_freem(m);
1329 +           if (dmp == NULL) {
1330 +               /* no error, but no decompressed packet produced */
1331 +               return;
1332 +           }
1333 +           m = dmp;
1334 +           cp = mtod(m, u_char *);
1335 +           proto = PPP_PROTOCOL(cp);
1336 +
1337 +       } else {
1338 +           /*
1339 +            * An error has occurred in decompression.
1340 +            * Pass the compressed packet up to pppd, which may take
1341 +            * CCP down or issue a Reset-Req.
1342 +            */
1343 +           if (sc->sc_flags & SC_DEBUG)
1344 +               printf("%s: decompress failed %d\n", ifp->if_xname, rv);
1345 +           s = splimp();
1346 +           sc->sc_flags |= SC_VJ_RESET;
1347 +           if (rv == DECOMP_ERROR)
1348 +               sc->sc_flags |= SC_DC_ERROR;
1349 +           else
1350 +               sc->sc_flags |= SC_DC_FERROR;
1351 +           splx(s);
1352 +       }
1353 +
1354 +    } else {
1355 +       if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1356 +           (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
1357 +       }
1358 +       if (proto == PPP_CCP) {
1359 +           ppp_ccp(sc, m, 1);
1360 +       }
1361 +    }
1362 +#endif
1363 +
1364 +    ilen = 0;
1365 +    for (mp = m; mp != NULL; mp = mp->m_next)
1366 +       ilen += mp->m_len;
1367 +
1368 +#ifdef VJC
1369 +    if (sc->sc_flags & SC_VJ_RESET) {
1370 +       /*
1371 +        * If we've missed a packet, we must toss subsequent compressed
1372 +        * packets which don't have an explicit connection ID.
1373 +        */
1374 +       if (sc->sc_comp)
1375 +           sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp);
1376 +       s = splimp();
1377 +       sc->sc_flags &= ~SC_VJ_RESET;
1378 +       splx(s);
1379 +    }
1380 +
1381 +    /*
1382 +     * See if we have a VJ-compressed packet to uncompress.
1383 +     */
1384 +    if (proto == PPP_VJC_COMP) {
1385 +       if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
1386 +           goto bad;
1387 +
1388 +       xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1389 +                                     ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP,
1390 +                                     sc->sc_comp, &iphdr, &hlen);
1391 +
1392 +       if (xlen <= 0) {
1393 +           if (sc->sc_flags & SC_DEBUG)
1394 +               printf("%s: VJ uncompress failed on type comp\n",
1395 +                   ifp->if_xname);
1396 +           goto bad;
1397 +       }
1398 +
1399 +       /* Copy the PPP and IP headers into a new mbuf. */
1400 +       MGETHDR(mp, M_DONTWAIT, MT_DATA);
1401 +       if (mp == NULL)
1402 +           goto bad;
1403 +       mp->m_len = 0;
1404 +       mp->m_next = NULL;
1405 +       if (hlen + PPP_HDRLEN > MHLEN) {
1406 +           MCLGET(mp, M_DONTWAIT);
1407 +           if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
1408 +               m_freem(mp);
1409 +               goto bad;       /* lose if big headers and no clusters */
1410 +           }
1411 +       }
1412 +       cp = mtod(mp, u_char *);
1413 +       cp[0] = adrs;
1414 +       cp[1] = ctrl;
1415 +       cp[2] = 0;
1416 +       cp[3] = PPP_IP;
1417 +       proto = PPP_IP;
1418 +       bcopy(iphdr, cp + PPP_HDRLEN, hlen);
1419 +       mp->m_len = hlen + PPP_HDRLEN;
1420 +
1421 +       /*
1422 +        * Trim the PPP and VJ headers off the old mbuf
1423 +        * and stick the new and old mbufs together.
1424 +        */
1425 +       m->m_data += PPP_HDRLEN + xlen;
1426 +       m->m_len -= PPP_HDRLEN + xlen;
1427 +       if (m->m_len <= M_TRAILINGSPACE(mp)) {
1428 +           bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len);
1429 +           mp->m_len += m->m_len;
1430 +           MFREE(m, mp->m_next);
1431 +       } else
1432 +           mp->m_next = m;
1433 +       m = mp;
1434 +       ilen += hlen - xlen;
1435 +
1436 +    } else if (proto == PPP_VJC_UNCOMP) {
1437 +       if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
1438 +           goto bad;
1439 +
1440 +       xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1441 +                                     ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP,
1442 +                                     sc->sc_comp, &iphdr, &hlen);
1443 +
1444 +       if (xlen < 0) {
1445 +           if (sc->sc_flags & SC_DEBUG)
1446 +               printf("%s: VJ uncompress failed on type uncomp\n",
1447 +                   ifp->if_xname);
1448 +           goto bad;
1449 +       }
1450 +
1451 +       proto = PPP_IP;
1452 +       cp[3] = PPP_IP;
1453 +    }
1454 +#endif /* VJC */
1455 +
1456 +    /*
1457 +     * If the packet will fit in a header mbuf, don't waste a
1458 +     * whole cluster on it.
1459 +     */
1460 +    if (ilen <= MHLEN && M_IS_CLUSTER(m)) {
1461 +       MGETHDR(mp, M_DONTWAIT, MT_DATA);
1462 +       if (mp != NULL) {
1463 +           m_copydata(m, 0, ilen, mtod(mp, caddr_t));
1464 +           m_freem(m);
1465 +           m = mp;
1466 +           m->m_len = ilen;
1467 +       }
1468 +    }
1469 +    m->m_pkthdr.len = ilen;
1470 +    m->m_pkthdr.rcvif = ifp;
1471 +
1472 +    if ((proto & 0x8000) == 0) {
1473 +#ifdef PPP_FILTER
1474 +       /*
1475 +        * See whether we want to pass this packet, and
1476 +        * if it counts as link activity.
1477 +        */
1478 +       if (sc->sc_pass_filt_in.bf_insns != 0
1479 +           && bpf_filter(sc->sc_pass_filt_in.bf_insns, (u_char *) m,
1480 +                         ilen, 0) == 0) {
1481 +           /* drop this packet */
1482 +           m_freem(m);
1483 +           return;
1484 +       }
1485 +       if (sc->sc_active_filt_in.bf_insns == 0
1486 +           || bpf_filter(sc->sc_active_filt_in.bf_insns, (u_char *) m,
1487 +                         ilen, 0))
1488 +           sc->sc_last_recv = time.tv_sec;
1489 +#else
1490 +       /*
1491 +        * Record the time that we received this packet.
1492 +        */
1493 +       sc->sc_last_recv = time.tv_sec;
1494 +#endif /* PPP_FILTER */
1495 +    }
1496 +
1497 +#if NBPFILTER > 0
1498 +    /* See if bpf wants to look at the packet. */
1499 +    if (sc->sc_bpf)
1500 +       bpf_mtap(sc->sc_bpf, m);
1501 +#endif
1502 +
1503 +    rv = 0;
1504 +    switch (proto) {
1505 +#ifdef INET
1506 +    case PPP_IP:
1507 +       /*
1508 +        * IP packet - take off the ppp header and pass it up to IP.
1509 +        */
1510 +       if ((ifp->if_flags & IFF_UP) == 0
1511 +           || sc->sc_npmode[NP_IP] != NPMODE_PASS) {
1512 +           /* interface is down - drop the packet. */
1513 +           m_freem(m);
1514 +           return;
1515 +       }
1516 +       m->m_pkthdr.len -= PPP_HDRLEN;
1517 +       m->m_data += PPP_HDRLEN;
1518 +       m->m_len -= PPP_HDRLEN;
1519 +#ifdef GATEWAY
1520 +       if (ipflow_fastforward(m))
1521 +               return;
1522 +#endif
1523 +       schednetisr(NETISR_IP);
1524 +       inq = &ipintrq;
1525 +       break;
1526 +#endif
1527 +
1528 +#ifdef INET6
1529 +    case PPP_IPV6:
1530 +       /*
1531 +        * IPv6 packet - take off the ppp header and pass it up to IPv6.
1532 +        */
1533 +       if ((ifp->if_flags & IFF_UP) == 0
1534 +           || sc->sc_npmode[NP_IPV6] != NPMODE_PASS) {
1535 +           /* interface is down - drop the packet. */
1536 +           m_freem(m);
1537 +           return;
1538 +       }
1539 +       m->m_pkthdr.len -= PPP_HDRLEN;
1540 +       m->m_data += PPP_HDRLEN;
1541 +       m->m_len -= PPP_HDRLEN;
1542 +       schednetisr(NETISR_IPV6);
1543 +       inq = &ip6intrq;
1544 +       break;
1545 +#endif
1546 +
1547 +    default:
1548 +       /*
1549 +        * Some other protocol - place on input queue for read().
1550 +        */
1551 +       inq = &sc->sc_inq;
1552 +       rv = 1;
1553 +       break;
1554 +    }
1555 +
1556 +    /*
1557 +     * Put the packet on the appropriate input queue.
1558 +     */
1559 +    s = splimp();
1560 +    if (IF_QFULL(inq)) {
1561 +       IF_DROP(inq);
1562 +       splx(s);
1563 +       if (sc->sc_flags & SC_DEBUG)
1564 +           printf("%s: input queue full\n", ifp->if_xname);
1565 +       ifp->if_iqdrops++;
1566 +       goto bad;
1567 +    }
1568 +    IF_ENQUEUE(inq, m);
1569 +    splx(s);
1570 +    ifp->if_ipackets++;
1571 +    ifp->if_ibytes += ilen;
1572 +    ifp->if_lastchange = time;
1573 +
1574 +    if (rv)
1575 +       (*sc->sc_ctlp)(sc);
1576 +
1577 +    return;
1578 +
1579 + bad:
1580 +    m_freem(m);
1581 +    sc->sc_if.if_ierrors++;
1582 +    sc->sc_stats.ppp_ierrors++;
1583 +}
1584 +
1585 +#define MAX_DUMP_BYTES 128
1586 +
1587 +static void
1588 +pppdumpm(m0)
1589 +    struct mbuf *m0;
1590 +{
1591 +    char buf[3*MAX_DUMP_BYTES+4];
1592 +    char *bp = buf;
1593 +    struct mbuf *m;
1594 +    static char digits[] = "0123456789abcdef";
1595 +
1596 +    for (m = m0; m; m = m->m_next) {
1597 +       int l = m->m_len;
1598 +       u_char *rptr = (u_char *)m->m_data;
1599 +
1600 +       while (l--) {
1601 +           if (bp > buf + sizeof(buf) - 4)
1602 +               goto done;
1603 +           *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1604 +           *bp++ = digits[*rptr++ & 0xf];
1605 +       }
1606 +
1607 +       if (m->m_next) {
1608 +           if (bp > buf + sizeof(buf) - 3)
1609 +               goto done;
1610 +           *bp++ = '|';
1611 +       } else
1612 +           *bp++ = ' ';
1613 +    }
1614 +done:
1615 +    if (m)
1616 +       *bp++ = '>';
1617 +    *bp = 0;
1618 +    printf("%s\n", buf);
1619 +}
1620 +
1621 +#endif /* NPPP > 0 */