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