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