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