xref: /openbsd-src/sys/net/if_pppx.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: if_pppx.c,v 1.11 2011/08/21 09:00:15 jmatthew 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 	do {
633 		int found = 0;
634 		RB_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
635 			if (pxi->pxi_unit == unit) {
636 				found = 1;
637 				break;
638 			}
639 		}
640 
641 		if (found == 0)
642 			break;
643 		unit++;
644 	} while (unit > 0);
645 
646 	return (unit);
647 }
648 
649 struct pppx_if *
650 pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
651 {
652 	struct pppx_if *s, *p;
653 	s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
654 
655 	s->pxi_key.pxik_session_id = session_id;
656 	s->pxi_key.pxik_protocol = protocol;
657 
658 	rw_enter_read(&pppx_ifs_lk);
659 	p = RB_FIND(pppx_ifs, &pppx_ifs, s);
660 	rw_exit_read(&pppx_ifs_lk);
661 
662 	free(s, M_DEVBUF);
663 	return (p);
664 }
665 
666 int
667 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
668 {
669 	struct pppx_if *pxi;
670 	struct pipex_session *session;
671 	struct pipex_hash_head *chain;
672 	struct ifnet *ifp;
673 	int unit, s, error = 0;
674 	struct in_ifaddr *ia;
675 	struct sockaddr_in ifaddr;
676 #ifdef PIPEX_PPPOE
677 	struct ifnet *over_ifp = NULL;
678 #endif
679 
680 	switch (req->pr_protocol) {
681 #ifdef PIPEX_PPPOE
682 	case PIPEX_PROTO_PPPOE:
683 		over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
684 		if (over_ifp == NULL)
685 			return (EINVAL);
686 		if (req->peer_address.ss_family != AF_UNSPEC)
687 			return (EINVAL);
688 		break;
689 #endif
690 #ifdef PIPEX_PPTP
691 	case PIPEX_PROTO_PPTP:
692 #endif
693 #ifdef PIPEX_L2TP
694 	case PIPEX_PROTO_L2TP:
695 #endif
696 		switch (req->peer_address.ss_family) {
697 		case AF_INET:
698 			if (req->peer_address.ss_len != sizeof(struct sockaddr_in))
699 				return (EINVAL);
700 			break;
701 #ifdef INET6
702 		case AF_INET6:
703 			if (req->peer_address.ss_len != sizeof(struct sockaddr_in6))
704 				return (EINVAL);
705 			break;
706 #endif
707 		default:
708 			return (EPROTONOSUPPORT);
709 		}
710 		if (req->peer_address.ss_family !=
711 		    req->local_address.ss_family ||
712 		    req->peer_address.ss_len !=
713 		    req->local_address.ss_len)
714 			return (EINVAL);
715 		break;
716 	default:
717 		return (EPROTONOSUPPORT);
718 	}
719 
720 	pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
721 	if (pxi == NULL)
722 		return (ENOMEM);
723 
724 	session = &pxi->pxi_session;
725 	ifp = &pxi->pxi_if;
726 
727 	/* fake a pipex interface context */
728 	session->pipex_iface = &pxi->pxi_ifcontext;
729 	session->pipex_iface->ifnet_this = ifp;
730 	session->pipex_iface->pipexmode = PIPEX_ENABLED;
731 
732 	/* setup session */
733 	session->state = PIPEX_STATE_OPENED;
734 	session->protocol = req->pr_protocol;
735 	session->session_id = req->pr_session_id;
736 	session->peer_session_id = req->pr_peer_session_id;
737 	session->peer_mru = req->pr_peer_mru;
738 	session->timeout_sec = req->pr_timeout_sec;
739 	session->ppp_flags = req->pr_ppp_flags;
740 	session->ppp_id = req->pr_ppp_id;
741 
742 	session->ip_forward = 1;
743 
744 	session->ip_address.sin_family = AF_INET;
745 	session->ip_address.sin_len = sizeof(struct sockaddr_in);
746 	session->ip_address.sin_addr = req->pr_ip_address;
747 
748 	session->ip_netmask.sin_family = AF_INET;
749 	session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
750 	session->ip_netmask.sin_addr = req->pr_ip_netmask;
751 
752 	if (session->ip_netmask.sin_addr.s_addr == 0L)
753 		session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
754 	session->ip_address.sin_addr.s_addr &=
755 	    session->ip_netmask.sin_addr.s_addr;
756 
757 	if (req->peer_address.ss_len > 0)
758 		memcpy(&session->peer, &req->peer_address,
759 		    MIN(req->peer_address.ss_len, sizeof(session->peer)));
760 	if (req->local_address.ss_len > 0)
761 		memcpy(&session->local, &req->local_address,
762 		    MIN(req->local_address.ss_len, sizeof(session->local)));
763 #ifdef PIPEX_PPPOE
764 	if (req->pr_protocol == PIPEX_PROTO_PPPOE)
765 		session->proto.pppoe.over_ifp = over_ifp;
766 #endif
767 #ifdef PIPEX_PPTP
768 	if (req->pr_protocol == PIPEX_PROTO_PPTP) {
769 		struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
770 
771 		sess_pptp->snd_gap = 0;
772 		sess_pptp->rcv_gap = 0;
773 		sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
774 		sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
775 		sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
776 		sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
777 
778 		sess_pptp->winsz = req->pr_proto.pptp.winsz;
779 		sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
780 		sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
781 		/* last ack number */
782 		sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
783 	}
784 #endif
785 #ifdef PIPEX_L2TP
786 	if (req->pr_protocol == PIPEX_PROTO_L2TP) {
787 		struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
788 
789 		/* session keys */
790 		sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
791 		sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
792 
793 		/* protocol options */
794 		sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
795 
796 		/* initial state of dynamic context */
797 		sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
798 		sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
799 		sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
800 		sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
801 		sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
802 		/* last ack number */
803 		sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
804 	}
805 #endif
806 #ifdef PIPEX_MPPE
807 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
808 		pipex_mppe_req_init(&req->pr_mppe_recv, &session->mppe_recv);
809 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
810 		pipex_mppe_req_init(&req->pr_mppe_send, &session->mppe_send);
811 
812 	if (pipex_session_is_mppe_required(session)) {
813 		if (!pipex_session_is_mppe_enabled(session) ||
814 		    !pipex_session_is_mppe_accepted(session)) {
815 			pool_put(pppx_if_pl, pxi);
816 			return (EINVAL);
817 		}
818 	}
819 #endif
820 
821 	/* try to set the interface up */
822 	rw_enter_write(&pppx_ifs_lk);
823 	unit = pppx_if_next_unit();
824 	if (unit < 0) {
825 		pool_put(pppx_if_pl, pxi);
826 		error = ENOMEM;
827 		goto out;
828 	}
829 
830 	pxi->pxi_unit = unit;
831 	pxi->pxi_key.pxik_session_id = req->pr_session_id;
832 	pxi->pxi_key.pxik_protocol = req->pr_protocol;
833 
834 	/* this is safe without splnet since we're not modifying it */
835 	if (RB_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
836 		pool_put(pppx_if_pl, pxi);
837 		error = EADDRINUSE;
838 		goto out;
839 	}
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_type = IFT_PPP;
848 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
849 	IFQ_SET_READY(&ifp->if_snd);
850 	ifp->if_softc = pxi;
851 	/* ifp->if_rdomain = req->pr_rdomain; */
852 
853 	s = splnet();
854 
855 	/* hook up pipex context */
856 	chain = PIPEX_ID_HASHTABLE(session->session_id);
857 	LIST_INSERT_HEAD(chain, session, id_chain);
858 	LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
859 	switch (req->pr_protocol) {
860 	case PIPEX_PROTO_PPTP:
861 	case PIPEX_PROTO_L2TP:
862 		chain = PIPEX_PEER_ADDR_HASHTABLE(
863 		    pipex_sockaddr_hash_key((struct sockaddr *)&session->peer));
864 		LIST_INSERT_HEAD(chain, session, peer_addr_chain);
865 		break;
866 	}
867 
868 	/* if first session is added, start timer */
869 	if (LIST_NEXT(session, session_list) == NULL)
870 		pipex_timer_start();
871 
872 	if_attach(ifp);
873 	if_alloc_sadl(ifp);
874 
875 #if NBPFILTER > 0
876 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, 0);
877 #endif
878 	SET(ifp->if_flags, IFF_RUNNING);
879 
880 	if (RB_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
881 		panic("pppx_ifs modified while lock was held");
882 	LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
883 
884 	/* XXX ipv6 support?  how does the caller indicate it wants ipv6
885 	 * instead of ipv4?
886 	 */
887 	memset(&ifaddr, 0, sizeof(ifaddr));
888 	ifaddr.sin_family = AF_INET;
889 	ifaddr.sin_len = sizeof(ifaddr);
890 	ifaddr.sin_addr = req->pr_ip_srcaddr;
891 
892 	ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
893 	TAILQ_INSERT_TAIL(&in_ifaddr, ia, ia_list);
894 
895 	ia->ia_addr.sin_family = AF_INET;
896 	ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
897 	ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
898 
899 	ia->ia_dstaddr.sin_family = AF_INET;
900 	ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
901 	ia->ia_dstaddr.sin_addr = req->pr_ip_address;
902 
903 	ia->ia_sockmask.sin_family = AF_INET;
904 	ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
905 	ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
906 
907 	ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
908 	ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
909 	ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
910 	ia->ia_ifa.ifa_ifp = ifp;
911 
912 	ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
913 
914 	error = in_ifinit(ifp, ia, &ifaddr, 0, 1);
915 	if (error) {
916 		printf("pppx: unable to set addresses for %s, error=%d\n",
917 		    ifp->if_xname, error);
918 	} else {
919 		dohooks(ifp->if_addrhooks, 0);
920 	}
921 	splx(s);
922 
923 out:
924 	rw_exit_write(&pppx_ifs_lk);
925 
926 	return (error);
927 }
928 
929 int
930 pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
931 {
932 	struct pppx_if *pxi;
933 
934 	pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
935 	if (pxi == NULL)
936 		return (EINVAL);
937 
938 	req->pcr_stat = pxi->pxi_session.stat;
939 
940 	pppx_if_destroy(pxd, pxi);
941 	return (0);
942 }
943 
944 int
945 pppx_set_session_descr(struct pppx_dev *pxd,
946     struct pipex_session_descr_req *req)
947 {
948 	struct pppx_if *pxi;
949 
950 	pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
951 	if (pxi == NULL)
952 		return (EINVAL);
953 
954 	(void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
955 	strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
956 
957 	return (0);
958 }
959 
960 void
961 pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
962 {
963 	struct ifnet *ifp;
964 	struct pipex_session *session;
965 	int s;
966 
967 	session = &pxi->pxi_session;
968 	ifp = &pxi->pxi_if;
969 
970 	s = splnet();
971 	LIST_REMOVE(session, id_chain);
972 	LIST_REMOVE(session, session_list);
973 	switch (session->protocol) {
974 	case PIPEX_PROTO_PPTP:
975 	case PIPEX_PROTO_L2TP:
976 		LIST_REMOVE((struct pipex_session *)session,
977 		    peer_addr_chain);
978 		break;
979 	}
980 
981 	/* if final session is destroyed, stop timer */
982 	if (LIST_EMPTY(&pipex_session_list))
983 		pipex_timer_stop();
984 	splx(s);
985 
986 	if_detach(ifp);
987 
988 	rw_enter_write(&pppx_ifs_lk);
989 	if (RB_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
990 		panic("pppx_ifs modified while lock was held");
991 	LIST_REMOVE(pxi, pxi_list);
992 	rw_exit_write(&pppx_ifs_lk);
993 
994 	pool_put(pppx_if_pl, pxi);
995 }
996 
997 void
998 pppx_if_start(struct ifnet *ifp)
999 {
1000 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1001 	struct mbuf *m;
1002 	int proto, s;
1003 
1004 	if (ISSET(ifp->if_flags, IFF_OACTIVE))
1005 		return;
1006 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1007 		return;
1008 
1009 	for (;;) {
1010 		s = splnet();
1011 		IFQ_DEQUEUE(&ifp->if_snd, m);
1012 		splx(s);
1013 
1014 		if (m == NULL)
1015 			break;
1016 
1017 		proto = *mtod(m, int *);
1018 		m_adj(m, sizeof(proto));
1019 
1020 #if NBPFILTER > 0
1021 		if (ifp->if_bpf) {
1022 			switch (proto) {
1023 			case PPP_IP:
1024 				bpf_mtap_af(ifp->if_bpf, AF_INET, m,
1025 					BPF_DIRECTION_OUT);
1026 				break;
1027 			case PPP_IPV6:
1028 				bpf_mtap_af(ifp->if_bpf, AF_INET6, m,
1029 					BPF_DIRECTION_OUT);
1030 				break;
1031 			}
1032 		}
1033 #endif
1034 
1035 		ifp->if_obytes += m->m_pkthdr.len;
1036 		ifp->if_opackets++;
1037 
1038 		pipex_ppp_output(m, &pxi->pxi_session, proto);
1039 	}
1040 }
1041 
1042 int
1043 pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1044     struct rtentry *rt)
1045 {
1046 	int error = 0;
1047 	int proto, s;
1048 
1049 	if (!ISSET(ifp->if_flags, IFF_UP)) {
1050 		m_freem(m);
1051 		error = ENETDOWN;
1052 		goto out;
1053 	}
1054 
1055 	switch (dst->sa_family) {
1056 	case AF_INET:
1057 		proto = PPP_IP;
1058 		break;
1059 	default:
1060 		m_freem(m);
1061 		error = EPFNOSUPPORT;
1062 		goto out;
1063 	}
1064 
1065 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
1066 	if (m == NULL) {
1067 		error = ENOBUFS;
1068 		goto out;
1069 	}
1070 	*mtod(m, int *) = proto;
1071 
1072 	s = splnet();
1073 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
1074 	if (error) {
1075 		splx(s);
1076 		goto out;
1077 	}
1078 	if_start(ifp);
1079 	splx(s);
1080 
1081 out:
1082 	if (error)
1083 		ifp->if_oerrors++;
1084 	return (error);
1085 }
1086 
1087 int
1088 pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
1089 {
1090 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1091 	struct ifreq *ifr = (struct ifreq *)addr;
1092 	int error = 0;
1093 
1094 	switch (cmd) {
1095 	case SIOCSIFADDR:
1096 	case SIOCSIFFLAGS:
1097 		break;
1098 
1099 	case SIOCADDMULTI:
1100 	case SIOCDELMULTI:
1101 		switch (ifr->ifr_addr.sa_family) {
1102 #ifdef INET
1103 		case AF_INET:
1104 			break;
1105 #endif
1106 #ifdef INET6
1107 		case AF_INET6:
1108 			break;
1109 #endif
1110 		default:
1111 			error = EAFNOSUPPORT;
1112 			break;
1113 		}
1114 		break;
1115 
1116 	case SIOCSIFMTU:
1117 		if (ifr->ifr_mtu < 512 ||
1118 		    ifr->ifr_mtu > pxi->pxi_session.peer_mru)
1119 			error = EINVAL;
1120 		else
1121 			ifp->if_mtu = ifr->ifr_mtu;
1122 		break;
1123 
1124 	default:
1125 		error = ENOTTY;
1126 		break;
1127 	}
1128 
1129 	return (error);
1130 }
1131 
1132 RB_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
1133