xref: /openbsd-src/sys/net/if_pppx.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: if_pppx.c,v 1.76 2020/02/20 16:56:52 visa 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/rwlock.h>
54 #include <sys/pool.h>
55 #include <sys/mbuf.h>
56 #include <sys/errno.h>
57 #include <sys/protosw.h>
58 #include <sys/socket.h>
59 #include <sys/ioctl.h>
60 #include <sys/vnode.h>
61 #include <sys/poll.h>
62 #include <sys/selinfo.h>
63 
64 #include <net/if.h>
65 #include <net/if_types.h>
66 #include <net/netisr.h>
67 #include <netinet/in.h>
68 #include <netinet/if_ether.h>
69 #include <net/if_dl.h>
70 
71 #include <netinet/in_var.h>
72 #include <netinet/ip.h>
73 #include <netinet/ip_var.h>
74 
75 #ifdef INET6
76 #include <netinet6/in6_var.h>
77 #include <netinet/ip6.h>
78 #include <netinet6/nd6.h>
79 #endif /* INET6 */
80 
81 #include "bpfilter.h"
82 #if NBPFILTER > 0
83 #include <net/bpf.h>
84 #endif
85 
86 #include "pf.h"
87 #if NPF > 0
88 #include <net/pfvar.h>
89 #endif
90 
91 #include <net/ppp_defs.h>
92 #include <net/ppp-comp.h>
93 #include <crypto/arc4.h>
94 
95 #ifdef PIPEX
96 #include <net/radix.h>
97 #include <net/pipex.h>
98 #include <net/pipex_local.h>
99 #else
100 #error PIPEX option not enabled
101 #endif
102 
103 #ifdef PPPX_DEBUG
104 #define PPPX_D_INIT	(1<<0)
105 
106 int pppxdebug = 0;
107 
108 #define DPRINTF(_m, _p...)	do { \
109 					if (ISSET(pppxdebug, (_m))) \
110 						printf(_p); \
111 				} while (0)
112 #else
113 #define DPRINTF(_m, _p...)	/* _m, _p */
114 #endif
115 
116 
117 struct pppx_if;
118 
119 struct pppx_dev {
120 	LIST_ENTRY(pppx_dev)	pxd_entry;
121 	int			pxd_unit;
122 
123 	/* kq shizz */
124 	struct selinfo		pxd_rsel;
125 	struct mutex		pxd_rsel_mtx;
126 	struct selinfo		pxd_wsel;
127 	struct mutex		pxd_wsel_mtx;
128 
129 	/* queue of packets for userland to service - protected by splnet */
130 	struct mbuf_queue	pxd_svcq;
131 	int			pxd_waiting;
132 	LIST_HEAD(,pppx_if)	pxd_pxis;
133 };
134 
135 struct rwlock			pppx_devs_lk = RWLOCK_INITIALIZER("pppxdevs");
136 LIST_HEAD(, pppx_dev)		pppx_devs = LIST_HEAD_INITIALIZER(pppx_devs);
137 struct pool			*pppx_if_pl;
138 
139 struct pppx_dev			*pppx_dev_lookup(dev_t);
140 struct pppx_dev			*pppx_dev2pxd(dev_t);
141 
142 struct pppx_if_key {
143 	int			pxik_session_id;
144 	int			pxik_protocol;
145 };
146 
147 struct pppx_if {
148 	struct pppx_if_key	pxi_key; /* must be first in the struct */
149 
150 	RBT_ENTRY(pppx_if)	pxi_entry;
151 	LIST_ENTRY(pppx_if)	pxi_list;
152 
153 	int			pxi_ready;
154 
155 	int			pxi_unit;
156 	struct ifnet		pxi_if;
157 	struct pppx_dev		*pxi_dev;
158 	struct pipex_session	pxi_session;
159 	struct pipex_iface_context	pxi_ifcontext;
160 };
161 
162 static inline int
163 pppx_if_cmp(const struct pppx_if *a, const struct pppx_if *b)
164 {
165 	return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key));
166 }
167 
168 struct rwlock			pppx_ifs_lk = RWLOCK_INITIALIZER("pppxifs");
169 RBT_HEAD(pppx_ifs, pppx_if)	pppx_ifs = RBT_INITIALIZER(&pppx_ifs);
170 RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
171 
172 int		pppx_if_next_unit(void);
173 struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
174 int		pppx_add_session(struct pppx_dev *,
175 		    struct pipex_session_req *);
176 int		pppx_del_session(struct pppx_dev *,
177 		    struct pipex_session_close_req *);
178 int		pppx_set_session_descr(struct pppx_dev *,
179 		    struct pipex_session_descr_req *);
180 
181 void		pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
182 void		pppx_if_start(struct ifnet *);
183 int		pppx_if_output(struct ifnet *, struct mbuf *,
184 		    struct sockaddr *, struct rtentry *);
185 int		pppx_if_ioctl(struct ifnet *, u_long, caddr_t);
186 
187 
188 void		pppxattach(int);
189 
190 void		filt_pppx_rdetach(struct knote *);
191 int		filt_pppx_read(struct knote *, long);
192 
193 const struct filterops pppx_rd_filtops = {
194 	.f_flags	= FILTEROP_ISFD,
195 	.f_attach	= NULL,
196 	.f_detach	= filt_pppx_rdetach,
197 	.f_event	= filt_pppx_read,
198 };
199 
200 void		filt_pppx_wdetach(struct knote *);
201 int		filt_pppx_write(struct knote *, long);
202 
203 const struct filterops pppx_wr_filtops = {
204 	.f_flags	= FILTEROP_ISFD,
205 	.f_attach	= NULL,
206 	.f_detach	= filt_pppx_wdetach,
207 	.f_event	= filt_pppx_write,
208 };
209 
210 struct pppx_dev *
211 pppx_dev_lookup(dev_t dev)
212 {
213 	struct pppx_dev *pxd;
214 	int unit = minor(dev);
215 
216 	/* must hold pppx_devs_lk */
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 	rw_enter_read(&pppx_devs_lk);
232 	pxd = pppx_dev_lookup(dev);
233 	rw_exit_read(&pppx_devs_lk);
234 
235 	return (pxd);
236 }
237 
238 void
239 pppxattach(int n)
240 {
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 	int rv = 0;
249 
250 	rv = rw_enter(&pppx_devs_lk, RW_WRITE | RW_INTR);
251 	if (rv != 0)
252 		return (rv);
253 
254 	pxd = pppx_dev_lookup(dev);
255 	if (pxd != NULL) {
256 		rv = EBUSY;
257 		goto out;
258 	}
259 
260 	if (LIST_EMPTY(&pppx_devs) && pppx_if_pl == NULL) {
261 		pppx_if_pl = malloc(sizeof(*pppx_if_pl), M_DEVBUF, M_WAITOK);
262 		pool_init(pppx_if_pl, sizeof(struct pppx_if), 0, IPL_NONE,
263 		    PR_WAITOK, "pppxif", NULL);
264 	}
265 
266 	pxd = malloc(sizeof(*pxd), M_DEVBUF, M_WAITOK | M_ZERO);
267 
268 	pxd->pxd_unit = minor(dev);
269 	mtx_init(&pxd->pxd_rsel_mtx, IPL_NET);
270 	mtx_init(&pxd->pxd_wsel_mtx, IPL_NET);
271 	LIST_INIT(&pxd->pxd_pxis);
272 
273 	mq_init(&pxd->pxd_svcq, 128, IPL_NET);
274 	LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry);
275 
276 out:
277 	rw_exit(&pppx_devs_lk);
278 	return (rv);
279 }
280 
281 int
282 pppxread(dev_t dev, struct uio *uio, int ioflag)
283 {
284 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
285 	struct mbuf *m, *m0;
286 	int error = 0;
287 	size_t len;
288 
289 	if (!pxd)
290 		return (ENXIO);
291 
292 	while ((m0 = mq_dequeue(&pxd->pxd_svcq)) == NULL) {
293 		if (ISSET(ioflag, IO_NDELAY))
294 			return (EWOULDBLOCK);
295 
296 		NET_LOCK();
297 		pxd->pxd_waiting = 1;
298 		error = rwsleep_nsec(pxd, &netlock,
299 		    (PZERO + 1)|PCATCH, "pppxread", INFSLP);
300 		NET_UNLOCK();
301 		if (error != 0) {
302 			return (error);
303 		}
304 	}
305 
306 	while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
307 		len = ulmin(uio->uio_resid, m0->m_len);
308 		if (len != 0)
309 			error = uiomove(mtod(m0, caddr_t), len, uio);
310 		m = m_free(m0);
311 		m0 = m;
312 	}
313 
314 	m_freem(m0);
315 
316 	return (error);
317 }
318 
319 int
320 pppxwrite(dev_t dev, struct uio *uio, int ioflag)
321 {
322 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
323 	struct pppx_hdr *th;
324 	struct pppx_if	*pxi;
325 	uint32_t proto;
326 	struct mbuf *top, **mp, *m;
327 	int tlen;
328 	int error = 0;
329 	size_t mlen;
330 
331 	if (uio->uio_resid < sizeof(*th) + sizeof(uint32_t) ||
332 	    uio->uio_resid > MCLBYTES)
333 		return (EMSGSIZE);
334 
335 	tlen = uio->uio_resid;
336 
337 	MGETHDR(m, M_DONTWAIT, MT_DATA);
338 	if (m == NULL)
339 		return (ENOBUFS);
340 	mlen = MHLEN;
341 	if (uio->uio_resid >= MINCLSIZE) {
342 		MCLGET(m, M_DONTWAIT);
343 		if (!(m->m_flags & M_EXT)) {
344 			m_free(m);
345 			return (ENOBUFS);
346 		}
347 		mlen = MCLBYTES;
348 	}
349 
350 	top = NULL;
351 	mp = &top;
352 
353 	while (error == 0 && uio->uio_resid > 0) {
354 		m->m_len = ulmin(mlen, uio->uio_resid);
355 		error = uiomove(mtod (m, caddr_t), m->m_len, uio);
356 		*mp = m;
357 		mp = &m->m_next;
358 		if (error == 0 && uio->uio_resid > 0) {
359 			MGET(m, M_DONTWAIT, MT_DATA);
360 			if (m == NULL) {
361 				error = ENOBUFS;
362 				break;
363 			}
364 			mlen = MLEN;
365 			if (uio->uio_resid >= MINCLSIZE) {
366 				MCLGET(m, M_DONTWAIT);
367 				if (!(m->m_flags & M_EXT)) {
368 					error = ENOBUFS;
369 					m_free(m);
370 					break;
371 				}
372 				mlen = MCLBYTES;
373 			}
374 		}
375 	}
376 
377 	if (error) {
378 		m_freem(top);
379 		return (error);
380 	}
381 
382 	top->m_pkthdr.len = tlen;
383 
384 	/* Find the interface */
385 	th = mtod(top, struct pppx_hdr *);
386 	m_adj(top, sizeof(struct pppx_hdr));
387 	pxi = pppx_if_find(pxd, th->pppx_id, th->pppx_proto);
388 	if (pxi == NULL) {
389 		m_freem(top);
390 		return (EINVAL);
391 	}
392 	top->m_pkthdr.ph_ifidx = pxi->pxi_if.if_index;
393 
394 #if NBPFILTER > 0
395 	if (pxi->pxi_if.if_bpf)
396 		bpf_mtap(pxi->pxi_if.if_bpf, top, BPF_DIRECTION_IN);
397 #endif
398 	/* strip the tunnel header */
399 	proto = ntohl(*(uint32_t *)(th + 1));
400 	m_adj(top, sizeof(uint32_t));
401 
402 	NET_LOCK();
403 
404 	switch (proto) {
405 	case AF_INET:
406 		ipv4_input(&pxi->pxi_if, top);
407 		break;
408 #ifdef INET6
409 	case AF_INET6:
410 		ipv6_input(&pxi->pxi_if, top);
411 		break;
412 #endif
413 	default:
414 		m_freem(top);
415 		error = EAFNOSUPPORT;
416 		break;
417 	}
418 
419 	NET_UNLOCK();
420 
421 	return (error);
422 }
423 
424 int
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 	NET_LOCK();
431 	switch (cmd) {
432 	case PIPEXSMODE:
433 		/*
434 		 * npppd always enables on open, and only disables before
435 		 * closing. we cheat and let open and close do that, so lie
436 		 * to npppd.
437 		 */
438 		break;
439 	case PIPEXGMODE:
440 		*(int *)addr = 1;
441 		break;
442 
443 	case PIPEXASESSION:
444 		error = pppx_add_session(pxd,
445 		    (struct pipex_session_req *)addr);
446 		break;
447 
448 	case PIPEXDSESSION:
449 		error = pppx_del_session(pxd,
450 		    (struct pipex_session_close_req *)addr);
451 		break;
452 
453 	case PIPEXCSESSION:
454 		error = pipex_config_session(
455 		    (struct pipex_session_config_req *)addr);
456 		break;
457 
458 	case PIPEXGSTAT:
459 		error = pipex_get_stat((struct pipex_session_stat_req *)addr);
460 		break;
461 
462 	case PIPEXGCLOSED:
463 		error = pipex_get_closed((struct pipex_session_list_req *)addr);
464 		break;
465 
466 	case PIPEXSIFDESCR:
467 		error = pppx_set_session_descr(pxd,
468 		    (struct pipex_session_descr_req *)addr);
469 		break;
470 
471 	case FIONBIO:
472 		break;
473 	case FIONREAD:
474 		*(int *)addr = mq_hdatalen(&pxd->pxd_svcq);
475 		break;
476 
477 	default:
478 		error = ENOTTY;
479 		break;
480 	}
481 	NET_UNLOCK();
482 
483 	return (error);
484 }
485 
486 int
487 pppxpoll(dev_t dev, int events, struct proc *p)
488 {
489 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
490 	int revents = 0;
491 
492 	if (events & (POLLIN | POLLRDNORM)) {
493 		if (!mq_empty(&pxd->pxd_svcq))
494 			revents |= events & (POLLIN | POLLRDNORM);
495 	}
496 	if (events & (POLLOUT | POLLWRNORM))
497 		revents |= events & (POLLOUT | POLLWRNORM);
498 
499 	if (revents == 0) {
500 		if (events & (POLLIN | POLLRDNORM))
501 			selrecord(p, &pxd->pxd_rsel);
502 	}
503 
504 	return (revents);
505 }
506 
507 int
508 pppxkqfilter(dev_t dev, struct knote *kn)
509 {
510 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
511 	struct mutex *mtx;
512 	struct klist *klist;
513 
514 	switch (kn->kn_filter) {
515 	case EVFILT_READ:
516 		mtx = &pxd->pxd_rsel_mtx;
517 		klist = &pxd->pxd_rsel.si_note;
518 		kn->kn_fop = &pppx_rd_filtops;
519 		break;
520 	case EVFILT_WRITE:
521 		mtx = &pxd->pxd_wsel_mtx;
522 		klist = &pxd->pxd_wsel.si_note;
523 		kn->kn_fop = &pppx_wr_filtops;
524 		break;
525 	default:
526 		return (EINVAL);
527 	}
528 
529 	kn->kn_hook = (caddr_t)pxd;
530 
531 	mtx_enter(mtx);
532 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
533 	mtx_leave(mtx);
534 
535 	return (0);
536 }
537 
538 void
539 filt_pppx_rdetach(struct knote *kn)
540 {
541 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
542 	struct klist *klist = &pxd->pxd_rsel.si_note;
543 
544 	mtx_enter(&pxd->pxd_rsel_mtx);
545 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
546 	mtx_leave(&pxd->pxd_rsel_mtx);
547 }
548 
549 int
550 filt_pppx_read(struct knote *kn, long hint)
551 {
552 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
553 
554 	kn->kn_data = mq_hdatalen(&pxd->pxd_svcq);
555 
556 	return (kn->kn_data > 0);
557 }
558 
559 void
560 filt_pppx_wdetach(struct knote *kn)
561 {
562 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
563 	struct klist *klist = &pxd->pxd_wsel.si_note;
564 
565 	mtx_enter(&pxd->pxd_wsel_mtx);
566 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
567 	mtx_leave(&pxd->pxd_wsel_mtx);
568 }
569 
570 int
571 filt_pppx_write(struct knote *kn, long hint)
572 {
573 	/* We're always ready to accept a write. */
574 	return (1);
575 }
576 
577 int
578 pppxclose(dev_t dev, int flags, int mode, struct proc *p)
579 {
580 	struct pppx_dev *pxd;
581 	struct pppx_if	*pxi;
582 
583 	rw_enter_write(&pppx_devs_lk);
584 
585 	pxd = pppx_dev_lookup(dev);
586 
587 	/* XXX */
588 	NET_LOCK();
589 	while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
590 		pppx_if_destroy(pxd, pxi);
591 	NET_UNLOCK();
592 
593 	LIST_REMOVE(pxd, pxd_entry);
594 
595 	mq_purge(&pxd->pxd_svcq);
596 
597 	free(pxd, M_DEVBUF, sizeof(*pxd));
598 
599 	if (LIST_EMPTY(&pppx_devs)) {
600 		pool_destroy(pppx_if_pl);
601 		free(pppx_if_pl, M_DEVBUF, sizeof(*pppx_if_pl));
602 		pppx_if_pl = NULL;
603 	}
604 
605 	rw_exit_write(&pppx_devs_lk);
606 	return (0);
607 }
608 
609 int
610 pppx_if_next_unit(void)
611 {
612 	struct pppx_if *pxi;
613 	int unit = 0;
614 
615 	rw_assert_wrlock(&pppx_ifs_lk);
616 
617 	/* this is safe without splnet since we're not modifying it */
618 	do {
619 		int found = 0;
620 		RBT_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
621 			if (pxi->pxi_unit == unit) {
622 				found = 1;
623 				break;
624 			}
625 		}
626 
627 		if (found == 0)
628 			break;
629 		unit++;
630 	} while (unit > 0);
631 
632 	return (unit);
633 }
634 
635 struct pppx_if *
636 pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
637 {
638 	struct pppx_if *s, *p;
639 	s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
640 
641 	s->pxi_key.pxik_session_id = session_id;
642 	s->pxi_key.pxik_protocol = protocol;
643 
644 	rw_enter_read(&pppx_ifs_lk);
645 	p = RBT_FIND(pppx_ifs, &pppx_ifs, s);
646 	if (p && p->pxi_ready == 0)
647 		p = NULL;
648 	rw_exit_read(&pppx_ifs_lk);
649 
650 	free(s, M_DEVBUF, sizeof(*s));
651 	return (p);
652 }
653 
654 int
655 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
656 {
657 	struct pppx_if *pxi;
658 	struct pipex_session *session;
659 	struct pipex_hash_head *chain;
660 	struct ifnet *ifp;
661 	int unit, error = 0;
662 	struct in_ifaddr *ia;
663 	struct sockaddr_in ifaddr;
664 #ifdef PIPEX_PPPOE
665 	struct ifnet *over_ifp = NULL;
666 #endif
667 
668 	switch (req->pr_protocol) {
669 #ifdef PIPEX_PPPOE
670 	case PIPEX_PROTO_PPPOE:
671 		over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
672 		if (over_ifp == NULL)
673 			return (EINVAL);
674 		if (req->pr_peer_address.ss_family != AF_UNSPEC)
675 			return (EINVAL);
676 		break;
677 #endif
678 #ifdef PIPEX_PPTP
679 	case PIPEX_PROTO_PPTP:
680 #endif
681 #ifdef PIPEX_L2TP
682 	case PIPEX_PROTO_L2TP:
683 #endif
684 		switch (req->pr_peer_address.ss_family) {
685 		case AF_INET:
686 			if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in))
687 				return (EINVAL);
688 			break;
689 #ifdef INET6
690 		case AF_INET6:
691 			if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in6))
692 				return (EINVAL);
693 			break;
694 #endif
695 		default:
696 			return (EPROTONOSUPPORT);
697 		}
698 		if (req->pr_peer_address.ss_family !=
699 		    req->pr_local_address.ss_family ||
700 		    req->pr_peer_address.ss_len !=
701 		    req->pr_local_address.ss_len)
702 			return (EINVAL);
703 		break;
704 	default:
705 		return (EPROTONOSUPPORT);
706 	}
707 
708 	pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
709 	if (pxi == NULL)
710 		return (ENOMEM);
711 
712 	session = &pxi->pxi_session;
713 	ifp = &pxi->pxi_if;
714 
715 	/* fake a pipex interface context */
716 	session->pipex_iface = &pxi->pxi_ifcontext;
717 	session->pipex_iface->ifnet_this = ifp;
718 	session->pipex_iface->pipexmode = PIPEX_ENABLED;
719 
720 	/* setup session */
721 	session->state = PIPEX_STATE_OPENED;
722 	session->protocol = req->pr_protocol;
723 	session->session_id = req->pr_session_id;
724 	session->peer_session_id = req->pr_peer_session_id;
725 	session->peer_mru = req->pr_peer_mru;
726 	session->timeout_sec = req->pr_timeout_sec;
727 	session->ppp_flags = req->pr_ppp_flags;
728 	session->ppp_id = req->pr_ppp_id;
729 
730 	session->ip_forward = 1;
731 
732 	session->ip_address.sin_family = AF_INET;
733 	session->ip_address.sin_len = sizeof(struct sockaddr_in);
734 	session->ip_address.sin_addr = req->pr_ip_address;
735 
736 	session->ip_netmask.sin_family = AF_INET;
737 	session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
738 	session->ip_netmask.sin_addr = req->pr_ip_netmask;
739 
740 	if (session->ip_netmask.sin_addr.s_addr == 0L)
741 		session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
742 	session->ip_address.sin_addr.s_addr &=
743 	    session->ip_netmask.sin_addr.s_addr;
744 
745 	if (req->pr_peer_address.ss_len > 0)
746 		memcpy(&session->peer, &req->pr_peer_address,
747 		    MIN(req->pr_peer_address.ss_len, sizeof(session->peer)));
748 	if (req->pr_local_address.ss_len > 0)
749 		memcpy(&session->local, &req->pr_local_address,
750 		    MIN(req->pr_local_address.ss_len, sizeof(session->local)));
751 #ifdef PIPEX_PPPOE
752 	if (req->pr_protocol == PIPEX_PROTO_PPPOE)
753 		session->proto.pppoe.over_ifidx = over_ifp->if_index;
754 #endif
755 #ifdef PIPEX_PPTP
756 	if (req->pr_protocol == PIPEX_PROTO_PPTP) {
757 		struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
758 
759 		sess_pptp->snd_gap = 0;
760 		sess_pptp->rcv_gap = 0;
761 		sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
762 		sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
763 		sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
764 		sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
765 
766 		sess_pptp->winsz = req->pr_proto.pptp.winsz;
767 		sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
768 		sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
769 		/* last ack number */
770 		sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
771 	}
772 #endif
773 #ifdef PIPEX_L2TP
774 	if (req->pr_protocol == PIPEX_PROTO_L2TP) {
775 		struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
776 
777 		/* session keys */
778 		sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
779 		sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
780 
781 		/* protocol options */
782 		sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
783 
784 		/* initial state of dynamic context */
785 		sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
786 		sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
787 		sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
788 		sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
789 		sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
790 		/* last ack number */
791 		sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
792 	}
793 #endif
794 #ifdef PIPEX_MPPE
795 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
796 		pipex_session_init_mppe_recv(session,
797 		    req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
798 		    req->pr_mppe_recv.master_key);
799 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
800 		pipex_session_init_mppe_send(session,
801 		    req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
802 		    req->pr_mppe_send.master_key);
803 
804 	if (pipex_session_is_mppe_required(session)) {
805 		if (!pipex_session_is_mppe_enabled(session) ||
806 		    !pipex_session_is_mppe_accepted(session)) {
807 			pool_put(pppx_if_pl, pxi);
808 			return (EINVAL);
809 		}
810 	}
811 #endif
812 
813 	/* try to set the interface up */
814 	rw_enter_write(&pppx_ifs_lk);
815 	unit = pppx_if_next_unit();
816 	if (unit < 0) {
817 		pool_put(pppx_if_pl, pxi);
818 		error = ENOMEM;
819 		rw_exit_write(&pppx_ifs_lk);
820 		goto out;
821 	}
822 
823 	pxi->pxi_unit = unit;
824 	pxi->pxi_key.pxik_session_id = req->pr_session_id;
825 	pxi->pxi_key.pxik_protocol = req->pr_protocol;
826 	pxi->pxi_dev = pxd;
827 
828 	/* this is safe without splnet since we're not modifying it */
829 	if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
830 		pool_put(pppx_if_pl, pxi);
831 		error = EADDRINUSE;
832 		rw_exit_write(&pppx_ifs_lk);
833 		goto out;
834 	}
835 
836 	if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
837 		panic("%s: pppx_ifs modified while lock was held", __func__);
838 	LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
839 	rw_exit_write(&pppx_ifs_lk);
840 
841 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
842 	ifp->if_mtu = req->pr_peer_mru;	/* XXX */
843 	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
844 	ifp->if_start = pppx_if_start;
845 	ifp->if_output = pppx_if_output;
846 	ifp->if_ioctl = pppx_if_ioctl;
847 	ifp->if_rtrequest = p2p_rtrequest;
848 	ifp->if_type = IFT_PPP;
849 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
850 	ifp->if_softc = pxi;
851 	/* ifp->if_rdomain = req->pr_rdomain; */
852 
853 	/* hook up pipex context */
854 	chain = PIPEX_ID_HASHTABLE(session->session_id);
855 	LIST_INSERT_HEAD(chain, session, id_chain);
856 	LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
857 	switch (req->pr_protocol) {
858 	case PIPEX_PROTO_PPTP:
859 	case PIPEX_PROTO_L2TP:
860 		chain = PIPEX_PEER_ADDR_HASHTABLE(
861 		    pipex_sockaddr_hash_key(&session->peer.sa));
862 		LIST_INSERT_HEAD(chain, session, peer_addr_chain);
863 		break;
864 	}
865 
866 	/* if first session is added, start timer */
867 	if (LIST_NEXT(session, session_list) == NULL)
868 		pipex_timer_start();
869 
870 	/* XXXSMP breaks atomicity */
871 	NET_UNLOCK();
872 	if_attach(ifp);
873 	NET_LOCK();
874 
875 	if_addgroup(ifp, "pppx");
876 	if_alloc_sadl(ifp);
877 
878 #if NBPFILTER > 0
879 	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
880 #endif
881 	SET(ifp->if_flags, IFF_RUNNING);
882 
883 	/* XXX ipv6 support?  how does the caller indicate it wants ipv6
884 	 * instead of ipv4?
885 	 */
886 	memset(&ifaddr, 0, sizeof(ifaddr));
887 	ifaddr.sin_family = AF_INET;
888 	ifaddr.sin_len = sizeof(ifaddr);
889 	ifaddr.sin_addr = req->pr_ip_srcaddr;
890 
891 	ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
892 
893 	ia->ia_addr.sin_family = AF_INET;
894 	ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
895 	ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
896 
897 	ia->ia_dstaddr.sin_family = AF_INET;
898 	ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
899 	ia->ia_dstaddr.sin_addr = req->pr_ip_address;
900 
901 	ia->ia_sockmask.sin_family = AF_INET;
902 	ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
903 	ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
904 
905 	ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
906 	ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
907 	ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
908 	ia->ia_ifa.ifa_ifp = ifp;
909 
910 	ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
911 
912 	error = in_ifinit(ifp, ia, &ifaddr, 1);
913 	if (error) {
914 		printf("pppx: unable to set addresses for %s, error=%d\n",
915 		    ifp->if_xname, error);
916 	} else {
917 		if_addrhooks_run(ifp);
918 	}
919 	rw_enter_write(&pppx_ifs_lk);
920 	pxi->pxi_ready = 1;
921 	rw_exit_write(&pppx_ifs_lk);
922 
923 out:
924 	return (error);
925 }
926 
927 int
928 pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
929 {
930 	struct pppx_if *pxi;
931 
932 	pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
933 	if (pxi == NULL)
934 		return (EINVAL);
935 
936 	req->pcr_stat = pxi->pxi_session.stat;
937 
938 	pppx_if_destroy(pxd, pxi);
939 	return (0);
940 }
941 
942 int
943 pppx_set_session_descr(struct pppx_dev *pxd,
944     struct pipex_session_descr_req *req)
945 {
946 	struct pppx_if *pxi;
947 
948 	pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
949 	if (pxi == NULL)
950 		return (EINVAL);
951 
952 	(void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
953 	strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
954 
955 	return (0);
956 }
957 
958 void
959 pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
960 {
961 	struct ifnet *ifp;
962 	struct pipex_session *session;
963 
964 	NET_ASSERT_LOCKED();
965 	session = &pxi->pxi_session;
966 	ifp = &pxi->pxi_if;
967 
968 	LIST_REMOVE(session, id_chain);
969 	LIST_REMOVE(session, session_list);
970 	switch (session->protocol) {
971 	case PIPEX_PROTO_PPTP:
972 	case PIPEX_PROTO_L2TP:
973 		LIST_REMOVE((struct pipex_session *)session,
974 		    peer_addr_chain);
975 		break;
976 	}
977 
978 	/* if final session is destroyed, stop timer */
979 	if (LIST_EMPTY(&pipex_session_list))
980 		pipex_timer_stop();
981 
982 	/* XXXSMP breaks atomicity */
983 	NET_UNLOCK();
984 	if_detach(ifp);
985 	NET_LOCK();
986 
987 	rw_enter_write(&pppx_ifs_lk);
988 	if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
989 		panic("%s: pppx_ifs modified while lock was held", __func__);
990 	LIST_REMOVE(pxi, pxi_list);
991 	rw_exit_write(&pppx_ifs_lk);
992 
993 	pool_put(pppx_if_pl, pxi);
994 }
995 
996 void
997 pppx_if_start(struct ifnet *ifp)
998 {
999 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1000 	struct mbuf *m;
1001 	int proto;
1002 
1003 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1004 		return;
1005 
1006 	for (;;) {
1007 		IFQ_DEQUEUE(&ifp->if_snd, m);
1008 
1009 		if (m == NULL)
1010 			break;
1011 
1012 		proto = *mtod(m, int *);
1013 		m_adj(m, sizeof(proto));
1014 
1015 		ifp->if_obytes += m->m_pkthdr.len;
1016 		ifp->if_opackets++;
1017 
1018 		pipex_ppp_output(m, &pxi->pxi_session, proto);
1019 	}
1020 }
1021 
1022 int
1023 pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1024     struct rtentry *rt)
1025 {
1026 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1027 	struct pppx_hdr *th;
1028 	int error = 0;
1029 	int proto;
1030 
1031 	NET_ASSERT_LOCKED();
1032 
1033 	if (!ISSET(ifp->if_flags, IFF_UP)) {
1034 		m_freem(m);
1035 		error = ENETDOWN;
1036 		goto out;
1037 	}
1038 
1039 #if NBPFILTER > 0
1040 	if (ifp->if_bpf)
1041 		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
1042 #endif
1043 	if (pipex_enable) {
1044 		switch (dst->sa_family) {
1045 #ifdef INET6
1046 		case AF_INET6:
1047 			proto = PPP_IPV6;
1048 			break;
1049 #endif
1050 		case AF_INET:
1051 			proto = PPP_IP;
1052 			break;
1053 		default:
1054 			m_freem(m);
1055 			error = EPFNOSUPPORT;
1056 			goto out;
1057 		}
1058 	} else
1059 		proto = htonl(dst->sa_family);
1060 
1061 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
1062 	if (m == NULL) {
1063 		error = ENOBUFS;
1064 		goto out;
1065 	}
1066 	*mtod(m, int *) = proto;
1067 
1068 	if (pipex_enable)
1069 		error = if_enqueue(ifp, m);
1070 	else {
1071 		M_PREPEND(m, sizeof(struct pppx_hdr), M_DONTWAIT);
1072 		if (m == NULL) {
1073 			error = ENOBUFS;
1074 			goto out;
1075 		}
1076 		th = mtod(m, struct pppx_hdr *);
1077 		th->pppx_proto = 0;	/* not used */
1078 		th->pppx_id = pxi->pxi_session.ppp_id;
1079 		rw_enter_read(&pppx_devs_lk);
1080 		error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m);
1081 		if (error == 0) {
1082 			if (pxi->pxi_dev->pxd_waiting) {
1083 				wakeup((caddr_t)pxi->pxi_dev);
1084 				pxi->pxi_dev->pxd_waiting = 0;
1085 			}
1086 			selwakeup(&pxi->pxi_dev->pxd_rsel);
1087 		}
1088 		rw_exit_read(&pppx_devs_lk);
1089 	}
1090 
1091 out:
1092 	if (error)
1093 		ifp->if_oerrors++;
1094 	return (error);
1095 }
1096 
1097 int
1098 pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
1099 {
1100 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1101 	struct ifreq *ifr = (struct ifreq *)addr;
1102 	int error = 0;
1103 
1104 	switch (cmd) {
1105 	case SIOCSIFADDR:
1106 		break;
1107 
1108 	case SIOCSIFFLAGS:
1109 		break;
1110 
1111 	case SIOCADDMULTI:
1112 	case SIOCDELMULTI:
1113 		break;
1114 
1115 	case SIOCSIFMTU:
1116 		if (ifr->ifr_mtu < 512 ||
1117 		    ifr->ifr_mtu > pxi->pxi_session.peer_mru)
1118 			error = EINVAL;
1119 		else
1120 			ifp->if_mtu = ifr->ifr_mtu;
1121 		break;
1122 
1123 	default:
1124 		error = ENOTTY;
1125 		break;
1126 	}
1127 
1128 	return (error);
1129 }
1130 
1131 RBT_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
1132 
1133 /*
1134  * pppac(4) - PPP Access Concentrator interface
1135  */
1136 
1137 #include <net/if_tun.h>
1138 
1139 struct pppac_softc {
1140 	struct ifnet	sc_if;
1141 	unsigned int	sc_dead;
1142 	dev_t		sc_dev;
1143 	LIST_ENTRY(pppac_softc)
1144 			sc_entry;
1145 
1146 	struct mutex	sc_rsel_mtx;
1147 	struct selinfo	sc_rsel;
1148 	struct mutex	sc_wsel_mtx;
1149 	struct selinfo	sc_wsel;
1150 
1151 	struct pipex_iface_context
1152 			sc_pipex_iface;
1153 
1154 	struct mbuf_queue
1155 			sc_mq;
1156 };
1157 
1158 LIST_HEAD(pppac_list, pppac_softc);
1159 
1160 static void	filt_pppac_rdetach(struct knote *);
1161 static int	filt_pppac_read(struct knote *, long);
1162 
1163 static const struct filterops pppac_rd_filtops = {
1164 	1,
1165 	NULL,
1166 	filt_pppac_rdetach,
1167 	filt_pppac_read
1168 };
1169 
1170 static void	filt_pppac_wdetach(struct knote *);
1171 static int	filt_pppac_write(struct knote *, long);
1172 
1173 static const struct filterops pppac_wr_filtops = {
1174 	1,
1175 	NULL,
1176 	filt_pppac_wdetach,
1177 	filt_pppac_write
1178 };
1179 
1180 static struct pppac_list pppac_devs = LIST_HEAD_INITIALIZER(pppac_devs);
1181 
1182 static int	pppac_ioctl(struct ifnet *, u_long, caddr_t);
1183 
1184 static int	pppac_output(struct ifnet *, struct mbuf *, struct sockaddr *,
1185 		    struct rtentry *);
1186 static void	pppac_start(struct ifnet *);
1187 
1188 static inline struct pppac_softc *
1189 pppac_lookup(dev_t dev)
1190 {
1191 	struct pppac_softc *sc;
1192 
1193 	LIST_FOREACH(sc, &pppac_devs, sc_entry) {
1194 		if (sc->sc_dev == dev)
1195 			return (sc);
1196 	}
1197 
1198 	return (NULL);
1199 }
1200 
1201 void
1202 pppacattach(int n)
1203 {
1204 	pipex_init(); /* to be sure, to be sure */
1205 }
1206 
1207 int
1208 pppacopen(dev_t dev, int flags, int mode, struct proc *p)
1209 {
1210 	struct pppac_softc *sc;
1211 	struct ifnet *ifp;
1212 
1213 	sc = pppac_lookup(dev);
1214 	if (sc != NULL)
1215 		return (EBUSY);
1216 
1217 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
1218 	sc->sc_dev = dev;
1219 
1220 	mtx_init(&sc->sc_rsel_mtx, IPL_SOFTNET);
1221 	mtx_init(&sc->sc_wsel_mtx, IPL_SOFTNET);
1222 	mq_init(&sc->sc_mq, IFQ_MAXLEN, IPL_SOFTNET);
1223 
1224 	LIST_INSERT_HEAD(&pppac_devs, sc, sc_entry);
1225 
1226 	ifp = &sc->sc_if;
1227 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "pppac%u", minor(dev));
1228 
1229 	ifp->if_softc = sc;
1230 	ifp->if_type = IFT_L3IPVLAN;
1231 	ifp->if_hdrlen = sizeof(uint32_t); /* for BPF */;
1232 	ifp->if_mtu = MAXMCLBYTES - sizeof(uint32_t);
1233 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST;
1234 	ifp->if_xflags = IFXF_CLONED;
1235 	ifp->if_rtrequest = p2p_rtrequest; /* XXX */
1236 	ifp->if_output = pppac_output;
1237 	ifp->if_start = pppac_start;
1238 	ifp->if_ioctl = pppac_ioctl;
1239 
1240 	if_counters_alloc(ifp);
1241 	if_attach(ifp);
1242 	if_alloc_sadl(ifp);
1243 
1244 #if NBPFILTER > 0
1245 	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
1246 #endif
1247 
1248 	pipex_iface_init(&sc->sc_pipex_iface, ifp);
1249 
1250 	return (0);
1251 }
1252 
1253 int
1254 pppacread(dev_t dev, struct uio *uio, int ioflag)
1255 {
1256 	struct pppac_softc *sc = pppac_lookup(dev);
1257 	struct ifnet *ifp = &sc->sc_if;
1258 	struct mbuf *m0, *m;
1259 	int error = 0;
1260 	size_t len;
1261 
1262 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1263 		return (EHOSTDOWN);
1264 
1265 	m0 = mq_dequeue(&sc->sc_mq);
1266 	if (m0 == NULL) {
1267 		if (ISSET(ioflag, IO_NDELAY))
1268 			return (EWOULDBLOCK);
1269 
1270 		do {
1271 			error = tsleep_nsec(sc, (PZERO + 1)|PCATCH,
1272 			    "pppacrd", INFSLP);
1273 			if (error != 0)
1274 				return (error);
1275 
1276 			m0 = mq_dequeue(&sc->sc_mq);
1277 		} while (m0 == NULL);
1278 	}
1279 
1280 	m = m0;
1281 	while (uio->uio_resid > 0) {
1282 		len = ulmin(uio->uio_resid, m->m_len);
1283 		if (len != 0) {
1284 			error = uiomove(mtod(m, caddr_t), len, uio);
1285 			if (error != 0)
1286 				break;
1287 		}
1288 
1289 		m = m->m_next;
1290 		if (m == NULL)
1291 			break;
1292 	}
1293 	m_freem(m0);
1294 
1295 	return (error);
1296 }
1297 
1298 int
1299 pppacwrite(dev_t dev, struct uio *uio, int ioflag)
1300 {
1301 	struct pppac_softc *sc = pppac_lookup(dev);
1302 	struct ifnet *ifp = &sc->sc_if;
1303 	uint32_t proto;
1304 	int error;
1305 	struct mbuf *m;
1306 
1307 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1308 		return (EHOSTDOWN);
1309 
1310 	if (uio->uio_resid < ifp->if_hdrlen || uio->uio_resid > MAXMCLBYTES)
1311 		return (EMSGSIZE);
1312 
1313 	m = m_gethdr(M_DONTWAIT, MT_DATA);
1314 	if (m == NULL)
1315 		return (ENOMEM);
1316 
1317 	if (uio->uio_resid > MINCLSIZE) {
1318 		m_clget(m, M_WAITOK, uio->uio_resid);
1319 		if (!ISSET(m->m_flags, M_EXT)) {
1320 			m_free(m);
1321 			return (ENOMEM);
1322 		}
1323 	}
1324 
1325 	m->m_pkthdr.len = m->m_len = uio->uio_resid;
1326 
1327 	error = uiomove(mtod(m, void *), m->m_len, uio);
1328 	if (error != 0) {
1329 		m_freem(m);
1330 		return (error);
1331 	}
1332 
1333 #if NBPFILTER > 0
1334 	if (ifp->if_bpf)
1335 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
1336 #endif
1337 
1338 	/* strip the tunnel header */
1339 	proto = ntohl(*mtod(m, uint32_t *));
1340 	m_adj(m, sizeof(uint32_t));
1341 
1342 	m->m_flags &= ~(M_MCAST|M_BCAST);
1343 	m->m_pkthdr.ph_ifidx = ifp->if_index;
1344 	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
1345 
1346 #if NPF > 0
1347 	pf_pkt_addr_changed(m);
1348 #endif
1349 
1350 	counters_pkt(ifp->if_counters,
1351 	    ifc_ipackets, ifc_ibytes, m->m_pkthdr.len);
1352 
1353 	NET_LOCK();
1354 
1355 	switch (proto) {
1356 	case AF_INET:
1357 		ipv4_input(ifp, m);
1358 		break;
1359 #ifdef INET6
1360 	case AF_INET6:
1361 		ipv6_input(ifp, m);
1362 		break;
1363 #endif
1364 	default:
1365 		m_freem(m);
1366 		error = EAFNOSUPPORT;
1367 		break;
1368 	}
1369 
1370 	NET_UNLOCK();
1371 
1372 	return (error);
1373 }
1374 
1375 int
1376 pppacioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
1377 {
1378 	struct pppac_softc *sc = pppac_lookup(dev);
1379 	int error = 0;
1380 
1381 	switch (cmd) {
1382 	case TUNSIFMODE: /* make npppd happy */
1383 		break;
1384 
1385 	case FIONBIO:
1386 		break;
1387 	case FIONREAD:
1388 		*(int *)data = mq_hdatalen(&sc->sc_mq);
1389 		break;
1390 
1391 	default:
1392 		error = pipex_ioctl(&sc->sc_pipex_iface, cmd, data);
1393 		break;
1394 	}
1395 
1396 	return (error);
1397 }
1398 
1399 int
1400 pppacpoll(dev_t dev, int events, struct proc *p)
1401 {
1402 	struct pppac_softc *sc = pppac_lookup(dev);
1403 	int revents = 0;
1404 
1405 	if (events & (POLLIN | POLLRDNORM)) {
1406 		if (!mq_empty(&sc->sc_mq))
1407 			revents |= events & (POLLIN | POLLRDNORM);
1408 	}
1409 	if (events & (POLLOUT | POLLWRNORM))
1410 		revents |= events & (POLLOUT | POLLWRNORM);
1411 
1412 	if (revents == 0) {
1413 		if (events & (POLLIN | POLLRDNORM))
1414 			selrecord(p, &sc->sc_rsel);
1415 	}
1416 
1417 	return (revents);
1418 }
1419 
1420 int
1421 pppackqfilter(dev_t dev, struct knote *kn)
1422 {
1423 	struct pppac_softc *sc = pppac_lookup(dev);
1424 	struct mutex *mtx;
1425 	struct klist *klist;
1426 
1427 	switch (kn->kn_filter) {
1428 	case EVFILT_READ:
1429 		mtx = &sc->sc_rsel_mtx;
1430 		klist = &sc->sc_rsel.si_note;
1431 		kn->kn_fop = &pppac_rd_filtops;
1432 		break;
1433 	case EVFILT_WRITE:
1434 		mtx = &sc->sc_wsel_mtx;
1435 		klist = &sc->sc_wsel.si_note;
1436 		kn->kn_fop = &pppac_wr_filtops;
1437 		break;
1438 	default:
1439 		return (EINVAL);
1440 	}
1441 
1442 	kn->kn_hook = sc;
1443 
1444 	mtx_enter(mtx);
1445 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1446 	mtx_leave(mtx);
1447 
1448 	return (0);
1449 }
1450 
1451 static void
1452 filt_pppac_rdetach(struct knote *kn)
1453 {
1454 	struct pppac_softc *sc = kn->kn_hook;
1455 	struct klist *klist = &sc->sc_rsel.si_note;
1456 
1457 	mtx_enter(&sc->sc_rsel_mtx);
1458 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
1459 	mtx_leave(&sc->sc_rsel_mtx);
1460 }
1461 
1462 static int
1463 filt_pppac_read(struct knote *kn, long hint)
1464 {
1465 	struct pppac_softc *sc = kn->kn_hook;
1466 
1467 	kn->kn_data = mq_hdatalen(&sc->sc_mq);
1468 
1469 	return (kn->kn_data > 0);
1470 }
1471 
1472 static void
1473 filt_pppac_wdetach(struct knote *kn)
1474 {
1475 	struct pppac_softc *sc = kn->kn_hook;
1476 	struct klist *klist = &sc->sc_wsel.si_note;
1477 
1478 	mtx_enter(&sc->sc_wsel_mtx);
1479 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
1480 	mtx_leave(&sc->sc_wsel_mtx);
1481 }
1482 
1483 static int
1484 filt_pppac_write(struct knote *kn, long hint)
1485 {
1486 	/* We're always ready to accept a write. */
1487 	return (1);
1488 }
1489 
1490 int
1491 pppacclose(dev_t dev, int flags, int mode, struct proc *p)
1492 {
1493 	struct pppac_softc *sc = pppac_lookup(dev);
1494 	struct ifnet *ifp = &sc->sc_if;
1495 	int s;
1496 
1497 	NET_LOCK();
1498 	sc->sc_dead = 1;
1499 	CLR(ifp->if_flags, IFF_RUNNING);
1500 	NET_UNLOCK();
1501 
1502 	s = splhigh();
1503 	klist_invalidate(&sc->sc_rsel.si_note);
1504 	klist_invalidate(&sc->sc_wsel.si_note);
1505 	splx(s);
1506 
1507 	pipex_iface_fini(&sc->sc_pipex_iface);
1508 
1509 	if_detach(ifp);
1510 
1511 	LIST_REMOVE(sc, sc_entry);
1512 	free(sc, M_DEVBUF, sizeof(*sc));
1513 
1514 	return (0);
1515 }
1516 
1517 static int
1518 pppac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1519 {
1520 	struct pppac_softc *sc = ifp->if_softc;
1521 	/* struct ifreq *ifr = (struct ifreq *)data; */
1522 	int error = 0;
1523 
1524 	if (sc->sc_dead)
1525 		return (ENXIO);
1526 
1527 	switch (cmd) {
1528 	case SIOCSIFADDR:
1529 		SET(ifp->if_flags, IFF_UP); /* XXX cry cry */
1530 		/* FALLTHROUGH */
1531 	case SIOCSIFFLAGS:
1532 		if (ISSET(ifp->if_flags, IFF_UP))
1533 			SET(ifp->if_flags, IFF_RUNNING);
1534 		else
1535 			CLR(ifp->if_flags, IFF_RUNNING);
1536 		break;
1537 	case SIOCSIFMTU:
1538 		break;
1539 	case SIOCADDMULTI:
1540 	case SIOCDELMULTI:
1541 		/* XXX */
1542 		break;
1543 
1544 	default:
1545 		error = ENOTTY;
1546 		break;
1547 	}
1548 
1549 	return (error);
1550 }
1551 
1552 static int
1553 pppac_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1554     struct rtentry *rt)
1555 {
1556 	int error;
1557 
1558 	if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
1559 		error = EHOSTDOWN;
1560 		goto drop;
1561 	}
1562 
1563 	switch (dst->sa_family) {
1564 	case AF_INET:
1565 #ifdef INET6
1566 	case AF_INET6:
1567 #endif
1568 		break;
1569 	default:
1570 		error = EAFNOSUPPORT;
1571 		goto drop;
1572 	}
1573 
1574 	m->m_pkthdr.ph_family = dst->sa_family;
1575 
1576 	return (if_enqueue(ifp, m));
1577 
1578 drop:
1579 	m_freem(m);
1580 	return (error);
1581 }
1582 
1583 static void
1584 pppac_start(struct ifnet *ifp)
1585 {
1586 	struct pppac_softc *sc = ifp->if_softc;
1587 	struct mbuf *m;
1588 
1589 	while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
1590 #if NBPFILTER > 0
1591 		if (ifp->if_bpf) {
1592 			bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, m,
1593 			    BPF_DIRECTION_OUT);
1594 		}
1595 #endif
1596 
1597 		m = pipex_output(m, m->m_pkthdr.ph_family, 0,
1598 		    &sc->sc_pipex_iface);
1599 		if (m == NULL)
1600 			continue;
1601 
1602 		m = m_prepend(m, sizeof(uint32_t), M_DONTWAIT);
1603 		if (m == NULL) {
1604 			/* oh well */
1605 			continue;
1606 		}
1607 		*mtod(m, uint32_t *) = htonl(m->m_pkthdr.ph_family);
1608 
1609 		mq_enqueue(&sc->sc_mq, m); /* qdrop */
1610 	}
1611 
1612 	if (!mq_empty(&sc->sc_mq)) {
1613 		KERNEL_ASSERT_LOCKED();
1614 		wakeup(sc);
1615 		selwakeup(&sc->sc_rsel);
1616 	}
1617 }
1618