xref: /openbsd-src/sys/net/if_pppx.c (revision 4b70baf6e17fc8b27fc1f7fa7929335753fa94c3)
1 /*	$OpenBSD: if_pppx.c,v 1.67 2019/03/04 18:41:40 denis 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 <net/ppp_defs.h>
87 #include <net/ppp-comp.h>
88 #include <crypto/arc4.h>
89 
90 #ifdef PIPEX
91 #include <net/radix.h>
92 #include <net/pipex.h>
93 #include <net/pipex_local.h>
94 #else
95 #error PIPEX option not enabled
96 #endif
97 
98 #ifdef PPPX_DEBUG
99 #define PPPX_D_INIT	(1<<0)
100 
101 int pppxdebug = 0;
102 
103 #define DPRINTF(_m, _p...)	do { \
104 					if (ISSET(pppxdebug, (_m))) \
105 						printf(_p); \
106 				} while (0)
107 #else
108 #define DPRINTF(_m, _p...)	/* _m, _p */
109 #endif
110 
111 
112 struct pppx_if;
113 
114 struct pppx_dev {
115 	LIST_ENTRY(pppx_dev)	pxd_entry;
116 	int			pxd_unit;
117 
118 	/* kq shizz */
119 	struct selinfo		pxd_rsel;
120 	struct mutex		pxd_rsel_mtx;
121 	struct selinfo		pxd_wsel;
122 	struct mutex		pxd_wsel_mtx;
123 
124 	/* queue of packets for userland to service - protected by splnet */
125 	struct mbuf_queue	pxd_svcq;
126 	int			pxd_waiting;
127 	LIST_HEAD(,pppx_if)	pxd_pxis;
128 };
129 
130 struct rwlock			pppx_devs_lk = RWLOCK_INITIALIZER("pppxdevs");
131 LIST_HEAD(, pppx_dev)		pppx_devs = LIST_HEAD_INITIALIZER(pppx_devs);
132 struct pool			*pppx_if_pl;
133 
134 struct pppx_dev			*pppx_dev_lookup(dev_t);
135 struct pppx_dev			*pppx_dev2pxd(dev_t);
136 
137 struct pppx_if_key {
138 	int			pxik_session_id;
139 	int			pxik_protocol;
140 };
141 
142 struct pppx_if {
143 	struct pppx_if_key	pxi_key; /* must be first in the struct */
144 
145 	RBT_ENTRY(pppx_if)	pxi_entry;
146 	LIST_ENTRY(pppx_if)	pxi_list;
147 
148 	int			pxi_ready;
149 
150 	int			pxi_unit;
151 	struct ifnet		pxi_if;
152 	struct pppx_dev		*pxi_dev;
153 	struct pipex_session	pxi_session;
154 	struct pipex_iface_context	pxi_ifcontext;
155 };
156 
157 static inline int
158 pppx_if_cmp(const struct pppx_if *a, const struct pppx_if *b)
159 {
160 	return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key));
161 }
162 
163 struct rwlock			pppx_ifs_lk = RWLOCK_INITIALIZER("pppxifs");
164 RBT_HEAD(pppx_ifs, pppx_if)	pppx_ifs = RBT_INITIALIZER(&pppx_ifs);
165 RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
166 
167 int		pppx_if_next_unit(void);
168 struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
169 int		pppx_add_session(struct pppx_dev *,
170 		    struct pipex_session_req *);
171 int		pppx_del_session(struct pppx_dev *,
172 		    struct pipex_session_close_req *);
173 int		pppx_set_session_descr(struct pppx_dev *,
174 		    struct pipex_session_descr_req *);
175 
176 void		pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
177 void		pppx_if_start(struct ifnet *);
178 int		pppx_if_output(struct ifnet *, struct mbuf *,
179 		    struct sockaddr *, struct rtentry *);
180 int		pppx_if_ioctl(struct ifnet *, u_long, caddr_t);
181 
182 
183 void		pppxattach(int);
184 
185 void		filt_pppx_rdetach(struct knote *);
186 int		filt_pppx_read(struct knote *, long);
187 
188 struct filterops pppx_rd_filtops = {
189 	1,
190 	NULL,
191 	filt_pppx_rdetach,
192 	filt_pppx_read
193 };
194 
195 void		filt_pppx_wdetach(struct knote *);
196 int		filt_pppx_write(struct knote *, long);
197 
198 struct filterops pppx_wr_filtops = {
199 	1,
200 	NULL,
201 	filt_pppx_wdetach,
202 	filt_pppx_write
203 };
204 
205 struct pppx_dev *
206 pppx_dev_lookup(dev_t dev)
207 {
208 	struct pppx_dev *pxd;
209 	int unit = minor(dev);
210 
211 	/* must hold pppx_devs_lk */
212 
213 	LIST_FOREACH(pxd, &pppx_devs, pxd_entry) {
214 		if (pxd->pxd_unit == unit)
215 			return (pxd);
216 	}
217 
218 	return (NULL);
219 }
220 
221 struct pppx_dev *
222 pppx_dev2pxd(dev_t dev)
223 {
224 	struct pppx_dev *pxd;
225 
226 	rw_enter_read(&pppx_devs_lk);
227 	pxd = pppx_dev_lookup(dev);
228 	rw_exit_read(&pppx_devs_lk);
229 
230 	return (pxd);
231 }
232 
233 void
234 pppxattach(int n)
235 {
236 	pipex_init();
237 }
238 
239 int
240 pppxopen(dev_t dev, int flags, int mode, struct proc *p)
241 {
242 	struct pppx_dev *pxd;
243 	int rv = 0;
244 
245 	rv = rw_enter(&pppx_devs_lk, RW_WRITE | RW_INTR);
246 	if (rv != 0)
247 		return (rv);
248 
249 	pxd = pppx_dev_lookup(dev);
250 	if (pxd != NULL) {
251 		rv = EBUSY;
252 		goto out;
253 	}
254 
255 	if (LIST_EMPTY(&pppx_devs) && pppx_if_pl == NULL) {
256 		pppx_if_pl = malloc(sizeof(*pppx_if_pl), M_DEVBUF, M_WAITOK);
257 		pool_init(pppx_if_pl, sizeof(struct pppx_if), 0, IPL_NONE,
258 		    PR_WAITOK, "pppxif", NULL);
259 	}
260 
261 	pxd = malloc(sizeof(*pxd), M_DEVBUF, M_WAITOK | M_ZERO);
262 
263 	pxd->pxd_unit = minor(dev);
264 	mtx_init(&pxd->pxd_rsel_mtx, IPL_NET);
265 	mtx_init(&pxd->pxd_wsel_mtx, IPL_NET);
266 	LIST_INIT(&pxd->pxd_pxis);
267 
268 	mq_init(&pxd->pxd_svcq, 128, IPL_NET);
269 	LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry);
270 
271 out:
272 	rw_exit(&pppx_devs_lk);
273 	return (rv);
274 }
275 
276 int
277 pppxread(dev_t dev, struct uio *uio, int ioflag)
278 {
279 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
280 	struct mbuf *m, *m0;
281 	int error = 0;
282 	size_t len;
283 
284 	if (!pxd)
285 		return (ENXIO);
286 
287 	while ((m0 = mq_dequeue(&pxd->pxd_svcq)) == NULL) {
288 		if (ISSET(ioflag, IO_NDELAY))
289 			return (EWOULDBLOCK);
290 
291 		NET_LOCK();
292 		pxd->pxd_waiting = 1;
293 		error = rwsleep(pxd, &netlock,
294 		    (PZERO + 1)|PCATCH, "pppxread", 0);
295 		NET_UNLOCK();
296 		if (error != 0) {
297 			return (error);
298 		}
299 	}
300 
301 	while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
302 		len = ulmin(uio->uio_resid, m0->m_len);
303 		if (len != 0)
304 			error = uiomove(mtod(m0, caddr_t), len, uio);
305 		m = m_free(m0);
306 		m0 = m;
307 	}
308 
309 	m_freem(m0);
310 
311 	return (error);
312 }
313 
314 int
315 pppxwrite(dev_t dev, struct uio *uio, int ioflag)
316 {
317 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
318 	struct pppx_hdr *th;
319 	struct pppx_if	*pxi;
320 	uint32_t proto;
321 	struct mbuf *top, **mp, *m;
322 	int tlen;
323 	int error = 0;
324 	size_t mlen;
325 
326 	if (uio->uio_resid < sizeof(*th) + sizeof(uint32_t) ||
327 	    uio->uio_resid > MCLBYTES)
328 		return (EMSGSIZE);
329 
330 	tlen = uio->uio_resid;
331 
332 	MGETHDR(m, M_DONTWAIT, MT_DATA);
333 	if (m == NULL)
334 		return (ENOBUFS);
335 	mlen = MHLEN;
336 	if (uio->uio_resid >= MINCLSIZE) {
337 		MCLGET(m, M_DONTWAIT);
338 		if (!(m->m_flags & M_EXT)) {
339 			m_free(m);
340 			return (ENOBUFS);
341 		}
342 		mlen = MCLBYTES;
343 	}
344 
345 	top = NULL;
346 	mp = &top;
347 
348 	while (error == 0 && uio->uio_resid > 0) {
349 		m->m_len = ulmin(mlen, uio->uio_resid);
350 		error = uiomove(mtod (m, caddr_t), m->m_len, uio);
351 		*mp = m;
352 		mp = &m->m_next;
353 		if (error == 0 && uio->uio_resid > 0) {
354 			MGET(m, M_DONTWAIT, MT_DATA);
355 			if (m == NULL) {
356 				error = ENOBUFS;
357 				break;
358 			}
359 			mlen = MLEN;
360 			if (uio->uio_resid >= MINCLSIZE) {
361 				MCLGET(m, M_DONTWAIT);
362 				if (!(m->m_flags & M_EXT)) {
363 					error = ENOBUFS;
364 					m_free(m);
365 					break;
366 				}
367 				mlen = MCLBYTES;
368 			}
369 		}
370 	}
371 
372 	if (error) {
373 		m_freem(top);
374 		return (error);
375 	}
376 
377 	top->m_pkthdr.len = tlen;
378 
379 	/* Find the interface */
380 	th = mtod(top, struct pppx_hdr *);
381 	m_adj(top, sizeof(struct pppx_hdr));
382 	pxi = pppx_if_find(pxd, th->pppx_id, th->pppx_proto);
383 	if (pxi == NULL) {
384 		m_freem(top);
385 		return (EINVAL);
386 	}
387 	top->m_pkthdr.ph_ifidx = pxi->pxi_if.if_index;
388 
389 #if NBPFILTER > 0
390 	if (pxi->pxi_if.if_bpf)
391 		bpf_mtap(pxi->pxi_if.if_bpf, top, BPF_DIRECTION_IN);
392 #endif
393 	/* strip the tunnel header */
394 	proto = ntohl(*(uint32_t *)(th + 1));
395 	m_adj(top, sizeof(uint32_t));
396 
397 	NET_LOCK();
398 
399 	switch (proto) {
400 	case AF_INET:
401 		ipv4_input(&pxi->pxi_if, top);
402 		break;
403 #ifdef INET6
404 	case AF_INET6:
405 		ipv6_input(&pxi->pxi_if, top);
406 		break;
407 #endif
408 	default:
409 		m_freem(top);
410 		error = EAFNOSUPPORT;
411 		break;
412 	}
413 
414 	NET_UNLOCK();
415 
416 	return (error);
417 }
418 
419 int
420 pppxioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
421 {
422 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
423 	int error = 0;
424 
425 	NET_LOCK();
426 	switch (cmd) {
427 	case PIPEXSMODE:
428 		/*
429 		 * npppd always enables on open, and only disables before
430 		 * closing. we cheat and let open and close do that, so lie
431 		 * to npppd.
432 		 */
433 		break;
434 	case PIPEXGMODE:
435 		*(int *)addr = 1;
436 		break;
437 
438 	case PIPEXASESSION:
439 		error = pppx_add_session(pxd,
440 		    (struct pipex_session_req *)addr);
441 		break;
442 
443 	case PIPEXDSESSION:
444 		error = pppx_del_session(pxd,
445 		    (struct pipex_session_close_req *)addr);
446 		break;
447 
448 	case PIPEXCSESSION:
449 		error = pipex_config_session(
450 		    (struct pipex_session_config_req *)addr);
451 		break;
452 
453 	case PIPEXGSTAT:
454 		error = pipex_get_stat((struct pipex_session_stat_req *)addr);
455 		break;
456 
457 	case PIPEXGCLOSED:
458 		error = pipex_get_closed((struct pipex_session_list_req *)addr);
459 		break;
460 
461 	case PIPEXSIFDESCR:
462 		error = pppx_set_session_descr(pxd,
463 		    (struct pipex_session_descr_req *)addr);
464 		break;
465 
466 	case FIONBIO:
467 	case FIOASYNC:
468 	case FIONREAD:
469 		break;
470 
471 	default:
472 		error = ENOTTY;
473 		break;
474 	}
475 	NET_UNLOCK();
476 
477 	return (error);
478 }
479 
480 int
481 pppxpoll(dev_t dev, int events, struct proc *p)
482 {
483 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
484 	int revents = 0;
485 
486 	if (events & (POLLIN | POLLRDNORM)) {
487 		if (!mq_empty(&pxd->pxd_svcq))
488 			revents |= events & (POLLIN | POLLRDNORM);
489 	}
490 	if (events & (POLLOUT | POLLWRNORM))
491 		revents |= events & (POLLOUT | POLLWRNORM);
492 
493 	if (revents == 0) {
494 		if (events & (POLLIN | POLLRDNORM))
495 			selrecord(p, &pxd->pxd_rsel);
496 	}
497 
498 	return (revents);
499 }
500 
501 int
502 pppxkqfilter(dev_t dev, struct knote *kn)
503 {
504 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
505 	struct mutex *mtx;
506 	struct klist *klist;
507 
508 	switch (kn->kn_filter) {
509 	case EVFILT_READ:
510 		mtx = &pxd->pxd_rsel_mtx;
511 		klist = &pxd->pxd_rsel.si_note;
512 		kn->kn_fop = &pppx_rd_filtops;
513 		break;
514 	case EVFILT_WRITE:
515 		mtx = &pxd->pxd_wsel_mtx;
516 		klist = &pxd->pxd_wsel.si_note;
517 		kn->kn_fop = &pppx_wr_filtops;
518 		break;
519 	default:
520 		return (EINVAL);
521 	}
522 
523 	kn->kn_hook = (caddr_t)pxd;
524 
525 	mtx_enter(mtx);
526 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
527 	mtx_leave(mtx);
528 
529 	return (0);
530 }
531 
532 void
533 filt_pppx_rdetach(struct knote *kn)
534 {
535 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
536 	struct klist *klist = &pxd->pxd_rsel.si_note;
537 
538 	if (ISSET(kn->kn_status, KN_DETACHED))
539 		return;
540 
541 	mtx_enter(&pxd->pxd_rsel_mtx);
542 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
543 	mtx_leave(&pxd->pxd_rsel_mtx);
544 }
545 
546 int
547 filt_pppx_read(struct knote *kn, long hint)
548 {
549 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
550 
551 	if (ISSET(kn->kn_status, KN_DETACHED)) {
552 		kn->kn_data = 0;
553 		return (1);
554 	}
555 
556 	kn->kn_data = mq_len(&pxd->pxd_svcq);
557 
558 	return (kn->kn_data > 0);
559 }
560 
561 void
562 filt_pppx_wdetach(struct knote *kn)
563 {
564 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
565 	struct klist *klist = &pxd->pxd_wsel.si_note;
566 
567 	if (ISSET(kn->kn_status, KN_DETACHED))
568 		return;
569 
570 	mtx_enter(&pxd->pxd_wsel_mtx);
571 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
572 	mtx_leave(&pxd->pxd_wsel_mtx);
573 }
574 
575 int
576 filt_pppx_write(struct knote *kn, long hint)
577 {
578 	/* We're always ready to accept a write. */
579 	return (1);
580 }
581 
582 int
583 pppxclose(dev_t dev, int flags, int mode, struct proc *p)
584 {
585 	struct pppx_dev *pxd;
586 	struct pppx_if	*pxi;
587 
588 	rw_enter_write(&pppx_devs_lk);
589 
590 	pxd = pppx_dev_lookup(dev);
591 
592 	/* XXX */
593 	NET_LOCK();
594 	while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
595 		pppx_if_destroy(pxd, pxi);
596 	NET_UNLOCK();
597 
598 	LIST_REMOVE(pxd, pxd_entry);
599 
600 	mq_purge(&pxd->pxd_svcq);
601 
602 	free(pxd, M_DEVBUF, 0);
603 
604 	if (LIST_EMPTY(&pppx_devs)) {
605 		pool_destroy(pppx_if_pl);
606 		free(pppx_if_pl, M_DEVBUF, 0);
607 		pppx_if_pl = NULL;
608 	}
609 
610 	rw_exit_write(&pppx_devs_lk);
611 	return (0);
612 }
613 
614 int
615 pppx_if_next_unit(void)
616 {
617 	struct pppx_if *pxi;
618 	int unit = 0;
619 
620 	rw_assert_wrlock(&pppx_ifs_lk);
621 
622 	/* this is safe without splnet since we're not modifying it */
623 	do {
624 		int found = 0;
625 		RBT_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
626 			if (pxi->pxi_unit == unit) {
627 				found = 1;
628 				break;
629 			}
630 		}
631 
632 		if (found == 0)
633 			break;
634 		unit++;
635 	} while (unit > 0);
636 
637 	return (unit);
638 }
639 
640 struct pppx_if *
641 pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
642 {
643 	struct pppx_if *s, *p;
644 	s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
645 
646 	s->pxi_key.pxik_session_id = session_id;
647 	s->pxi_key.pxik_protocol = protocol;
648 
649 	rw_enter_read(&pppx_ifs_lk);
650 	p = RBT_FIND(pppx_ifs, &pppx_ifs, s);
651 	if (p && p->pxi_ready == 0)
652 		p = NULL;
653 	rw_exit_read(&pppx_ifs_lk);
654 
655 	free(s, M_DEVBUF, 0);
656 	return (p);
657 }
658 
659 int
660 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
661 {
662 	struct pppx_if *pxi;
663 	struct pipex_session *session;
664 	struct pipex_hash_head *chain;
665 	struct ifnet *ifp;
666 	int unit, error = 0;
667 	struct in_ifaddr *ia;
668 	struct sockaddr_in ifaddr;
669 #ifdef PIPEX_PPPOE
670 	struct ifnet *over_ifp = NULL;
671 #endif
672 
673 	switch (req->pr_protocol) {
674 #ifdef PIPEX_PPPOE
675 	case PIPEX_PROTO_PPPOE:
676 		over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
677 		if (over_ifp == NULL)
678 			return (EINVAL);
679 		if (req->pr_peer_address.ss_family != AF_UNSPEC)
680 			return (EINVAL);
681 		break;
682 #endif
683 #ifdef PIPEX_PPTP
684 	case PIPEX_PROTO_PPTP:
685 #endif
686 #ifdef PIPEX_L2TP
687 	case PIPEX_PROTO_L2TP:
688 #endif
689 		switch (req->pr_peer_address.ss_family) {
690 		case AF_INET:
691 			if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in))
692 				return (EINVAL);
693 			break;
694 #ifdef INET6
695 		case AF_INET6:
696 			if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in6))
697 				return (EINVAL);
698 			break;
699 #endif
700 		default:
701 			return (EPROTONOSUPPORT);
702 		}
703 		if (req->pr_peer_address.ss_family !=
704 		    req->pr_local_address.ss_family ||
705 		    req->pr_peer_address.ss_len !=
706 		    req->pr_local_address.ss_len)
707 			return (EINVAL);
708 		break;
709 	default:
710 		return (EPROTONOSUPPORT);
711 	}
712 
713 	pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
714 	if (pxi == NULL)
715 		return (ENOMEM);
716 
717 	session = &pxi->pxi_session;
718 	ifp = &pxi->pxi_if;
719 
720 	/* fake a pipex interface context */
721 	session->pipex_iface = &pxi->pxi_ifcontext;
722 	session->pipex_iface->ifnet_this = ifp;
723 	session->pipex_iface->pipexmode = PIPEX_ENABLED;
724 
725 	/* setup session */
726 	session->state = PIPEX_STATE_OPENED;
727 	session->protocol = req->pr_protocol;
728 	session->session_id = req->pr_session_id;
729 	session->peer_session_id = req->pr_peer_session_id;
730 	session->peer_mru = req->pr_peer_mru;
731 	session->timeout_sec = req->pr_timeout_sec;
732 	session->ppp_flags = req->pr_ppp_flags;
733 	session->ppp_id = req->pr_ppp_id;
734 
735 	session->ip_forward = 1;
736 
737 	session->ip_address.sin_family = AF_INET;
738 	session->ip_address.sin_len = sizeof(struct sockaddr_in);
739 	session->ip_address.sin_addr = req->pr_ip_address;
740 
741 	session->ip_netmask.sin_family = AF_INET;
742 	session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
743 	session->ip_netmask.sin_addr = req->pr_ip_netmask;
744 
745 	if (session->ip_netmask.sin_addr.s_addr == 0L)
746 		session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
747 	session->ip_address.sin_addr.s_addr &=
748 	    session->ip_netmask.sin_addr.s_addr;
749 
750 	if (req->pr_peer_address.ss_len > 0)
751 		memcpy(&session->peer, &req->pr_peer_address,
752 		    MIN(req->pr_peer_address.ss_len, sizeof(session->peer)));
753 	if (req->pr_local_address.ss_len > 0)
754 		memcpy(&session->local, &req->pr_local_address,
755 		    MIN(req->pr_local_address.ss_len, sizeof(session->local)));
756 #ifdef PIPEX_PPPOE
757 	if (req->pr_protocol == PIPEX_PROTO_PPPOE)
758 		session->proto.pppoe.over_ifidx = over_ifp->if_index;
759 #endif
760 #ifdef PIPEX_PPTP
761 	if (req->pr_protocol == PIPEX_PROTO_PPTP) {
762 		struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
763 
764 		sess_pptp->snd_gap = 0;
765 		sess_pptp->rcv_gap = 0;
766 		sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
767 		sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
768 		sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
769 		sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
770 
771 		sess_pptp->winsz = req->pr_proto.pptp.winsz;
772 		sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
773 		sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
774 		/* last ack number */
775 		sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
776 	}
777 #endif
778 #ifdef PIPEX_L2TP
779 	if (req->pr_protocol == PIPEX_PROTO_L2TP) {
780 		struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
781 
782 		/* session keys */
783 		sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
784 		sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
785 
786 		/* protocol options */
787 		sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
788 
789 		/* initial state of dynamic context */
790 		sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
791 		sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
792 		sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
793 		sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
794 		sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
795 		/* last ack number */
796 		sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
797 	}
798 #endif
799 #ifdef PIPEX_MPPE
800 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
801 		pipex_session_init_mppe_recv(session,
802 		    req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
803 		    req->pr_mppe_recv.master_key);
804 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
805 		pipex_session_init_mppe_send(session,
806 		    req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
807 		    req->pr_mppe_send.master_key);
808 
809 	if (pipex_session_is_mppe_required(session)) {
810 		if (!pipex_session_is_mppe_enabled(session) ||
811 		    !pipex_session_is_mppe_accepted(session)) {
812 			pool_put(pppx_if_pl, pxi);
813 			return (EINVAL);
814 		}
815 	}
816 #endif
817 
818 	/* try to set the interface up */
819 	rw_enter_write(&pppx_ifs_lk);
820 	unit = pppx_if_next_unit();
821 	if (unit < 0) {
822 		pool_put(pppx_if_pl, pxi);
823 		error = ENOMEM;
824 		rw_exit_write(&pppx_ifs_lk);
825 		goto out;
826 	}
827 
828 	pxi->pxi_unit = unit;
829 	pxi->pxi_key.pxik_session_id = req->pr_session_id;
830 	pxi->pxi_key.pxik_protocol = req->pr_protocol;
831 	pxi->pxi_dev = pxd;
832 
833 	/* this is safe without splnet since we're not modifying it */
834 	if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
835 		pool_put(pppx_if_pl, pxi);
836 		error = EADDRINUSE;
837 		rw_exit_write(&pppx_ifs_lk);
838 		goto out;
839 	}
840 
841 	if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
842 		panic("%s: pppx_ifs modified while lock was held", __func__);
843 	LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
844 	rw_exit_write(&pppx_ifs_lk);
845 
846 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
847 	ifp->if_mtu = req->pr_peer_mru;	/* XXX */
848 	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
849 	ifp->if_start = pppx_if_start;
850 	ifp->if_output = pppx_if_output;
851 	ifp->if_ioctl = pppx_if_ioctl;
852 	ifp->if_rtrequest = p2p_rtrequest;
853 	ifp->if_type = IFT_PPP;
854 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
855 	ifp->if_softc = pxi;
856 	/* ifp->if_rdomain = req->pr_rdomain; */
857 
858 	/* hook up pipex context */
859 	chain = PIPEX_ID_HASHTABLE(session->session_id);
860 	LIST_INSERT_HEAD(chain, session, id_chain);
861 	LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
862 	switch (req->pr_protocol) {
863 	case PIPEX_PROTO_PPTP:
864 	case PIPEX_PROTO_L2TP:
865 		chain = PIPEX_PEER_ADDR_HASHTABLE(
866 		    pipex_sockaddr_hash_key(&session->peer.sa));
867 		LIST_INSERT_HEAD(chain, session, peer_addr_chain);
868 		break;
869 	}
870 
871 	/* if first session is added, start timer */
872 	if (LIST_NEXT(session, session_list) == NULL)
873 		pipex_timer_start();
874 
875 	/* XXXSMP breaks atomicity */
876 	NET_UNLOCK();
877 	if_attach(ifp);
878 	NET_LOCK();
879 
880 	if_addgroup(ifp, "pppx");
881 	if_alloc_sadl(ifp);
882 
883 #if NBPFILTER > 0
884 	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
885 #endif
886 	SET(ifp->if_flags, IFF_RUNNING);
887 
888 	/* XXX ipv6 support?  how does the caller indicate it wants ipv6
889 	 * instead of ipv4?
890 	 */
891 	memset(&ifaddr, 0, sizeof(ifaddr));
892 	ifaddr.sin_family = AF_INET;
893 	ifaddr.sin_len = sizeof(ifaddr);
894 	ifaddr.sin_addr = req->pr_ip_srcaddr;
895 
896 	ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
897 
898 	ia->ia_addr.sin_family = AF_INET;
899 	ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
900 	ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
901 
902 	ia->ia_dstaddr.sin_family = AF_INET;
903 	ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
904 	ia->ia_dstaddr.sin_addr = req->pr_ip_address;
905 
906 	ia->ia_sockmask.sin_family = AF_INET;
907 	ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
908 	ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
909 
910 	ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
911 	ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
912 	ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
913 	ia->ia_ifa.ifa_ifp = ifp;
914 
915 	ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
916 
917 	error = in_ifinit(ifp, ia, &ifaddr, 1);
918 	if (error) {
919 		printf("pppx: unable to set addresses for %s, error=%d\n",
920 		    ifp->if_xname, error);
921 	} else {
922 		dohooks(ifp->if_addrhooks, 0);
923 	}
924 	rw_enter_write(&pppx_ifs_lk);
925 	pxi->pxi_ready = 1;
926 	rw_exit_write(&pppx_ifs_lk);
927 
928 out:
929 	return (error);
930 }
931 
932 int
933 pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
934 {
935 	struct pppx_if *pxi;
936 
937 	pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
938 	if (pxi == NULL)
939 		return (EINVAL);
940 
941 	req->pcr_stat = pxi->pxi_session.stat;
942 
943 	pppx_if_destroy(pxd, pxi);
944 	return (0);
945 }
946 
947 int
948 pppx_set_session_descr(struct pppx_dev *pxd,
949     struct pipex_session_descr_req *req)
950 {
951 	struct pppx_if *pxi;
952 
953 	pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
954 	if (pxi == NULL)
955 		return (EINVAL);
956 
957 	(void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
958 	strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
959 
960 	return (0);
961 }
962 
963 void
964 pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
965 {
966 	struct ifnet *ifp;
967 	struct pipex_session *session;
968 
969 	NET_ASSERT_LOCKED();
970 	session = &pxi->pxi_session;
971 	ifp = &pxi->pxi_if;
972 
973 	LIST_REMOVE(session, id_chain);
974 	LIST_REMOVE(session, session_list);
975 	switch (session->protocol) {
976 	case PIPEX_PROTO_PPTP:
977 	case PIPEX_PROTO_L2TP:
978 		LIST_REMOVE((struct pipex_session *)session,
979 		    peer_addr_chain);
980 		break;
981 	}
982 
983 	/* if final session is destroyed, stop timer */
984 	if (LIST_EMPTY(&pipex_session_list))
985 		pipex_timer_stop();
986 
987 	/* XXXSMP breaks atomicity */
988 	NET_UNLOCK();
989 	if_detach(ifp);
990 	NET_LOCK();
991 
992 	rw_enter_write(&pppx_ifs_lk);
993 	if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
994 		panic("%s: pppx_ifs modified while lock was held", __func__);
995 	LIST_REMOVE(pxi, pxi_list);
996 	rw_exit_write(&pppx_ifs_lk);
997 
998 	pool_put(pppx_if_pl, pxi);
999 }
1000 
1001 void
1002 pppx_if_start(struct ifnet *ifp)
1003 {
1004 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1005 	struct mbuf *m;
1006 	int proto;
1007 
1008 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1009 		return;
1010 
1011 	for (;;) {
1012 		IFQ_DEQUEUE(&ifp->if_snd, m);
1013 
1014 		if (m == NULL)
1015 			break;
1016 
1017 		proto = *mtod(m, int *);
1018 		m_adj(m, sizeof(proto));
1019 
1020 		ifp->if_obytes += m->m_pkthdr.len;
1021 		ifp->if_opackets++;
1022 
1023 		pipex_ppp_output(m, &pxi->pxi_session, proto);
1024 	}
1025 }
1026 
1027 int
1028 pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1029     struct rtentry *rt)
1030 {
1031 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1032 	struct pppx_hdr *th;
1033 	int error = 0;
1034 	int proto;
1035 
1036 	NET_ASSERT_LOCKED();
1037 
1038 	if (!ISSET(ifp->if_flags, IFF_UP)) {
1039 		m_freem(m);
1040 		error = ENETDOWN;
1041 		goto out;
1042 	}
1043 
1044 #if NBPFILTER > 0
1045 	if (ifp->if_bpf)
1046 		bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
1047 #endif
1048 	if (pipex_enable) {
1049 		switch (dst->sa_family) {
1050 #ifdef INET6
1051 		case AF_INET6:
1052 			proto = PPP_IPV6;
1053 			break;
1054 #endif
1055 		case AF_INET:
1056 			proto = PPP_IP;
1057 			break;
1058 		default:
1059 			m_freem(m);
1060 			error = EPFNOSUPPORT;
1061 			goto out;
1062 		}
1063 	} else
1064 		proto = htonl(dst->sa_family);
1065 
1066 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
1067 	if (m == NULL) {
1068 		error = ENOBUFS;
1069 		goto out;
1070 	}
1071 	*mtod(m, int *) = proto;
1072 
1073 	if (pipex_enable)
1074 		error = if_enqueue(ifp, m);
1075 	else {
1076 		M_PREPEND(m, sizeof(struct pppx_hdr), M_DONTWAIT);
1077 		if (m == NULL) {
1078 			error = ENOBUFS;
1079 			goto out;
1080 		}
1081 		th = mtod(m, struct pppx_hdr *);
1082 		th->pppx_proto = 0;	/* not used */
1083 		th->pppx_id = pxi->pxi_session.ppp_id;
1084 		rw_enter_read(&pppx_devs_lk);
1085 		error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m);
1086 		if (error == 0) {
1087 			if (pxi->pxi_dev->pxd_waiting) {
1088 				wakeup((caddr_t)pxi->pxi_dev);
1089 				pxi->pxi_dev->pxd_waiting = 0;
1090 			}
1091 			selwakeup(&pxi->pxi_dev->pxd_rsel);
1092 		}
1093 		rw_exit_read(&pppx_devs_lk);
1094 	}
1095 
1096 out:
1097 	if (error)
1098 		ifp->if_oerrors++;
1099 	return (error);
1100 }
1101 
1102 int
1103 pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
1104 {
1105 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1106 	struct ifreq *ifr = (struct ifreq *)addr;
1107 	int error = 0;
1108 
1109 	switch (cmd) {
1110 	case SIOCSIFADDR:
1111 		break;
1112 
1113 	case SIOCSIFFLAGS:
1114 		break;
1115 
1116 	case SIOCADDMULTI:
1117 	case SIOCDELMULTI:
1118 		break;
1119 
1120 	case SIOCSIFMTU:
1121 		if (ifr->ifr_mtu < 512 ||
1122 		    ifr->ifr_mtu > pxi->pxi_session.peer_mru)
1123 			error = EINVAL;
1124 		else
1125 			ifp->if_mtu = ifr->ifr_mtu;
1126 		break;
1127 
1128 	default:
1129 		error = ENOTTY;
1130 		break;
1131 	}
1132 
1133 	return (error);
1134 }
1135 
1136 RBT_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
1137