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