1/*	$OpenBSD: if_pppx.c,v 1.128 2023/12/23 10:52:54 bluhm 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
104int 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
115struct 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
125struct 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
140LIST_HEAD(, pppx_dev)		pppx_devs =
141				    LIST_HEAD_INITIALIZER(pppx_devs); /* [K] */
142struct pool			pppx_if_pl;
143
144struct pppx_dev			*pppx_dev_lookup(dev_t);
145struct pppx_dev			*pppx_dev2pxd(dev_t);
146
147struct pppx_if_key {
148	int			pxik_session_id;	/* [I] */
149	int			pxik_protocol;		/* [I] */
150};
151
152struct 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
168static inline int
169pppx_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
174RBT_HEAD(pppx_ifs, pppx_if) pppx_ifs = RBT_INITIALIZER(&pppx_ifs); /* [N] */
175RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
176
177int		pppx_if_next_unit(void);
178struct pppx_if *pppx_if_find_locked(struct pppx_dev *, int, int);
179static inline struct pppx_if	*pppx_if_find(struct pppx_dev *, int, int);
180static inline void		 pppx_if_rele(struct pppx_if *);
181int		pppx_add_session(struct pppx_dev *,
182		    struct pipex_session_req *);
183int		pppx_del_session(struct pppx_dev *,
184		    struct pipex_session_close_req *);
185int		pppx_set_session_descr(struct pppx_dev *,
186		    struct pipex_session_descr_req *);
187
188void		pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
189void		pppx_if_qstart(struct ifqueue *);
190int		pppx_if_output(struct ifnet *, struct mbuf *,
191		    struct sockaddr *, struct rtentry *);
192int		pppx_if_ioctl(struct ifnet *, u_long, caddr_t);
193
194
195void		pppxattach(int);
196
197void		filt_pppx_rdetach(struct knote *);
198int		filt_pppx_read(struct knote *, long);
199int		filt_pppx_modify(struct kevent *, struct knote *);
200int		filt_pppx_process(struct knote *, struct kevent *);
201
202const 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
211void		filt_pppx_wdetach(struct knote *);
212int		filt_pppx_write(struct knote *, long);
213
214const 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
223struct pppx_dev *
224pppx_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
237struct pppx_dev *
238pppx_dev2pxd(dev_t dev)
239{
240	struct pppx_dev *pxd;
241
242	pxd = pppx_dev_lookup(dev);
243
244	return (pxd);
245}
246
247void
248pppxattach(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
255int
256pppxopen(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
278int
279pppxread(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
316int
317pppxwrite(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 = &top;
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
424int
425pppxioctl(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 FIONBIO:
447		break;
448	case FIONREAD:
449		*(int *)addr = mq_hdatalen(&pxd->pxd_svcq);
450		break;
451
452	default:
453		error = pipex_ioctl(pxd, cmd, addr);
454		break;
455	}
456
457	return (error);
458}
459
460int
461pppxkqfilter(dev_t dev, struct knote *kn)
462{
463	struct pppx_dev *pxd = pppx_dev2pxd(dev);
464	struct klist *klist;
465
466	switch (kn->kn_filter) {
467	case EVFILT_READ:
468		klist = &pxd->pxd_rklist;
469		kn->kn_fop = &pppx_rd_filtops;
470		break;
471	case EVFILT_WRITE:
472		klist = &pxd->pxd_wklist;
473		kn->kn_fop = &pppx_wr_filtops;
474		break;
475	default:
476		return (EINVAL);
477	}
478
479	kn->kn_hook = pxd;
480
481	klist_insert(klist, kn);
482
483	return (0);
484}
485
486void
487filt_pppx_rdetach(struct knote *kn)
488{
489	struct pppx_dev *pxd = kn->kn_hook;
490
491	klist_remove(&pxd->pxd_rklist, kn);
492}
493
494int
495filt_pppx_read(struct knote *kn, long hint)
496{
497	struct pppx_dev *pxd = kn->kn_hook;
498
499	MUTEX_ASSERT_LOCKED(&pxd->pxd_mtx);
500
501	kn->kn_data = mq_hdatalen(&pxd->pxd_svcq);
502
503	return (kn->kn_data > 0);
504}
505
506void
507filt_pppx_wdetach(struct knote *kn)
508{
509	struct pppx_dev *pxd = kn->kn_hook;
510
511	klist_remove(&pxd->pxd_wklist, kn);
512}
513
514int
515filt_pppx_write(struct knote *kn, long hint)
516{
517	/* We're always ready to accept a write. */
518	return (1);
519}
520
521int
522filt_pppx_modify(struct kevent *kev, struct knote *kn)
523{
524	struct pppx_dev *pxd = kn->kn_hook;
525	int active;
526
527	mtx_enter(&pxd->pxd_mtx);
528	active = knote_modify(kev, kn);
529	mtx_leave(&pxd->pxd_mtx);
530
531	return (active);
532}
533
534int
535filt_pppx_process(struct knote *kn, struct kevent *kev)
536{
537	struct pppx_dev *pxd = kn->kn_hook;
538	int active;
539
540	mtx_enter(&pxd->pxd_mtx);
541	active = knote_process(kn, kev);
542	mtx_leave(&pxd->pxd_mtx);
543
544	return (active);
545}
546
547int
548pppxclose(dev_t dev, int flags, int mode, struct proc *p)
549{
550	struct pppx_dev *pxd;
551	struct pppx_if	*pxi;
552
553	pxd = pppx_dev_lookup(dev);
554
555	while ((pxi = LIST_FIRST(&pxd->pxd_pxis))) {
556		pxi->pxi_ready = 0;
557		pppx_if_destroy(pxd, pxi);
558	}
559
560	LIST_REMOVE(pxd, pxd_entry);
561
562	mq_purge(&pxd->pxd_svcq);
563
564	klist_free(&pxd->pxd_rklist);
565	klist_free(&pxd->pxd_rklist);
566
567	free(pxd, M_DEVBUF, sizeof(*pxd));
568
569	return (0);
570}
571
572int
573pppx_if_next_unit(void)
574{
575	struct pppx_if *pxi;
576	int unit = 0;
577
578	/* this is safe without splnet since we're not modifying it */
579	do {
580		int found = 0;
581		RBT_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
582			if (pxi->pxi_unit == unit) {
583				found = 1;
584				break;
585			}
586		}
587
588		if (found == 0)
589			break;
590		unit++;
591	} while (unit > 0);
592
593	return (unit);
594}
595
596struct pppx_if *
597pppx_if_find_locked(struct pppx_dev *pxd, int session_id, int protocol)
598{
599	struct pppx_if_key key;
600	struct pppx_if *pxi;
601
602	memset(&key, 0, sizeof(key));
603	key.pxik_session_id = session_id;
604	key.pxik_protocol = protocol;
605
606	pxi = RBT_FIND(pppx_ifs, &pppx_ifs, (struct pppx_if *)&key);
607	if (pxi && pxi->pxi_ready == 0)
608		pxi = NULL;
609
610	return pxi;
611}
612
613static inline struct pppx_if *
614pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
615{
616	struct pppx_if *pxi;
617
618	if ((pxi = pppx_if_find_locked(pxd, session_id, protocol)))
619		refcnt_take(&pxi->pxi_refcnt);
620
621	return pxi;
622}
623
624static inline void
625pppx_if_rele(struct pppx_if *pxi)
626{
627	refcnt_rele_wake(&pxi->pxi_refcnt);
628}
629
630int
631pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
632{
633	struct pppx_if *pxi;
634	struct pipex_session *session;
635	struct ifnet *ifp;
636	int unit, error = 0;
637	struct in_ifaddr *ia;
638	struct sockaddr_in ifaddr;
639
640	/*
641	 * XXX: As long as `session' is allocated as part of a `pxi'
642	 *	it isn't possible to free it separately.  So disallow
643	 *	the timeout feature until this is fixed.
644	 */
645	if (req->pr_timeout_sec != 0)
646		return (EINVAL);
647
648	error = pipex_init_session(&session, req);
649	if (error)
650		return (error);
651
652	pxi = pool_get(&pppx_if_pl, PR_WAITOK | PR_ZERO);
653	ifp = &pxi->pxi_if;
654
655	pxi->pxi_session = session;
656
657	/* try to set the interface up */
658	unit = pppx_if_next_unit();
659	if (unit < 0) {
660		error = ENOMEM;
661		goto out;
662	}
663
664	refcnt_init(&pxi->pxi_refcnt);
665	pxi->pxi_unit = unit;
666	pxi->pxi_key.pxik_session_id = req->pr_session_id;
667	pxi->pxi_key.pxik_protocol = req->pr_protocol;
668	pxi->pxi_dev = pxd;
669
670	if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL) {
671		error = EADDRINUSE;
672		goto out;
673	}
674	LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
675
676	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
677	ifp->if_mtu = req->pr_peer_mru;	/* XXX */
678	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
679	ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
680	ifp->if_qstart = pppx_if_qstart;
681	ifp->if_output = pppx_if_output;
682	ifp->if_ioctl = pppx_if_ioctl;
683	ifp->if_rtrequest = p2p_rtrequest;
684	ifp->if_type = IFT_PPP;
685	ifp->if_softc = pxi;
686	/* ifp->if_rdomain = req->pr_rdomain; */
687	if_counters_alloc(ifp);
688
689	if_attach(ifp);
690
691	NET_LOCK();
692	if_addgroup(ifp, "pppx");
693	if_alloc_sadl(ifp);
694	NET_UNLOCK();
695
696#if NBPFILTER > 0
697	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
698#endif
699
700	/* XXX ipv6 support?  how does the caller indicate it wants ipv6
701	 * instead of ipv4?
702	 */
703	memset(&ifaddr, 0, sizeof(ifaddr));
704	ifaddr.sin_family = AF_INET;
705	ifaddr.sin_len = sizeof(ifaddr);
706	ifaddr.sin_addr = req->pr_ip_srcaddr;
707
708	ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
709	refcnt_init_trace(&ia->ia_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR);
710
711	ia->ia_addr.sin_family = AF_INET;
712	ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
713	ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
714
715	ia->ia_dstaddr.sin_family = AF_INET;
716	ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
717	ia->ia_dstaddr.sin_addr = req->pr_ip_address;
718
719	ia->ia_sockmask.sin_family = AF_INET;
720	ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
721	ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
722
723	ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
724	ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
725	ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
726	ia->ia_ifa.ifa_ifp = ifp;
727
728	ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
729
730	NET_LOCK();
731	error = in_ifinit(ifp, ia, &ifaddr, 1);
732	if (error) {
733		printf("pppx: unable to set addresses for %s, error=%d\n",
734		    ifp->if_xname, error);
735	} else {
736		if_addrhooks_run(ifp);
737	}
738	NET_UNLOCK();
739
740	error = pipex_link_session(session, ifp, pxd);
741	if (error)
742		goto detach;
743
744	NET_LOCK();
745	SET(ifp->if_flags, IFF_RUNNING);
746	NET_UNLOCK();
747	pxi->pxi_ready = 1;
748
749	return (error);
750
751detach:
752	if_detach(ifp);
753
754	if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
755		panic("%s: inconsistent RB tree", __func__);
756	LIST_REMOVE(pxi, pxi_list);
757out:
758	pool_put(&pppx_if_pl, pxi);
759	pipex_rele_session(session);
760
761	return (error);
762}
763
764int
765pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
766{
767	struct pppx_if *pxi;
768
769	pxi = pppx_if_find_locked(pxd, req->pcr_session_id, req->pcr_protocol);
770	if (pxi == NULL)
771		return (EINVAL);
772
773	pxi->pxi_ready = 0;
774	pipex_export_session_stats(pxi->pxi_session, &req->pcr_stat);
775	pppx_if_destroy(pxd, pxi);
776	return (0);
777}
778
779int
780pppx_set_session_descr(struct pppx_dev *pxd,
781    struct pipex_session_descr_req *req)
782{
783	struct pppx_if *pxi;
784
785	pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
786	if (pxi == NULL)
787		return (EINVAL);
788
789	NET_LOCK();
790	(void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
791	strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
792	NET_UNLOCK();
793
794	pppx_if_rele(pxi);
795
796	return (0);
797}
798
799void
800pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
801{
802	struct ifnet *ifp;
803	struct pipex_session *session;
804
805	session = pxi->pxi_session;
806	ifp = &pxi->pxi_if;
807
808	refcnt_finalize(&pxi->pxi_refcnt, "pxifinal");
809
810	NET_LOCK();
811	CLR(ifp->if_flags, IFF_RUNNING);
812	NET_UNLOCK();
813
814	pipex_unlink_session(session);
815	if_detach(ifp);
816
817	pipex_rele_session(session);
818	if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
819		panic("%s: inconsistent RB tree", __func__);
820	LIST_REMOVE(pxi, pxi_list);
821
822	pool_put(&pppx_if_pl, pxi);
823}
824
825void
826pppx_if_qstart(struct ifqueue *ifq)
827{
828	struct ifnet *ifp = ifq->ifq_if;
829	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
830	struct mbuf *m;
831	int proto;
832
833	while ((m = ifq_dequeue(ifq)) != NULL) {
834		proto = *mtod(m, int *);
835		m_adj(m, sizeof(proto));
836
837		pipex_ppp_output(m, pxi->pxi_session, proto);
838	}
839}
840
841int
842pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
843    struct rtentry *rt)
844{
845	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
846	struct pppx_hdr *th;
847	int error = 0;
848	int pipex_enable_local, proto;
849
850	pipex_enable_local = atomic_load_int(&pipex_enable);
851
852	NET_ASSERT_LOCKED();
853
854	if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
855		m_freem(m);
856		error = ENETDOWN;
857		goto out;
858	}
859
860#if NBPFILTER > 0
861	if (ifp->if_bpf)
862		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
863#endif
864	if (pipex_enable_local) {
865		switch (dst->sa_family) {
866#ifdef INET6
867		case AF_INET6:
868			proto = PPP_IPV6;
869			break;
870#endif
871		case AF_INET:
872			proto = PPP_IP;
873			break;
874		default:
875			m_freem(m);
876			error = EPFNOSUPPORT;
877			goto out;
878		}
879	} else
880		proto = htonl(dst->sa_family);
881
882	M_PREPEND(m, sizeof(int), M_DONTWAIT);
883	if (m == NULL) {
884		error = ENOBUFS;
885		goto out;
886	}
887	*mtod(m, int *) = proto;
888
889	if (pipex_enable_local)
890		error = if_enqueue(ifp, m);
891	else {
892		M_PREPEND(m, sizeof(struct pppx_hdr), M_DONTWAIT);
893		if (m == NULL) {
894			error = ENOBUFS;
895			goto out;
896		}
897		th = mtod(m, struct pppx_hdr *);
898		th->pppx_proto = 0;	/* not used */
899		th->pppx_id = pxi->pxi_session->ppp_id;
900		error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m);
901		if (error == 0) {
902			if (pxi->pxi_dev->pxd_waiting) {
903				wakeup((caddr_t)pxi->pxi_dev);
904				pxi->pxi_dev->pxd_waiting = 0;
905			}
906			knote(&pxi->pxi_dev->pxd_rklist, 0);
907		}
908	}
909
910out:
911	if (error)
912		counters_inc(ifp->if_counters, ifc_oerrors);
913	return (error);
914}
915
916int
917pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
918{
919	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
920	struct ifreq *ifr = (struct ifreq *)addr;
921	int error = 0;
922
923	switch (cmd) {
924	case SIOCSIFADDR:
925		break;
926
927	case SIOCSIFFLAGS:
928		break;
929
930	case SIOCADDMULTI:
931	case SIOCDELMULTI:
932		break;
933
934	case SIOCSIFMTU:
935		if (ifr->ifr_mtu < 512 ||
936		    ifr->ifr_mtu > pxi->pxi_session->peer_mru)
937			error = EINVAL;
938		else
939			ifp->if_mtu = ifr->ifr_mtu;
940		break;
941
942	default:
943		error = ENOTTY;
944		break;
945	}
946
947	return (error);
948}
949
950RBT_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
951
952/*
953 * Locks used to protect struct members and global data
954 *       I       immutable after creation
955 *       K       kernel lock
956 *       N       net lock
957 *       m       sc_mtx
958 */
959
960struct pppac_softc {
961	struct ifnet	sc_if;
962	dev_t		sc_dev;		/* [I] */
963	int		sc_ready;	/* [K] */
964	LIST_ENTRY(pppac_softc)
965			sc_entry;	/* [K] */
966
967	struct mutex	sc_mtx;
968	struct klist	sc_rklist;	/* [m] */
969	struct klist	sc_wklist;	/* [m] */
970
971	struct pipex_session
972			*sc_multicast_session;
973
974	struct mbuf_queue
975			sc_mq;
976};
977
978LIST_HEAD(pppac_list, pppac_softc);	/* [K] */
979
980static void	filt_pppac_rdetach(struct knote *);
981static int	filt_pppac_read(struct knote *, long);
982static int	filt_pppac_modify(struct kevent *, struct knote *);
983static int	filt_pppac_process(struct knote *, struct kevent *);
984
985static const struct filterops pppac_rd_filtops = {
986	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
987	.f_attach	= NULL,
988	.f_detach	= filt_pppac_rdetach,
989	.f_event	= filt_pppac_read,
990	.f_modify	= filt_pppac_modify,
991	.f_process	= filt_pppac_process,
992};
993
994static void	filt_pppac_wdetach(struct knote *);
995static int	filt_pppac_write(struct knote *, long);
996
997static const struct filterops pppac_wr_filtops = {
998	.f_flags	= FILTEROP_ISFD | FILTEROP_MPSAFE,
999	.f_attach	= NULL,
1000	.f_detach	= filt_pppac_wdetach,
1001	.f_event	= filt_pppac_write,
1002	.f_modify	= filt_pppac_modify,
1003	.f_process	= filt_pppac_process,
1004};
1005
1006static struct pppac_list pppac_devs = LIST_HEAD_INITIALIZER(pppac_devs);
1007
1008static int	pppac_ioctl(struct ifnet *, u_long, caddr_t);
1009
1010static int	pppac_add_session(struct pppac_softc *,
1011		    struct pipex_session_req *);
1012static int	pppac_del_session(struct pppac_softc *,
1013		    struct pipex_session_close_req *);
1014static int	pppac_output(struct ifnet *, struct mbuf *, struct sockaddr *,
1015		    struct rtentry *);
1016static void	pppac_qstart(struct ifqueue *);
1017
1018static inline struct pppac_softc *
1019pppac_lookup(dev_t dev)
1020{
1021	struct pppac_softc *sc;
1022
1023	LIST_FOREACH(sc, &pppac_devs, sc_entry) {
1024		if (sc->sc_dev == dev) {
1025			if (sc->sc_ready == 0)
1026				break;
1027
1028			return (sc);
1029		}
1030	}
1031
1032	return (NULL);
1033}
1034
1035void
1036pppacattach(int n)
1037{
1038	pipex_init(); /* to be sure, to be sure */
1039}
1040
1041int
1042pppacopen(dev_t dev, int flags, int mode, struct proc *p)
1043{
1044	struct pppac_softc *sc, *tmp;
1045	struct ifnet *ifp;
1046	struct pipex_session *session;
1047
1048	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
1049	sc->sc_dev = dev;
1050	LIST_FOREACH(tmp, &pppac_devs, sc_entry) {
1051		if (tmp->sc_dev == dev) {
1052			free(sc, M_DEVBUF, sizeof(*sc));
1053			return (EBUSY);
1054		}
1055	}
1056	LIST_INSERT_HEAD(&pppac_devs, sc, sc_entry);
1057
1058	/* virtual pipex_session entry for multicast */
1059	session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO);
1060	session->flags |= PIPEX_SFLAGS_MULTICAST;
1061	session->ownersc = sc;
1062	sc->sc_multicast_session = session;
1063
1064	mtx_init(&sc->sc_mtx, IPL_SOFTNET);
1065	klist_init_mutex(&sc->sc_rklist, &sc->sc_mtx);
1066	klist_init_mutex(&sc->sc_wklist, &sc->sc_mtx);
1067	mq_init(&sc->sc_mq, IFQ_MAXLEN, IPL_SOFTNET);
1068
1069	ifp = &sc->sc_if;
1070	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "pppac%u", minor(dev));
1071
1072	ifp->if_softc = sc;
1073	ifp->if_type = IFT_L3IPVLAN;
1074	ifp->if_hdrlen = sizeof(uint32_t); /* for BPF */;
1075	ifp->if_mtu = MAXMCLBYTES - sizeof(uint32_t);
1076	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST;
1077	ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
1078	ifp->if_rtrequest = p2p_rtrequest; /* XXX */
1079	ifp->if_output = pppac_output;
1080	ifp->if_qstart = pppac_qstart;
1081	ifp->if_ioctl = pppac_ioctl;
1082
1083	if_counters_alloc(ifp);
1084	if_attach(ifp);
1085	if_alloc_sadl(ifp);
1086
1087#if NBPFILTER > 0
1088	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
1089#endif
1090
1091	sc->sc_ready = 1;
1092
1093	return (0);
1094}
1095
1096int
1097pppacread(dev_t dev, struct uio *uio, int ioflag)
1098{
1099	struct pppac_softc *sc = pppac_lookup(dev);
1100	struct ifnet *ifp = &sc->sc_if;
1101	struct mbuf *m0, *m;
1102	int error = 0;
1103	size_t len;
1104
1105	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1106		return (EHOSTDOWN);
1107
1108	m0 = mq_dequeue(&sc->sc_mq);
1109	if (m0 == NULL) {
1110		if (ISSET(ioflag, IO_NDELAY))
1111			return (EWOULDBLOCK);
1112
1113		do {
1114			error = tsleep_nsec(sc, (PZERO + 1)|PCATCH,
1115			    "pppacrd", INFSLP);
1116			if (error != 0)
1117				return (error);
1118
1119			m0 = mq_dequeue(&sc->sc_mq);
1120		} while (m0 == NULL);
1121	}
1122
1123	m = m0;
1124	while (uio->uio_resid > 0) {
1125		len = ulmin(uio->uio_resid, m->m_len);
1126		if (len != 0) {
1127			error = uiomove(mtod(m, caddr_t), len, uio);
1128			if (error != 0)
1129				break;
1130		}
1131
1132		m = m->m_next;
1133		if (m == NULL)
1134			break;
1135	}
1136	m_freem(m0);
1137
1138	return (error);
1139}
1140
1141int
1142pppacwrite(dev_t dev, struct uio *uio, int ioflag)
1143{
1144	struct pppac_softc *sc = pppac_lookup(dev);
1145	struct ifnet *ifp = &sc->sc_if;
1146	uint32_t proto;
1147	int error;
1148	struct mbuf *m;
1149
1150	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1151		return (EHOSTDOWN);
1152
1153	if (uio->uio_resid < ifp->if_hdrlen || uio->uio_resid > MAXMCLBYTES)
1154		return (EMSGSIZE);
1155
1156	m = m_gethdr(M_DONTWAIT, MT_DATA);
1157	if (m == NULL)
1158		return (ENOMEM);
1159
1160	if (uio->uio_resid > MHLEN) {
1161		m_clget(m, M_WAITOK, uio->uio_resid);
1162		if (!ISSET(m->m_flags, M_EXT)) {
1163			m_free(m);
1164			return (ENOMEM);
1165		}
1166	}
1167
1168	m->m_pkthdr.len = m->m_len = uio->uio_resid;
1169
1170	error = uiomove(mtod(m, void *), m->m_len, uio);
1171	if (error != 0) {
1172		m_freem(m);
1173		return (error);
1174	}
1175
1176#if NBPFILTER > 0
1177	if (ifp->if_bpf)
1178		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
1179#endif
1180
1181	/* strip the tunnel header */
1182	proto = ntohl(*mtod(m, uint32_t *));
1183	m_adj(m, sizeof(uint32_t));
1184
1185	m->m_flags &= ~(M_MCAST|M_BCAST);
1186	m->m_pkthdr.ph_ifidx = ifp->if_index;
1187	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
1188
1189#if NPF > 0
1190	pf_pkt_addr_changed(m);
1191#endif
1192
1193	counters_pkt(ifp->if_counters,
1194	    ifc_ipackets, ifc_ibytes, m->m_pkthdr.len);
1195
1196	NET_LOCK();
1197
1198	switch (proto) {
1199	case AF_INET:
1200		ipv4_input(ifp, m);
1201		break;
1202#ifdef INET6
1203	case AF_INET6:
1204		ipv6_input(ifp, m);
1205		break;
1206#endif
1207	default:
1208		m_freem(m);
1209		error = EAFNOSUPPORT;
1210		break;
1211	}
1212
1213	NET_UNLOCK();
1214
1215	return (error);
1216}
1217
1218int
1219pppacioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
1220{
1221	struct pppac_softc *sc = pppac_lookup(dev);
1222	int error = 0;
1223
1224	switch (cmd) {
1225	case FIONBIO:
1226		break;
1227	case FIONREAD:
1228		*(int *)data = mq_hdatalen(&sc->sc_mq);
1229		break;
1230
1231	case PIPEXASESSION:
1232		error = pppac_add_session(sc, (struct pipex_session_req *)data);
1233		break;
1234	case PIPEXDSESSION:
1235		error = pppac_del_session(sc,
1236		    (struct pipex_session_close_req *)data);
1237		break;
1238	default:
1239		error = pipex_ioctl(sc, cmd, data);
1240		break;
1241	}
1242
1243	return (error);
1244}
1245
1246int
1247pppackqfilter(dev_t dev, struct knote *kn)
1248{
1249	struct pppac_softc *sc = pppac_lookup(dev);
1250	struct klist *klist;
1251
1252	switch (kn->kn_filter) {
1253	case EVFILT_READ:
1254		klist = &sc->sc_rklist;
1255		kn->kn_fop = &pppac_rd_filtops;
1256		break;
1257	case EVFILT_WRITE:
1258		klist = &sc->sc_wklist;
1259		kn->kn_fop = &pppac_wr_filtops;
1260		break;
1261	default:
1262		return (EINVAL);
1263	}
1264
1265	kn->kn_hook = sc;
1266
1267	klist_insert(klist, kn);
1268
1269	return (0);
1270}
1271
1272static void
1273filt_pppac_rdetach(struct knote *kn)
1274{
1275	struct pppac_softc *sc = kn->kn_hook;
1276
1277	klist_remove(&sc->sc_rklist, kn);
1278}
1279
1280static int
1281filt_pppac_read(struct knote *kn, long hint)
1282{
1283	struct pppac_softc *sc = kn->kn_hook;
1284
1285	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1286
1287	kn->kn_data = mq_hdatalen(&sc->sc_mq);
1288
1289	return (kn->kn_data > 0);
1290}
1291
1292static void
1293filt_pppac_wdetach(struct knote *kn)
1294{
1295	struct pppac_softc *sc = kn->kn_hook;
1296
1297	klist_remove(&sc->sc_wklist, kn);
1298}
1299
1300static int
1301filt_pppac_write(struct knote *kn, long hint)
1302{
1303	/* We're always ready to accept a write. */
1304	return (1);
1305}
1306
1307static int
1308filt_pppac_modify(struct kevent *kev, struct knote *kn)
1309{
1310	struct pppac_softc *sc = kn->kn_hook;
1311	int active;
1312
1313	mtx_enter(&sc->sc_mtx);
1314	active = knote_modify(kev, kn);
1315	mtx_leave(&sc->sc_mtx);
1316
1317	return (active);
1318}
1319
1320static int
1321filt_pppac_process(struct knote *kn, struct kevent *kev)
1322{
1323	struct pppac_softc *sc = kn->kn_hook;
1324	int active;
1325
1326	mtx_enter(&sc->sc_mtx);
1327	active = knote_process(kn, kev);
1328	mtx_leave(&sc->sc_mtx);
1329
1330	return (active);
1331}
1332
1333int
1334pppacclose(dev_t dev, int flags, int mode, struct proc *p)
1335{
1336	struct pppac_softc *sc = pppac_lookup(dev);
1337	struct ifnet *ifp = &sc->sc_if;
1338
1339	sc->sc_ready = 0;
1340
1341	NET_LOCK();
1342	CLR(ifp->if_flags, IFF_RUNNING);
1343	NET_UNLOCK();
1344
1345	if_detach(ifp);
1346
1347	klist_free(&sc->sc_rklist);
1348	klist_free(&sc->sc_wklist);
1349
1350	pool_put(&pipex_session_pool, sc->sc_multicast_session);
1351	pipex_destroy_all_sessions(sc);
1352
1353	LIST_REMOVE(sc, sc_entry);
1354	free(sc, M_DEVBUF, sizeof(*sc));
1355
1356	return (0);
1357}
1358
1359static int
1360pppac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1361{
1362	/* struct ifreq *ifr = (struct ifreq *)data; */
1363	int error = 0;
1364
1365	switch (cmd) {
1366	case SIOCSIFADDR:
1367		SET(ifp->if_flags, IFF_UP); /* XXX cry cry */
1368		/* FALLTHROUGH */
1369	case SIOCSIFFLAGS:
1370		if (ISSET(ifp->if_flags, IFF_UP))
1371			SET(ifp->if_flags, IFF_RUNNING);
1372		else
1373			CLR(ifp->if_flags, IFF_RUNNING);
1374		break;
1375	case SIOCSIFMTU:
1376		break;
1377	case SIOCADDMULTI:
1378	case SIOCDELMULTI:
1379		/* XXX */
1380		break;
1381
1382	default:
1383		error = ENOTTY;
1384		break;
1385	}
1386
1387	return (error);
1388}
1389
1390static int
1391pppac_add_session(struct pppac_softc *sc, struct pipex_session_req *req)
1392{
1393	int error;
1394	struct pipex_session *session;
1395
1396	error = pipex_init_session(&session, req);
1397	if (error != 0)
1398		return (error);
1399	error = pipex_link_session(session, &sc->sc_if, sc);
1400	if (error != 0)
1401		pipex_rele_session(session);
1402
1403	return (error);
1404}
1405
1406static int
1407pppac_del_session(struct pppac_softc *sc, struct pipex_session_close_req *req)
1408{
1409	struct pipex_session *session;
1410
1411	mtx_enter(&pipex_list_mtx);
1412
1413	session = pipex_lookup_by_session_id_locked(req->pcr_protocol,
1414	    req->pcr_session_id);
1415	if (session == NULL || session->ownersc != sc) {
1416		mtx_leave(&pipex_list_mtx);
1417		return (EINVAL);
1418	}
1419	pipex_unlink_session_locked(session);
1420	pipex_rele_session(session);
1421
1422	mtx_leave(&pipex_list_mtx);
1423
1424	return (0);
1425}
1426
1427static int
1428pppac_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1429    struct rtentry *rt)
1430{
1431	int error;
1432
1433	if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
1434		error = EHOSTDOWN;
1435		goto drop;
1436	}
1437
1438	switch (dst->sa_family) {
1439	case AF_INET:
1440#ifdef INET6
1441	case AF_INET6:
1442#endif
1443		break;
1444	default:
1445		error = EAFNOSUPPORT;
1446		goto drop;
1447	}
1448
1449	m->m_pkthdr.ph_family = dst->sa_family;
1450
1451	return (if_enqueue(ifp, m));
1452
1453drop:
1454	m_freem(m);
1455	return (error);
1456}
1457
1458static void
1459pppac_qstart(struct ifqueue *ifq)
1460{
1461	struct ifnet *ifp = ifq->ifq_if;
1462	struct pppac_softc *sc = ifp->if_softc;
1463	struct mbuf *m, *m0;
1464	struct pipex_session *session;
1465	struct ip ip;
1466	int rv;
1467
1468	while ((m = ifq_dequeue(ifq)) != NULL) {
1469#if NBPFILTER > 0
1470		if (ifp->if_bpf) {
1471			bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, m,
1472			    BPF_DIRECTION_OUT);
1473		}
1474#endif
1475
1476		switch (m->m_pkthdr.ph_family) {
1477		case AF_INET:
1478			if (m->m_pkthdr.len < sizeof(struct ip))
1479				goto bad;
1480			m_copydata(m, 0, sizeof(struct ip), &ip);
1481			if (IN_MULTICAST(ip.ip_dst.s_addr)) {
1482				/* pass a copy to pipex */
1483				m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1484				if (m0 != NULL)
1485					pipex_ip_output(m0,
1486					    sc->sc_multicast_session);
1487				else
1488					goto bad;
1489			} else {
1490				session = pipex_lookup_by_ip_address(ip.ip_dst);
1491				if (session != NULL) {
1492					pipex_ip_output(m, session);
1493					pipex_rele_session(session);
1494					m = NULL;
1495				}
1496			}
1497			break;
1498		}
1499		if (m == NULL)	/* handled by pipex */
1500			continue;
1501
1502		m = m_prepend(m, sizeof(uint32_t), M_DONTWAIT);
1503		if (m == NULL)
1504			goto bad;
1505		*mtod(m, uint32_t *) = htonl(m->m_pkthdr.ph_family);
1506
1507		rv = mq_enqueue(&sc->sc_mq, m);
1508		if (rv == 1)
1509			counters_inc(ifp->if_counters, ifc_collisions);
1510		continue;
1511bad:
1512		counters_inc(ifp->if_counters, ifc_oerrors);
1513		if (m != NULL)
1514			m_freem(m);
1515		continue;
1516	}
1517
1518	if (!mq_empty(&sc->sc_mq)) {
1519		wakeup(sc);
1520		knote(&sc->sc_rklist, 0);
1521	}
1522}
1523