1 /* $OpenBSD: if_pppx.c,v 1.133 2024/12/30 02:46:00 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*-
21 * Copyright (c) 2009 Internet Initiative Japan Inc.
22 * All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 */
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/buf.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/device.h>
51 #include <sys/conf.h>
52 #include <sys/queue.h>
53 #include <sys/pool.h>
54 #include <sys/mbuf.h>
55 #include <sys/errno.h>
56 #include <sys/socket.h>
57 #include <sys/ioctl.h>
58 #include <sys/vnode.h>
59 #include <sys/event.h>
60 #include <sys/mutex.h>
61 #include <sys/refcnt.h>
62
63 #include <net/if.h>
64 #include <net/if_types.h>
65 #include <netinet/in.h>
66 #include <netinet/if_ether.h>
67 #include <net/if_dl.h>
68
69 #include <netinet/in_var.h>
70 #include <netinet/ip.h>
71 #include <netinet/ip_var.h>
72
73 #ifdef INET6
74 #include <netinet6/in6_var.h>
75 #include <netinet/ip6.h>
76 #include <netinet6/nd6.h>
77 #endif /* INET6 */
78
79 #include "bpfilter.h"
80 #if NBPFILTER > 0
81 #include <net/bpf.h>
82 #endif
83
84 #include "pf.h"
85 #if NPF > 0
86 #include <net/pfvar.h>
87 #endif
88
89 #include <net/ppp_defs.h>
90 #include <net/ppp-comp.h>
91 #include <crypto/arc4.h>
92
93 #ifdef PIPEX
94 #include <net/radix.h>
95 #include <net/pipex.h>
96 #include <net/pipex_local.h>
97 #else
98 #error PIPEX option not enabled
99 #endif
100
101 #ifdef PPPX_DEBUG
102 #define PPPX_D_INIT (1<<0)
103
104 int pppxdebug = 0;
105
106 #define DPRINTF(_m, _p...) do { \
107 if (ISSET(pppxdebug, (_m))) \
108 printf(_p); \
109 } while (0)
110 #else
111 #define DPRINTF(_m, _p...) /* _m, _p */
112 #endif
113
114
115 struct pppx_if;
116
117 /*
118 * Locks used to protect struct members and global data
119 * I immutable after creation
120 * K kernel lock
121 * N net lock
122 * m pxd_mtx
123 */
124
125 struct pppx_dev {
126 LIST_ENTRY(pppx_dev) pxd_entry; /* [K] */
127 int pxd_unit; /* [I] */
128
129 /* kq shizz */
130 struct mutex pxd_mtx;
131 struct klist pxd_rklist; /* [m] */
132 struct klist pxd_wklist; /* [m] */
133
134 /* queue of packets for userland to service - protected by splnet */
135 struct mbuf_queue pxd_svcq;
136 int pxd_waiting; /* [N] */
137 LIST_HEAD(,pppx_if) pxd_pxis; /* [K] */
138 };
139
140 LIST_HEAD(, pppx_dev) pppx_devs =
141 LIST_HEAD_INITIALIZER(pppx_devs); /* [K] */
142 struct pool pppx_if_pl;
143
144 struct pppx_dev *pppx_dev_lookup(dev_t);
145 struct pppx_dev *pppx_dev2pxd(dev_t);
146
147 struct pppx_if_key {
148 int pxik_session_id; /* [I] */
149 int pxik_protocol; /* [I] */
150 };
151
152 struct pppx_if {
153 struct pppx_if_key pxi_key; /* [I] must be first
154 in the struct */
155 struct refcnt pxi_refcnt;
156
157 RBT_ENTRY(pppx_if) pxi_entry; /* [K] */
158 LIST_ENTRY(pppx_if) pxi_list; /* [K] */
159
160 int pxi_ready; /* [K] */
161
162 int pxi_unit; /* [I] */
163 struct ifnet pxi_if;
164 struct pppx_dev *pxi_dev; /* [I] */
165 struct pipex_session *pxi_session; /* [I] */
166 };
167
168 static inline int
pppx_if_cmp(const struct pppx_if * a,const struct pppx_if * b)169 pppx_if_cmp(const struct pppx_if *a, const struct pppx_if *b)
170 {
171 return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key));
172 }
173
174 RBT_HEAD(pppx_ifs, pppx_if) pppx_ifs = RBT_INITIALIZER(&pppx_ifs); /* [N] */
175 RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
176
177 int pppx_if_next_unit(void);
178 struct pppx_if *pppx_if_find_locked(struct pppx_dev *, int, int);
179 static inline struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
180 static inline void pppx_if_rele(struct pppx_if *);
181 int pppx_add_session(struct pppx_dev *,
182 struct pipex_session_req *);
183 int pppx_del_session(struct pppx_dev *,
184 struct pipex_session_close_req *);
185 int pppx_set_session_descr(struct pppx_dev *,
186 struct pipex_session_descr_req *);
187
188 void pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
189 void pppx_if_qstart(struct ifqueue *);
190 int pppx_if_output(struct ifnet *, struct mbuf *,
191 struct sockaddr *, struct rtentry *);
192 int pppx_if_ioctl(struct ifnet *, u_long, caddr_t);
193
194
195 void pppxattach(int);
196
197 void filt_pppx_rdetach(struct knote *);
198 int filt_pppx_read(struct knote *, long);
199 int filt_pppx_modify(struct kevent *, struct knote *);
200 int filt_pppx_process(struct knote *, struct kevent *);
201
202 const struct filterops pppx_rd_filtops = {
203 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
204 .f_attach = NULL,
205 .f_detach = filt_pppx_rdetach,
206 .f_event = filt_pppx_read,
207 .f_modify = filt_pppx_modify,
208 .f_process = filt_pppx_process,
209 };
210
211 void filt_pppx_wdetach(struct knote *);
212 int filt_pppx_write(struct knote *, long);
213
214 const struct filterops pppx_wr_filtops = {
215 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
216 .f_attach = NULL,
217 .f_detach = filt_pppx_wdetach,
218 .f_event = filt_pppx_write,
219 .f_modify = filt_pppx_modify,
220 .f_process = filt_pppx_process,
221 };
222
223 struct pppx_dev *
pppx_dev_lookup(dev_t dev)224 pppx_dev_lookup(dev_t dev)
225 {
226 struct pppx_dev *pxd;
227 int unit = minor(dev);
228
229 LIST_FOREACH(pxd, &pppx_devs, pxd_entry) {
230 if (pxd->pxd_unit == unit)
231 return (pxd);
232 }
233
234 return (NULL);
235 }
236
237 struct pppx_dev *
pppx_dev2pxd(dev_t dev)238 pppx_dev2pxd(dev_t dev)
239 {
240 struct pppx_dev *pxd;
241
242 pxd = pppx_dev_lookup(dev);
243
244 return (pxd);
245 }
246
247 void
pppxattach(int n)248 pppxattach(int n)
249 {
250 pool_init(&pppx_if_pl, sizeof(struct pppx_if), 0, IPL_NONE,
251 PR_WAITOK, "pppxif", NULL);
252 pipex_init();
253 }
254
255 int
pppxopen(dev_t dev,int flags,int mode,struct proc * p)256 pppxopen(dev_t dev, int flags, int mode, struct proc *p)
257 {
258 struct pppx_dev *pxd;
259
260 pxd = malloc(sizeof(*pxd), M_DEVBUF, M_WAITOK | M_ZERO);
261 if (pppx_dev_lookup(dev) != NULL) {
262 free(pxd, M_DEVBUF, sizeof(*pxd));
263 return (EBUSY);
264 }
265
266 pxd->pxd_unit = minor(dev);
267 mtx_init(&pxd->pxd_mtx, IPL_NET);
268 klist_init_mutex(&pxd->pxd_rklist, &pxd->pxd_mtx);
269 klist_init_mutex(&pxd->pxd_wklist, &pxd->pxd_mtx);
270 LIST_INIT(&pxd->pxd_pxis);
271
272 mq_init(&pxd->pxd_svcq, 128, IPL_NET);
273 LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry);
274
275 return 0;
276 }
277
278 int
pppxread(dev_t dev,struct uio * uio,int ioflag)279 pppxread(dev_t dev, struct uio *uio, int ioflag)
280 {
281 struct pppx_dev *pxd = pppx_dev2pxd(dev);
282 struct mbuf *m, *m0;
283 int error = 0;
284 size_t len;
285
286 if (!pxd)
287 return (ENXIO);
288
289 while ((m0 = mq_dequeue(&pxd->pxd_svcq)) == NULL) {
290 if (ISSET(ioflag, IO_NDELAY))
291 return (EWOULDBLOCK);
292
293 NET_LOCK();
294 pxd->pxd_waiting = 1;
295 error = rwsleep_nsec(pxd, &netlock,
296 (PZERO + 1)|PCATCH, "pppxread", INFSLP);
297 NET_UNLOCK();
298 if (error != 0) {
299 return (error);
300 }
301 }
302
303 while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
304 len = ulmin(uio->uio_resid, m0->m_len);
305 if (len != 0)
306 error = uiomove(mtod(m0, caddr_t), len, uio);
307 m = m_free(m0);
308 m0 = m;
309 }
310
311 m_freem(m0);
312
313 return (error);
314 }
315
316 int
pppxwrite(dev_t dev,struct uio * uio,int ioflag)317 pppxwrite(dev_t dev, struct uio *uio, int ioflag)
318 {
319 struct pppx_dev *pxd = pppx_dev2pxd(dev);
320 struct pppx_hdr *th;
321 struct pppx_if *pxi;
322 uint32_t proto;
323 struct mbuf *top, **mp, *m;
324 int tlen;
325 int error = 0;
326 size_t mlen;
327
328 if (uio->uio_resid < sizeof(*th) + sizeof(uint32_t) ||
329 uio->uio_resid > MCLBYTES)
330 return (EMSGSIZE);
331
332 tlen = uio->uio_resid;
333
334 MGETHDR(m, M_DONTWAIT, MT_DATA);
335 if (m == NULL)
336 return (ENOBUFS);
337 mlen = MHLEN;
338 if (uio->uio_resid > MHLEN) {
339 MCLGET(m, M_DONTWAIT);
340 if (!(m->m_flags & M_EXT)) {
341 m_free(m);
342 return (ENOBUFS);
343 }
344 mlen = MCLBYTES;
345 }
346
347 top = NULL;
348 mp = ⊤
349
350 while (error == 0 && uio->uio_resid > 0) {
351 m->m_len = ulmin(mlen, uio->uio_resid);
352 error = uiomove(mtod (m, caddr_t), m->m_len, uio);
353 *mp = m;
354 mp = &m->m_next;
355 if (error == 0 && uio->uio_resid > 0) {
356 MGET(m, M_DONTWAIT, MT_DATA);
357 if (m == NULL) {
358 error = ENOBUFS;
359 break;
360 }
361 mlen = MLEN;
362 if (uio->uio_resid >= MINCLSIZE) {
363 MCLGET(m, M_DONTWAIT);
364 if (!(m->m_flags & M_EXT)) {
365 error = ENOBUFS;
366 m_free(m);
367 break;
368 }
369 mlen = MCLBYTES;
370 }
371 }
372 }
373
374 if (error) {
375 m_freem(top);
376 return (error);
377 }
378
379 top->m_pkthdr.len = tlen;
380
381 /* Find the interface */
382 th = mtod(top, struct pppx_hdr *);
383 m_adj(top, sizeof(struct pppx_hdr));
384
385 pxi = pppx_if_find(pxd, th->pppx_id, th->pppx_proto);
386 if (pxi == NULL) {
387 m_freem(top);
388 return (EINVAL);
389 }
390 top->m_pkthdr.ph_ifidx = pxi->pxi_if.if_index;
391
392 #if NBPFILTER > 0
393 if (pxi->pxi_if.if_bpf)
394 bpf_mtap(pxi->pxi_if.if_bpf, top, BPF_DIRECTION_IN);
395 #endif
396 /* strip the tunnel header */
397 proto = ntohl(*(uint32_t *)(th + 1));
398 m_adj(top, sizeof(uint32_t));
399
400 NET_LOCK();
401
402 switch (proto) {
403 case AF_INET:
404 ipv4_input(&pxi->pxi_if, top);
405 break;
406 #ifdef INET6
407 case AF_INET6:
408 ipv6_input(&pxi->pxi_if, top);
409 break;
410 #endif
411 default:
412 m_freem(top);
413 error = EAFNOSUPPORT;
414 break;
415 }
416
417 NET_UNLOCK();
418
419 pppx_if_rele(pxi);
420
421 return (error);
422 }
423
424 int
pppxioctl(dev_t dev,u_long cmd,caddr_t addr,int flags,struct proc * p)425 pppxioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
426 {
427 struct pppx_dev *pxd = pppx_dev2pxd(dev);
428 int error = 0;
429
430 switch (cmd) {
431 case PIPEXASESSION:
432 error = pppx_add_session(pxd,
433 (struct pipex_session_req *)addr);
434 break;
435
436 case PIPEXDSESSION:
437 error = pppx_del_session(pxd,
438 (struct pipex_session_close_req *)addr);
439 break;
440
441 case PIPEXSIFDESCR:
442 error = pppx_set_session_descr(pxd,
443 (struct pipex_session_descr_req *)addr);
444 break;
445
446 case FIONREAD:
447 *(int *)addr = mq_hdatalen(&pxd->pxd_svcq);
448 break;
449
450 default:
451 error = pipex_ioctl(pxd, cmd, addr);
452 break;
453 }
454
455 return (error);
456 }
457
458 int
pppxkqfilter(dev_t dev,struct knote * kn)459 pppxkqfilter(dev_t dev, struct knote *kn)
460 {
461 struct pppx_dev *pxd = pppx_dev2pxd(dev);
462 struct klist *klist;
463
464 switch (kn->kn_filter) {
465 case EVFILT_READ:
466 klist = &pxd->pxd_rklist;
467 kn->kn_fop = &pppx_rd_filtops;
468 break;
469 case EVFILT_WRITE:
470 klist = &pxd->pxd_wklist;
471 kn->kn_fop = &pppx_wr_filtops;
472 break;
473 default:
474 return (EINVAL);
475 }
476
477 kn->kn_hook = pxd;
478
479 klist_insert(klist, kn);
480
481 return (0);
482 }
483
484 void
filt_pppx_rdetach(struct knote * kn)485 filt_pppx_rdetach(struct knote *kn)
486 {
487 struct pppx_dev *pxd = kn->kn_hook;
488
489 klist_remove(&pxd->pxd_rklist, kn);
490 }
491
492 int
filt_pppx_read(struct knote * kn,long hint)493 filt_pppx_read(struct knote *kn, long hint)
494 {
495 struct pppx_dev *pxd = kn->kn_hook;
496
497 MUTEX_ASSERT_LOCKED(&pxd->pxd_mtx);
498
499 kn->kn_data = mq_hdatalen(&pxd->pxd_svcq);
500
501 return (kn->kn_data > 0);
502 }
503
504 void
filt_pppx_wdetach(struct knote * kn)505 filt_pppx_wdetach(struct knote *kn)
506 {
507 struct pppx_dev *pxd = kn->kn_hook;
508
509 klist_remove(&pxd->pxd_wklist, kn);
510 }
511
512 int
filt_pppx_write(struct knote * kn,long hint)513 filt_pppx_write(struct knote *kn, long hint)
514 {
515 /* We're always ready to accept a write. */
516 return (1);
517 }
518
519 int
filt_pppx_modify(struct kevent * kev,struct knote * kn)520 filt_pppx_modify(struct kevent *kev, struct knote *kn)
521 {
522 struct pppx_dev *pxd = kn->kn_hook;
523 int active;
524
525 mtx_enter(&pxd->pxd_mtx);
526 active = knote_modify(kev, kn);
527 mtx_leave(&pxd->pxd_mtx);
528
529 return (active);
530 }
531
532 int
filt_pppx_process(struct knote * kn,struct kevent * kev)533 filt_pppx_process(struct knote *kn, struct kevent *kev)
534 {
535 struct pppx_dev *pxd = kn->kn_hook;
536 int active;
537
538 mtx_enter(&pxd->pxd_mtx);
539 active = knote_process(kn, kev);
540 mtx_leave(&pxd->pxd_mtx);
541
542 return (active);
543 }
544
545 int
pppxclose(dev_t dev,int flags,int mode,struct proc * p)546 pppxclose(dev_t dev, int flags, int mode, struct proc *p)
547 {
548 struct pppx_dev *pxd;
549 struct pppx_if *pxi;
550
551 pxd = pppx_dev_lookup(dev);
552
553 while ((pxi = LIST_FIRST(&pxd->pxd_pxis))) {
554 pxi->pxi_ready = 0;
555 pppx_if_destroy(pxd, pxi);
556 }
557
558 LIST_REMOVE(pxd, pxd_entry);
559
560 mq_purge(&pxd->pxd_svcq);
561
562 klist_free(&pxd->pxd_rklist);
563 klist_free(&pxd->pxd_wklist);
564
565 free(pxd, M_DEVBUF, sizeof(*pxd));
566
567 return (0);
568 }
569
570 int
pppx_if_next_unit(void)571 pppx_if_next_unit(void)
572 {
573 struct pppx_if *pxi;
574 int unit = 0;
575
576 /* this is safe without splnet since we're not modifying it */
577 do {
578 int found = 0;
579 RBT_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
580 if (pxi->pxi_unit == unit) {
581 found = 1;
582 break;
583 }
584 }
585
586 if (found == 0)
587 break;
588 unit++;
589 } while (unit > 0);
590
591 return (unit);
592 }
593
594 struct pppx_if *
pppx_if_find_locked(struct pppx_dev * pxd,int session_id,int protocol)595 pppx_if_find_locked(struct pppx_dev *pxd, int session_id, int protocol)
596 {
597 struct pppx_if_key key;
598 struct pppx_if *pxi;
599
600 memset(&key, 0, sizeof(key));
601 key.pxik_session_id = session_id;
602 key.pxik_protocol = protocol;
603
604 pxi = RBT_FIND(pppx_ifs, &pppx_ifs, (struct pppx_if *)&key);
605 if (pxi && pxi->pxi_ready == 0)
606 pxi = NULL;
607
608 return pxi;
609 }
610
611 static inline struct pppx_if *
pppx_if_find(struct pppx_dev * pxd,int session_id,int protocol)612 pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
613 {
614 struct pppx_if *pxi;
615
616 if ((pxi = pppx_if_find_locked(pxd, session_id, protocol)))
617 refcnt_take(&pxi->pxi_refcnt);
618
619 return pxi;
620 }
621
622 static inline void
pppx_if_rele(struct pppx_if * pxi)623 pppx_if_rele(struct pppx_if *pxi)
624 {
625 refcnt_rele_wake(&pxi->pxi_refcnt);
626 }
627
628 int
pppx_add_session(struct pppx_dev * pxd,struct pipex_session_req * req)629 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
630 {
631 struct pppx_if *pxi;
632 struct pipex_session *session;
633 struct ifnet *ifp;
634 int unit, error = 0;
635 struct in_ifaddr *ia;
636 struct sockaddr_in ifaddr;
637
638 /*
639 * XXX: As long as `session' is allocated as part of a `pxi'
640 * it isn't possible to free it separately. So disallow
641 * the timeout feature until this is fixed.
642 */
643 if (req->pr_timeout_sec != 0)
644 return (EINVAL);
645
646 error = pipex_init_session(&session, req);
647 if (error)
648 return (error);
649
650 pxi = pool_get(&pppx_if_pl, PR_WAITOK | PR_ZERO);
651 ifp = &pxi->pxi_if;
652
653 pxi->pxi_session = session;
654
655 /* try to set the interface up */
656 unit = pppx_if_next_unit();
657 if (unit < 0) {
658 error = ENOMEM;
659 goto out;
660 }
661
662 refcnt_init(&pxi->pxi_refcnt);
663 pxi->pxi_unit = unit;
664 pxi->pxi_key.pxik_session_id = req->pr_session_id;
665 pxi->pxi_key.pxik_protocol = req->pr_protocol;
666 pxi->pxi_dev = pxd;
667
668 if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL) {
669 error = EADDRINUSE;
670 goto out;
671 }
672 LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
673
674 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
675 ifp->if_mtu = req->pr_peer_mru; /* XXX */
676 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
677 ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
678 ifp->if_qstart = pppx_if_qstart;
679 ifp->if_output = pppx_if_output;
680 ifp->if_ioctl = pppx_if_ioctl;
681 ifp->if_rtrequest = p2p_rtrequest;
682 ifp->if_type = IFT_PPP;
683 ifp->if_softc = pxi;
684 /* ifp->if_rdomain = req->pr_rdomain; */
685 if_counters_alloc(ifp);
686
687 if_attach(ifp);
688
689 NET_LOCK();
690 if_addgroup(ifp, "pppx");
691 if_alloc_sadl(ifp);
692 NET_UNLOCK();
693
694 #if NBPFILTER > 0
695 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
696 #endif
697
698 /* XXX ipv6 support? how does the caller indicate it wants ipv6
699 * instead of ipv4?
700 */
701 memset(&ifaddr, 0, sizeof(ifaddr));
702 ifaddr.sin_family = AF_INET;
703 ifaddr.sin_len = sizeof(ifaddr);
704 ifaddr.sin_addr = req->pr_ip_srcaddr;
705
706 ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
707 refcnt_init_trace(&ia->ia_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR);
708
709 ia->ia_addr.sin_family = AF_INET;
710 ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
711 ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
712
713 ia->ia_dstaddr.sin_family = AF_INET;
714 ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
715 ia->ia_dstaddr.sin_addr = req->pr_ip_address;
716
717 ia->ia_sockmask.sin_family = AF_INET;
718 ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
719 ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
720
721 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
722 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
723 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
724 ia->ia_ifa.ifa_ifp = ifp;
725
726 ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
727
728 NET_LOCK();
729 error = in_ifinit(ifp, ia, &ifaddr, 1);
730 if (error) {
731 printf("pppx: unable to set addresses for %s, error=%d\n",
732 ifp->if_xname, error);
733 } else {
734 if_addrhooks_run(ifp);
735 }
736 NET_UNLOCK();
737
738 error = pipex_link_session(session, ifp, pxd);
739 if (error)
740 goto detach;
741
742 NET_LOCK();
743 SET(ifp->if_flags, IFF_RUNNING);
744 NET_UNLOCK();
745 pxi->pxi_ready = 1;
746
747 return (error);
748
749 detach:
750 if_detach(ifp);
751
752 if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
753 panic("%s: inconsistent RB tree", __func__);
754 LIST_REMOVE(pxi, pxi_list);
755 out:
756 pool_put(&pppx_if_pl, pxi);
757 pipex_rele_session(session);
758
759 return (error);
760 }
761
762 int
pppx_del_session(struct pppx_dev * pxd,struct pipex_session_close_req * req)763 pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
764 {
765 struct pppx_if *pxi;
766
767 pxi = pppx_if_find_locked(pxd, req->pcr_session_id, req->pcr_protocol);
768 if (pxi == NULL)
769 return (EINVAL);
770
771 pxi->pxi_ready = 0;
772 pipex_export_session_stats(pxi->pxi_session, &req->pcr_stat);
773 pppx_if_destroy(pxd, pxi);
774 return (0);
775 }
776
777 int
pppx_set_session_descr(struct pppx_dev * pxd,struct pipex_session_descr_req * req)778 pppx_set_session_descr(struct pppx_dev *pxd,
779 struct pipex_session_descr_req *req)
780 {
781 struct pppx_if *pxi;
782
783 pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
784 if (pxi == NULL)
785 return (EINVAL);
786
787 (void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
788 strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
789
790 pppx_if_rele(pxi);
791
792 return (0);
793 }
794
795 void
pppx_if_destroy(struct pppx_dev * pxd,struct pppx_if * pxi)796 pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
797 {
798 struct ifnet *ifp;
799 struct pipex_session *session;
800
801 session = pxi->pxi_session;
802 ifp = &pxi->pxi_if;
803
804 refcnt_finalize(&pxi->pxi_refcnt, "pxifinal");
805
806 NET_LOCK();
807 CLR(ifp->if_flags, IFF_RUNNING);
808 NET_UNLOCK();
809
810 pipex_unlink_session(session);
811 if_detach(ifp);
812
813 pipex_rele_session(session);
814 if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
815 panic("%s: inconsistent RB tree", __func__);
816 LIST_REMOVE(pxi, pxi_list);
817
818 pool_put(&pppx_if_pl, pxi);
819 }
820
821 void
pppx_if_qstart(struct ifqueue * ifq)822 pppx_if_qstart(struct ifqueue *ifq)
823 {
824 struct ifnet *ifp = ifq->ifq_if;
825 struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
826 struct mbuf *m;
827 int proto;
828
829 while ((m = ifq_dequeue(ifq)) != NULL) {
830 proto = *mtod(m, int *);
831 m_adj(m, sizeof(proto));
832
833 pipex_ppp_output(m, pxi->pxi_session, proto);
834 }
835 }
836
837 int
pppx_if_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)838 pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
839 struct rtentry *rt)
840 {
841 struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
842 struct pppx_hdr *th;
843 int error = 0;
844 int pipex_enable_local, proto;
845
846 pipex_enable_local = atomic_load_int(&pipex_enable);
847
848 NET_ASSERT_LOCKED();
849
850 if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
851 m_freem(m);
852 error = ENETDOWN;
853 goto out;
854 }
855
856 #if NBPFILTER > 0
857 if (ifp->if_bpf)
858 bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
859 #endif
860 if (pipex_enable_local) {
861 switch (dst->sa_family) {
862 #ifdef INET6
863 case AF_INET6:
864 proto = PPP_IPV6;
865 break;
866 #endif
867 case AF_INET:
868 proto = PPP_IP;
869 break;
870 default:
871 m_freem(m);
872 error = EPFNOSUPPORT;
873 goto out;
874 }
875 } else
876 proto = htonl(dst->sa_family);
877
878 M_PREPEND(m, sizeof(int), M_DONTWAIT);
879 if (m == NULL) {
880 error = ENOBUFS;
881 goto out;
882 }
883 *mtod(m, int *) = proto;
884
885 if (pipex_enable_local)
886 error = if_enqueue(ifp, m);
887 else {
888 M_PREPEND(m, sizeof(struct pppx_hdr), M_DONTWAIT);
889 if (m == NULL) {
890 error = ENOBUFS;
891 goto out;
892 }
893 th = mtod(m, struct pppx_hdr *);
894 th->pppx_proto = 0; /* not used */
895 th->pppx_id = pxi->pxi_session->ppp_id;
896 error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m);
897 if (error == 0) {
898 if (pxi->pxi_dev->pxd_waiting) {
899 wakeup((caddr_t)pxi->pxi_dev);
900 pxi->pxi_dev->pxd_waiting = 0;
901 }
902 knote(&pxi->pxi_dev->pxd_rklist, 0);
903 }
904 }
905
906 out:
907 if (error)
908 counters_inc(ifp->if_counters, ifc_oerrors);
909 return (error);
910 }
911
912 int
pppx_if_ioctl(struct ifnet * ifp,u_long cmd,caddr_t addr)913 pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
914 {
915 struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
916 struct ifreq *ifr = (struct ifreq *)addr;
917 int error = 0;
918
919 switch (cmd) {
920 case SIOCSIFADDR:
921 break;
922
923 case SIOCSIFFLAGS:
924 break;
925
926 case SIOCADDMULTI:
927 case SIOCDELMULTI:
928 break;
929
930 case SIOCSIFMTU:
931 if (ifr->ifr_mtu < 512 ||
932 ifr->ifr_mtu > pxi->pxi_session->peer_mru)
933 error = EINVAL;
934 else
935 ifp->if_mtu = ifr->ifr_mtu;
936 break;
937
938 default:
939 error = ENOTTY;
940 break;
941 }
942
943 return (error);
944 }
945
946 RBT_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
947
948 /*
949 * Locks used to protect struct members and global data
950 * I immutable after creation
951 * K kernel lock
952 * N net lock
953 * m sc_mtx
954 */
955
956 struct pppac_softc {
957 struct ifnet sc_if;
958 dev_t sc_dev; /* [I] */
959 int sc_ready; /* [K] */
960 LIST_ENTRY(pppac_softc)
961 sc_entry; /* [K] */
962
963 struct mutex sc_mtx;
964 struct klist sc_rklist; /* [m] */
965 struct klist sc_wklist; /* [m] */
966
967 struct pipex_session
968 *sc_multicast_session;
969
970 struct mbuf_queue
971 sc_mq;
972 };
973
974 LIST_HEAD(pppac_list, pppac_softc); /* [K] */
975
976 static void filt_pppac_rdetach(struct knote *);
977 static int filt_pppac_read(struct knote *, long);
978 static int filt_pppac_modify(struct kevent *, struct knote *);
979 static int filt_pppac_process(struct knote *, struct kevent *);
980
981 static const struct filterops pppac_rd_filtops = {
982 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
983 .f_attach = NULL,
984 .f_detach = filt_pppac_rdetach,
985 .f_event = filt_pppac_read,
986 .f_modify = filt_pppac_modify,
987 .f_process = filt_pppac_process,
988 };
989
990 static void filt_pppac_wdetach(struct knote *);
991 static int filt_pppac_write(struct knote *, long);
992
993 static const struct filterops pppac_wr_filtops = {
994 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
995 .f_attach = NULL,
996 .f_detach = filt_pppac_wdetach,
997 .f_event = filt_pppac_write,
998 .f_modify = filt_pppac_modify,
999 .f_process = filt_pppac_process,
1000 };
1001
1002 static struct pppac_list pppac_devs = LIST_HEAD_INITIALIZER(pppac_devs);
1003
1004 static int pppac_ioctl(struct ifnet *, u_long, caddr_t);
1005
1006 static int pppac_add_session(struct pppac_softc *,
1007 struct pipex_session_req *);
1008 static int pppac_del_session(struct pppac_softc *,
1009 struct pipex_session_close_req *);
1010 static int pppac_output(struct ifnet *, struct mbuf *, struct sockaddr *,
1011 struct rtentry *);
1012 static void pppac_qstart(struct ifqueue *);
1013
1014 static inline struct pppac_softc *
pppac_lookup(dev_t dev)1015 pppac_lookup(dev_t dev)
1016 {
1017 struct pppac_softc *sc;
1018
1019 LIST_FOREACH(sc, &pppac_devs, sc_entry) {
1020 if (sc->sc_dev == dev) {
1021 if (sc->sc_ready == 0)
1022 break;
1023
1024 return (sc);
1025 }
1026 }
1027
1028 return (NULL);
1029 }
1030
1031 void
pppacattach(int n)1032 pppacattach(int n)
1033 {
1034 pipex_init(); /* to be sure, to be sure */
1035 }
1036
1037 int
pppacopen(dev_t dev,int flags,int mode,struct proc * p)1038 pppacopen(dev_t dev, int flags, int mode, struct proc *p)
1039 {
1040 struct pppac_softc *sc, *tmp;
1041 struct ifnet *ifp;
1042 struct pipex_session *session;
1043
1044 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
1045 sc->sc_dev = dev;
1046 LIST_FOREACH(tmp, &pppac_devs, sc_entry) {
1047 if (tmp->sc_dev == dev) {
1048 free(sc, M_DEVBUF, sizeof(*sc));
1049 return (EBUSY);
1050 }
1051 }
1052 LIST_INSERT_HEAD(&pppac_devs, sc, sc_entry);
1053
1054 /* virtual pipex_session entry for multicast */
1055 session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO);
1056 session->flags |= PIPEX_SFLAGS_MULTICAST;
1057 session->ownersc = sc;
1058 sc->sc_multicast_session = session;
1059
1060 mtx_init(&sc->sc_mtx, IPL_SOFTNET);
1061 klist_init_mutex(&sc->sc_rklist, &sc->sc_mtx);
1062 klist_init_mutex(&sc->sc_wklist, &sc->sc_mtx);
1063 mq_init(&sc->sc_mq, IFQ_MAXLEN, IPL_SOFTNET);
1064
1065 ifp = &sc->sc_if;
1066 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "pppac%u", minor(dev));
1067
1068 ifp->if_softc = sc;
1069 ifp->if_type = IFT_L3IPVLAN;
1070 ifp->if_hdrlen = sizeof(uint32_t); /* for BPF */
1071 ifp->if_mtu = MAXMCLBYTES - sizeof(uint32_t);
1072 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST;
1073 ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
1074 ifp->if_rtrequest = p2p_rtrequest; /* XXX */
1075 ifp->if_output = pppac_output;
1076 ifp->if_qstart = pppac_qstart;
1077 ifp->if_ioctl = pppac_ioctl;
1078
1079 if_counters_alloc(ifp);
1080 if_attach(ifp);
1081 if_alloc_sadl(ifp);
1082
1083 #if NBPFILTER > 0
1084 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
1085 #endif
1086
1087 sc->sc_ready = 1;
1088
1089 return (0);
1090 }
1091
1092 int
pppacread(dev_t dev,struct uio * uio,int ioflag)1093 pppacread(dev_t dev, struct uio *uio, int ioflag)
1094 {
1095 struct pppac_softc *sc = pppac_lookup(dev);
1096 struct ifnet *ifp = &sc->sc_if;
1097 struct mbuf *m0, *m;
1098 int error = 0;
1099 size_t len;
1100
1101 if (!ISSET(ifp->if_flags, IFF_RUNNING))
1102 return (EHOSTDOWN);
1103
1104 m0 = mq_dequeue(&sc->sc_mq);
1105 if (m0 == NULL) {
1106 if (ISSET(ioflag, IO_NDELAY))
1107 return (EWOULDBLOCK);
1108
1109 do {
1110 error = tsleep_nsec(sc, (PZERO + 1)|PCATCH,
1111 "pppacrd", INFSLP);
1112 if (error != 0)
1113 return (error);
1114
1115 m0 = mq_dequeue(&sc->sc_mq);
1116 } while (m0 == NULL);
1117 }
1118
1119 m = m0;
1120 while (uio->uio_resid > 0) {
1121 len = ulmin(uio->uio_resid, m->m_len);
1122 if (len != 0) {
1123 error = uiomove(mtod(m, caddr_t), len, uio);
1124 if (error != 0)
1125 break;
1126 }
1127
1128 m = m->m_next;
1129 if (m == NULL)
1130 break;
1131 }
1132 m_freem(m0);
1133
1134 return (error);
1135 }
1136
1137 int
pppacwrite(dev_t dev,struct uio * uio,int ioflag)1138 pppacwrite(dev_t dev, struct uio *uio, int ioflag)
1139 {
1140 struct pppac_softc *sc = pppac_lookup(dev);
1141 struct ifnet *ifp = &sc->sc_if;
1142 uint32_t proto;
1143 int error;
1144 struct mbuf *m;
1145
1146 if (!ISSET(ifp->if_flags, IFF_RUNNING))
1147 return (EHOSTDOWN);
1148
1149 if (uio->uio_resid < ifp->if_hdrlen || uio->uio_resid > MAXMCLBYTES)
1150 return (EMSGSIZE);
1151
1152 m = m_gethdr(M_DONTWAIT, MT_DATA);
1153 if (m == NULL)
1154 return (ENOMEM);
1155
1156 if (uio->uio_resid > MHLEN) {
1157 m_clget(m, M_WAITOK, uio->uio_resid);
1158 if (!ISSET(m->m_flags, M_EXT)) {
1159 m_free(m);
1160 return (ENOMEM);
1161 }
1162 }
1163
1164 m->m_pkthdr.len = m->m_len = uio->uio_resid;
1165
1166 error = uiomove(mtod(m, void *), m->m_len, uio);
1167 if (error != 0) {
1168 m_freem(m);
1169 return (error);
1170 }
1171
1172 #if NBPFILTER > 0
1173 if (ifp->if_bpf)
1174 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
1175 #endif
1176
1177 /* strip the tunnel header */
1178 proto = ntohl(*mtod(m, uint32_t *));
1179 m_adj(m, sizeof(uint32_t));
1180
1181 m->m_flags &= ~(M_MCAST|M_BCAST);
1182 m->m_pkthdr.ph_ifidx = ifp->if_index;
1183 m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
1184
1185 #if NPF > 0
1186 pf_pkt_addr_changed(m);
1187 #endif
1188
1189 counters_pkt(ifp->if_counters,
1190 ifc_ipackets, ifc_ibytes, m->m_pkthdr.len);
1191
1192 NET_LOCK();
1193
1194 switch (proto) {
1195 case AF_INET:
1196 ipv4_input(ifp, m);
1197 break;
1198 #ifdef INET6
1199 case AF_INET6:
1200 ipv6_input(ifp, m);
1201 break;
1202 #endif
1203 default:
1204 m_freem(m);
1205 error = EAFNOSUPPORT;
1206 break;
1207 }
1208
1209 NET_UNLOCK();
1210
1211 return (error);
1212 }
1213
1214 int
pppacioctl(dev_t dev,u_long cmd,caddr_t data,int flags,struct proc * p)1215 pppacioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
1216 {
1217 struct pppac_softc *sc = pppac_lookup(dev);
1218 int error = 0;
1219
1220 switch (cmd) {
1221 case FIONREAD:
1222 *(int *)data = mq_hdatalen(&sc->sc_mq);
1223 break;
1224
1225 case PIPEXASESSION:
1226 error = pppac_add_session(sc, (struct pipex_session_req *)data);
1227 break;
1228 case PIPEXDSESSION:
1229 error = pppac_del_session(sc,
1230 (struct pipex_session_close_req *)data);
1231 break;
1232 default:
1233 error = pipex_ioctl(sc, cmd, data);
1234 break;
1235 }
1236
1237 return (error);
1238 }
1239
1240 int
pppackqfilter(dev_t dev,struct knote * kn)1241 pppackqfilter(dev_t dev, struct knote *kn)
1242 {
1243 struct pppac_softc *sc = pppac_lookup(dev);
1244 struct klist *klist;
1245
1246 switch (kn->kn_filter) {
1247 case EVFILT_READ:
1248 klist = &sc->sc_rklist;
1249 kn->kn_fop = &pppac_rd_filtops;
1250 break;
1251 case EVFILT_WRITE:
1252 klist = &sc->sc_wklist;
1253 kn->kn_fop = &pppac_wr_filtops;
1254 break;
1255 default:
1256 return (EINVAL);
1257 }
1258
1259 kn->kn_hook = sc;
1260
1261 klist_insert(klist, kn);
1262
1263 return (0);
1264 }
1265
1266 static void
filt_pppac_rdetach(struct knote * kn)1267 filt_pppac_rdetach(struct knote *kn)
1268 {
1269 struct pppac_softc *sc = kn->kn_hook;
1270
1271 klist_remove(&sc->sc_rklist, kn);
1272 }
1273
1274 static int
filt_pppac_read(struct knote * kn,long hint)1275 filt_pppac_read(struct knote *kn, long hint)
1276 {
1277 struct pppac_softc *sc = kn->kn_hook;
1278
1279 MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1280
1281 kn->kn_data = mq_hdatalen(&sc->sc_mq);
1282
1283 return (kn->kn_data > 0);
1284 }
1285
1286 static void
filt_pppac_wdetach(struct knote * kn)1287 filt_pppac_wdetach(struct knote *kn)
1288 {
1289 struct pppac_softc *sc = kn->kn_hook;
1290
1291 klist_remove(&sc->sc_wklist, kn);
1292 }
1293
1294 static int
filt_pppac_write(struct knote * kn,long hint)1295 filt_pppac_write(struct knote *kn, long hint)
1296 {
1297 /* We're always ready to accept a write. */
1298 return (1);
1299 }
1300
1301 static int
filt_pppac_modify(struct kevent * kev,struct knote * kn)1302 filt_pppac_modify(struct kevent *kev, struct knote *kn)
1303 {
1304 struct pppac_softc *sc = kn->kn_hook;
1305 int active;
1306
1307 mtx_enter(&sc->sc_mtx);
1308 active = knote_modify(kev, kn);
1309 mtx_leave(&sc->sc_mtx);
1310
1311 return (active);
1312 }
1313
1314 static int
filt_pppac_process(struct knote * kn,struct kevent * kev)1315 filt_pppac_process(struct knote *kn, struct kevent *kev)
1316 {
1317 struct pppac_softc *sc = kn->kn_hook;
1318 int active;
1319
1320 mtx_enter(&sc->sc_mtx);
1321 active = knote_process(kn, kev);
1322 mtx_leave(&sc->sc_mtx);
1323
1324 return (active);
1325 }
1326
1327 int
pppacclose(dev_t dev,int flags,int mode,struct proc * p)1328 pppacclose(dev_t dev, int flags, int mode, struct proc *p)
1329 {
1330 struct pppac_softc *sc = pppac_lookup(dev);
1331 struct ifnet *ifp = &sc->sc_if;
1332
1333 sc->sc_ready = 0;
1334
1335 NET_LOCK();
1336 CLR(ifp->if_flags, IFF_RUNNING);
1337 NET_UNLOCK();
1338
1339 if_detach(ifp);
1340
1341 klist_free(&sc->sc_rklist);
1342 klist_free(&sc->sc_wklist);
1343
1344 pool_put(&pipex_session_pool, sc->sc_multicast_session);
1345 pipex_destroy_all_sessions(sc);
1346
1347 LIST_REMOVE(sc, sc_entry);
1348 free(sc, M_DEVBUF, sizeof(*sc));
1349
1350 return (0);
1351 }
1352
1353 static int
pppac_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)1354 pppac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1355 {
1356 /* struct ifreq *ifr = (struct ifreq *)data; */
1357 int error = 0;
1358
1359 switch (cmd) {
1360 case SIOCSIFADDR:
1361 SET(ifp->if_flags, IFF_UP); /* XXX cry cry */
1362 /* FALLTHROUGH */
1363 case SIOCSIFFLAGS:
1364 if (ISSET(ifp->if_flags, IFF_UP))
1365 SET(ifp->if_flags, IFF_RUNNING);
1366 else
1367 CLR(ifp->if_flags, IFF_RUNNING);
1368 break;
1369 case SIOCSIFMTU:
1370 break;
1371 case SIOCADDMULTI:
1372 case SIOCDELMULTI:
1373 /* XXX */
1374 break;
1375
1376 default:
1377 error = ENOTTY;
1378 break;
1379 }
1380
1381 return (error);
1382 }
1383
1384 static int
pppac_add_session(struct pppac_softc * sc,struct pipex_session_req * req)1385 pppac_add_session(struct pppac_softc *sc, struct pipex_session_req *req)
1386 {
1387 int error;
1388 struct pipex_session *session;
1389
1390 error = pipex_init_session(&session, req);
1391 if (error != 0)
1392 return (error);
1393 error = pipex_link_session(session, &sc->sc_if, sc);
1394 if (error != 0)
1395 pipex_rele_session(session);
1396
1397 return (error);
1398 }
1399
1400 static int
pppac_del_session(struct pppac_softc * sc,struct pipex_session_close_req * req)1401 pppac_del_session(struct pppac_softc *sc, struct pipex_session_close_req *req)
1402 {
1403 struct pipex_session *session;
1404
1405 mtx_enter(&pipex_list_mtx);
1406
1407 session = pipex_lookup_by_session_id_locked(req->pcr_protocol,
1408 req->pcr_session_id);
1409 if (session == NULL || session->ownersc != sc) {
1410 mtx_leave(&pipex_list_mtx);
1411 return (EINVAL);
1412 }
1413 pipex_unlink_session_locked(session);
1414
1415 mtx_leave(&pipex_list_mtx);
1416
1417 pipex_export_session_stats(session, &req->psr_stat);
1418 pipex_rele_session(session);
1419
1420 return (0);
1421 }
1422
1423 static int
pppac_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)1424 pppac_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1425 struct rtentry *rt)
1426 {
1427 int error;
1428
1429 if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
1430 error = EHOSTDOWN;
1431 goto drop;
1432 }
1433
1434 switch (dst->sa_family) {
1435 case AF_INET:
1436 #ifdef INET6
1437 case AF_INET6:
1438 #endif
1439 break;
1440 default:
1441 error = EAFNOSUPPORT;
1442 goto drop;
1443 }
1444
1445 m->m_pkthdr.ph_family = dst->sa_family;
1446
1447 return (if_enqueue(ifp, m));
1448
1449 drop:
1450 m_freem(m);
1451 return (error);
1452 }
1453
1454 static void
pppac_qstart(struct ifqueue * ifq)1455 pppac_qstart(struct ifqueue *ifq)
1456 {
1457 struct ifnet *ifp = ifq->ifq_if;
1458 struct pppac_softc *sc = ifp->if_softc;
1459 struct mbuf *m, *m0;
1460 struct pipex_session *session;
1461 struct ip ip;
1462 int rv;
1463
1464 while ((m = ifq_dequeue(ifq)) != NULL) {
1465 #if NBPFILTER > 0
1466 if (ifp->if_bpf) {
1467 bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, m,
1468 BPF_DIRECTION_OUT);
1469 }
1470 #endif
1471
1472 switch (m->m_pkthdr.ph_family) {
1473 case AF_INET:
1474 if (m->m_pkthdr.len < sizeof(struct ip))
1475 goto bad;
1476 m_copydata(m, 0, sizeof(struct ip), &ip);
1477 if (IN_MULTICAST(ip.ip_dst.s_addr)) {
1478 /* pass a copy to pipex */
1479 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1480 if (m0 != NULL)
1481 pipex_ip_output(m0,
1482 sc->sc_multicast_session);
1483 else
1484 goto bad;
1485 } else {
1486 session = pipex_lookup_by_ip_address(ip.ip_dst);
1487 if (session != NULL) {
1488 pipex_ip_output(m, session);
1489 pipex_rele_session(session);
1490 m = NULL;
1491 }
1492 }
1493 break;
1494 }
1495 if (m == NULL) /* handled by pipex */
1496 continue;
1497
1498 m = m_prepend(m, sizeof(uint32_t), M_DONTWAIT);
1499 if (m == NULL)
1500 goto bad;
1501 *mtod(m, uint32_t *) = htonl(m->m_pkthdr.ph_family);
1502
1503 rv = mq_enqueue(&sc->sc_mq, m);
1504 if (rv == 1)
1505 counters_inc(ifp->if_counters, ifc_collisions);
1506 continue;
1507 bad:
1508 counters_inc(ifp->if_counters, ifc_oerrors);
1509 if (m != NULL)
1510 m_freem(m);
1511 continue;
1512 }
1513
1514 if (!mq_empty(&sc->sc_mq)) {
1515 wakeup(sc);
1516 knote(&sc->sc_rklist, 0);
1517 }
1518 }
1519