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