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