xref: /openbsd-src/sys/net/if_pppx.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: if_pppx.c,v 1.31 2014/07/12 18:44:22 tedu 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/route.h>
67 #include <net/netisr.h>
68 #include <netinet/in.h>
69 #include <netinet/if_ether.h>
70 #include <net/if_dl.h>
71 
72 #ifdef INET
73 #include <netinet/in_systm.h>
74 #include <netinet/in_var.h>
75 #include <netinet/ip.h>
76 #include <netinet/ip_var.h>
77 #endif
78 
79 #ifdef INET6
80 #include <netinet6/in6_var.h>
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 	pxd->pxd_unit = minor(dev);
260 	mtx_init(&pxd->pxd_rsel_mtx, IPL_NET);
261 	mtx_init(&pxd->pxd_wsel_mtx, IPL_NET);
262 	LIST_INIT(&pxd->pxd_pxis);
263 
264 	IFQ_SET_MAXLEN(&pxd->pxd_svcq, 128);
265 	LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry);
266 
267 out:
268 	rw_exit(&pppx_devs_lk);
269 	return (rv);
270 }
271 
272 int
273 pppxread(dev_t dev, struct uio *uio, int ioflag)
274 {
275 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
276 	struct mbuf *m, *m0;
277 	int error = 0;
278 	int len, s;
279 
280 	if (!pxd)
281 		return (ENXIO);
282 
283 	s = splnet();
284 	for (;;) {
285 		IF_DEQUEUE(&pxd->pxd_svcq, m0);
286 		if (m0 != NULL)
287 			break;
288 
289 		if (ISSET(ioflag, IO_NDELAY)) {
290 			splx(s);
291 			return (EWOULDBLOCK);
292 		}
293 
294 		pxd->pxd_waiting = 1;
295 		error = tsleep(pxd, (PZERO + 1)|PCATCH, "pppxread", 0);
296 		if (error != 0) {
297 			splx(s);
298 			return (error);
299 		}
300 	}
301 	splx(s);
302 
303 	while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
304 		len = min(uio->uio_resid, m0->m_len);
305 		if (len != 0)
306 			error = uiomove(mtod(m0, caddr_t), len, uio);
307 		MFREE(m0, m);
308 		m0 = m;
309 	}
310 
311 	if (m0 != NULL)
312 		m_freem(m0);
313 
314 	return (error);
315 }
316 
317 int
318 pppxwrite(dev_t dev, struct uio *uio, int ioflag)
319 {
320 /*	struct pppx_dev *pxd = pppx_dev2pxd(dev);	*/
321 	struct pppx_hdr *th;
322 	struct mbuf *top, **mp, *m;
323 	struct ifqueue *ifq;
324 	int tlen, mlen;
325 	int isr, s, error = 0;
326 
327 	if (uio->uio_resid < sizeof(*th) || 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 = min(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 		if (top != NULL)
374 			m_freem(top);
375 		return (error);
376 	}
377 
378 	top->m_pkthdr.len = tlen;
379 
380 	/* strip the tunnel header */
381 	th = mtod(top, struct pppx_hdr *);
382 	m_adj(top, sizeof(struct pppx_hdr));
383 
384 	switch (ntohl(th->pppx_proto)) {
385 #ifdef INET
386 	case AF_INET:
387 		ifq = &ipintrq;
388 		isr = NETISR_IP;
389 		break;
390 #endif
391 #ifdef INET6
392 	case AF_INET6:
393 		ifq = &ip6intrq;
394 		isr = NETISR_IPV6;
395 		break;
396 #endif
397 	default:
398 		m_freem(top);
399 		return (EAFNOSUPPORT);
400 	}
401 
402 	s = splnet();
403 	if (IF_QFULL(ifq)) {
404 		IF_DROP(ifq);
405 		splx(s);
406 		m_freem(top);
407 		return (ENOBUFS);
408 	}
409 	IF_ENQUEUE(ifq, top);
410 	schednetisr(isr);
411 	splx(s);
412 
413 	return (error);
414 }
415 
416 int
417 pppxioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
418 {
419 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
420 	int error = 0;
421 
422 	switch (cmd) {
423 	case PIPEXSMODE:
424 		/*
425 		 * npppd always enables on open, and only disables before
426 		 * closing. we cheat and let open and close do that, so lie
427 		 * to npppd.
428 		 */
429 		break;
430 	case PIPEXGMODE:
431 		*(int *)addr = 1;
432 		break;
433 
434 	case PIPEXASESSION:
435 		error = pppx_add_session(pxd,
436 		    (struct pipex_session_req *)addr);
437 		break;
438 
439 	case PIPEXDSESSION:
440 		error = pppx_del_session(pxd,
441 		    (struct pipex_session_close_req *)addr);
442 		break;
443 
444 	case PIPEXCSESSION:
445 		error = pipex_config_session(
446 		    (struct pipex_session_config_req *)addr);
447 		break;
448 
449 	case PIPEXGSTAT:
450 		error = pipex_get_stat((struct pipex_session_stat_req *)addr);
451 		break;
452 
453 	case PIPEXGCLOSED:
454 		error = pipex_get_closed((struct pipex_session_list_req *)addr);
455 		break;
456 
457 	case PIPEXSIFDESCR:
458 		error = pppx_set_session_descr(pxd,
459 		    (struct pipex_session_descr_req *)addr);
460 		break;
461 
462 	case FIONBIO:
463 	case FIOASYNC:
464 	case FIONREAD:
465 		return (0);
466 
467 	default:
468 		error = ENOTTY;
469 		break;
470 	}
471 
472 	return (error);
473 }
474 
475 int
476 pppxpoll(dev_t dev, int events, struct proc *p)
477 {
478 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
479 	int s, revents = 0;
480 
481 	if (events & (POLLIN | POLLRDNORM)) {
482 		s = splnet();
483 		if (!IF_IS_EMPTY(&pxd->pxd_svcq))
484 			revents |= events & (POLLIN | POLLRDNORM);
485 		splx(s);
486 	}
487 	if (events & (POLLOUT | POLLWRNORM))
488 		revents |= events & (POLLOUT | POLLWRNORM);
489 
490 	if (revents == 0) {
491 		if (events & (POLLIN | POLLRDNORM))
492 			selrecord(p, &pxd->pxd_rsel);
493 	}
494 
495 	return (revents);
496 }
497 
498 int
499 pppxkqfilter(dev_t dev, struct knote *kn)
500 {
501 	struct pppx_dev *pxd = pppx_dev2pxd(dev);
502 	struct mutex *mtx;
503 	struct klist *klist;
504 
505 	switch (kn->kn_filter) {
506 	case EVFILT_READ:
507 		mtx = &pxd->pxd_rsel_mtx;
508 		klist = &pxd->pxd_rsel.si_note;
509 		kn->kn_fop = &pppx_rd_filtops;
510 		break;
511 	case EVFILT_WRITE:
512 		mtx = &pxd->pxd_wsel_mtx;
513 		klist = &pxd->pxd_wsel.si_note;
514 		kn->kn_fop = &pppx_wr_filtops;
515 		break;
516 	default:
517 		return (EINVAL);
518 	}
519 
520 	kn->kn_hook = (caddr_t)pxd;
521 
522 	mtx_enter(mtx);
523 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
524 	mtx_leave(mtx);
525 
526 	return (0);
527 }
528 
529 void
530 filt_pppx_rdetach(struct knote *kn)
531 {
532 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
533 	struct klist *klist = &pxd->pxd_rsel.si_note;
534 
535 	if (ISSET(kn->kn_status, KN_DETACHED))
536 		return;
537 
538 	mtx_enter(&pxd->pxd_rsel_mtx);
539 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
540 	mtx_leave(&pxd->pxd_rsel_mtx);
541 }
542 
543 int
544 filt_pppx_read(struct knote *kn, long hint)
545 {
546 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
547 	int s, event = 0;
548 
549 	if (ISSET(kn->kn_status, KN_DETACHED)) {
550 		kn->kn_data = 0;
551 		return (1);
552 	}
553 
554 	s = splnet();
555 	if (!IF_IS_EMPTY(&pxd->pxd_svcq)) {
556 		event = 1;
557 		kn->kn_data = IF_LEN(&pxd->pxd_svcq);
558 	}
559 	splx(s);
560 
561 	return (event);
562 }
563 
564 void
565 filt_pppx_wdetach(struct knote *kn)
566 {
567 	struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
568 	struct klist *klist = &pxd->pxd_wsel.si_note;
569 
570 	if (ISSET(kn->kn_status, KN_DETACHED))
571 		return;
572 
573 	mtx_enter(&pxd->pxd_wsel_mtx);
574 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
575 	mtx_leave(&pxd->pxd_wsel_mtx);
576 }
577 
578 int
579 filt_pppx_write(struct knote *kn, long hint)
580 {
581 	/* We're always ready to accept a write. */
582 	return (1);
583 }
584 
585 int
586 pppxclose(dev_t dev, int flags, int mode, struct proc *p)
587 {
588 	struct pppx_dev *pxd;
589 	struct pppx_if	*pxi;
590 	int s;
591 
592 	rw_enter_write(&pppx_devs_lk);
593 
594 	pxd = pppx_dev_lookup(dev);
595 
596 	/* XXX */
597 	while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
598 		pppx_if_destroy(pxd, pxi);
599 
600 	LIST_REMOVE(pxd, pxd_entry);
601 
602 	s = splnet();
603 	IF_PURGE(&pxd->pxd_svcq);
604 	splx(s);
605 
606 	free(pxd, M_DEVBUF, 0);
607 
608 	if (LIST_EMPTY(&pppx_devs)) {
609 		pool_destroy(pppx_if_pl);
610 		free(pppx_if_pl, M_DEVBUF, 0);
611 		pppx_if_pl = NULL;
612 	}
613 
614 	rw_exit_write(&pppx_devs_lk);
615 	return (0);
616 }
617 
618 int
619 pppx_if_cmp(struct pppx_if *a, struct pppx_if *b)
620 {
621 	return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key));
622 }
623 
624 int
625 pppx_if_next_unit(void)
626 {
627 	struct pppx_if *pxi;
628 	int unit = 0;
629 
630 	rw_assert_wrlock(&pppx_ifs_lk);
631 
632 	/* this is safe without splnet since we're not modifying it */
633 	do {
634 		int found = 0;
635 		RB_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
636 			if (pxi->pxi_unit == unit) {
637 				found = 1;
638 				break;
639 			}
640 		}
641 
642 		if (found == 0)
643 			break;
644 		unit++;
645 	} while (unit > 0);
646 
647 	return (unit);
648 }
649 
650 struct pppx_if *
651 pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
652 {
653 	struct pppx_if *s, *p;
654 	s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
655 
656 	s->pxi_key.pxik_session_id = session_id;
657 	s->pxi_key.pxik_protocol = protocol;
658 
659 	rw_enter_read(&pppx_ifs_lk);
660 	p = RB_FIND(pppx_ifs, &pppx_ifs, s);
661 	rw_exit_read(&pppx_ifs_lk);
662 
663 	free(s, M_DEVBUF, 0);
664 	return (p);
665 }
666 
667 int
668 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
669 {
670 	struct pppx_if *pxi;
671 	struct pipex_session *session;
672 	struct pipex_hash_head *chain;
673 	struct ifnet *ifp;
674 	int unit, s, error = 0;
675 	struct in_ifaddr *ia;
676 	struct sockaddr_in ifaddr;
677 #ifdef PIPEX_PPPOE
678 	struct ifnet *over_ifp = NULL;
679 #endif
680 
681 	switch (req->pr_protocol) {
682 #ifdef PIPEX_PPPOE
683 	case PIPEX_PROTO_PPPOE:
684 		over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
685 		if (over_ifp == NULL)
686 			return (EINVAL);
687 		if (req->pr_peer_address.ss_family != AF_UNSPEC)
688 			return (EINVAL);
689 		break;
690 #endif
691 #ifdef PIPEX_PPTP
692 	case PIPEX_PROTO_PPTP:
693 #endif
694 #ifdef PIPEX_L2TP
695 	case PIPEX_PROTO_L2TP:
696 #endif
697 		switch (req->pr_peer_address.ss_family) {
698 		case AF_INET:
699 			if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in))
700 				return (EINVAL);
701 			break;
702 #ifdef INET6
703 		case AF_INET6:
704 			if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in6))
705 				return (EINVAL);
706 			break;
707 #endif
708 		default:
709 			return (EPROTONOSUPPORT);
710 		}
711 		if (req->pr_peer_address.ss_family !=
712 		    req->pr_local_address.ss_family ||
713 		    req->pr_peer_address.ss_len !=
714 		    req->pr_local_address.ss_len)
715 			return (EINVAL);
716 		break;
717 	default:
718 		return (EPROTONOSUPPORT);
719 	}
720 
721 	pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
722 	if (pxi == NULL)
723 		return (ENOMEM);
724 
725 	session = &pxi->pxi_session;
726 	ifp = &pxi->pxi_if;
727 
728 	/* fake a pipex interface context */
729 	session->pipex_iface = &pxi->pxi_ifcontext;
730 	session->pipex_iface->ifnet_this = ifp;
731 	session->pipex_iface->pipexmode = PIPEX_ENABLED;
732 
733 	/* setup session */
734 	session->state = PIPEX_STATE_OPENED;
735 	session->protocol = req->pr_protocol;
736 	session->session_id = req->pr_session_id;
737 	session->peer_session_id = req->pr_peer_session_id;
738 	session->peer_mru = req->pr_peer_mru;
739 	session->timeout_sec = req->pr_timeout_sec;
740 	session->ppp_flags = req->pr_ppp_flags;
741 	session->ppp_id = req->pr_ppp_id;
742 
743 	session->ip_forward = 1;
744 
745 	session->ip_address.sin_family = AF_INET;
746 	session->ip_address.sin_len = sizeof(struct sockaddr_in);
747 	session->ip_address.sin_addr = req->pr_ip_address;
748 
749 	session->ip_netmask.sin_family = AF_INET;
750 	session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
751 	session->ip_netmask.sin_addr = req->pr_ip_netmask;
752 
753 	if (session->ip_netmask.sin_addr.s_addr == 0L)
754 		session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
755 	session->ip_address.sin_addr.s_addr &=
756 	    session->ip_netmask.sin_addr.s_addr;
757 
758 	if (req->pr_peer_address.ss_len > 0)
759 		memcpy(&session->peer, &req->pr_peer_address,
760 		    MIN(req->pr_peer_address.ss_len, sizeof(session->peer)));
761 	if (req->pr_local_address.ss_len > 0)
762 		memcpy(&session->local, &req->pr_local_address,
763 		    MIN(req->pr_local_address.ss_len, sizeof(session->local)));
764 #ifdef PIPEX_PPPOE
765 	if (req->pr_protocol == PIPEX_PROTO_PPPOE)
766 		session->proto.pppoe.over_ifp = over_ifp;
767 #endif
768 #ifdef PIPEX_PPTP
769 	if (req->pr_protocol == PIPEX_PROTO_PPTP) {
770 		struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
771 
772 		sess_pptp->snd_gap = 0;
773 		sess_pptp->rcv_gap = 0;
774 		sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
775 		sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
776 		sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
777 		sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
778 
779 		sess_pptp->winsz = req->pr_proto.pptp.winsz;
780 		sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
781 		sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
782 		/* last ack number */
783 		sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
784 	}
785 #endif
786 #ifdef PIPEX_L2TP
787 	if (req->pr_protocol == PIPEX_PROTO_L2TP) {
788 		struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
789 
790 		/* session keys */
791 		sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
792 		sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
793 
794 		/* protocol options */
795 		sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
796 
797 		/* initial state of dynamic context */
798 		sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
799 		sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
800 		sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
801 		sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
802 		sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
803 		/* last ack number */
804 		sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
805 	}
806 #endif
807 #ifdef PIPEX_MPPE
808 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
809 		pipex_session_init_mppe_recv(session,
810 		    req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
811 		    req->pr_mppe_recv.master_key);
812 	if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
813 		pipex_session_init_mppe_send(session,
814 		    req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
815 		    req->pr_mppe_send.master_key);
816 
817 	if (pipex_session_is_mppe_required(session)) {
818 		if (!pipex_session_is_mppe_enabled(session) ||
819 		    !pipex_session_is_mppe_accepted(session)) {
820 			pool_put(pppx_if_pl, pxi);
821 			return (EINVAL);
822 		}
823 	}
824 #endif
825 
826 	/* try to set the interface up */
827 	rw_enter_write(&pppx_ifs_lk);
828 	unit = pppx_if_next_unit();
829 	if (unit < 0) {
830 		pool_put(pppx_if_pl, pxi);
831 		error = ENOMEM;
832 		goto out;
833 	}
834 
835 	pxi->pxi_unit = unit;
836 	pxi->pxi_key.pxik_session_id = req->pr_session_id;
837 	pxi->pxi_key.pxik_protocol = req->pr_protocol;
838 
839 	/* this is safe without splnet since we're not modifying it */
840 	if (RB_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
841 		pool_put(pppx_if_pl, pxi);
842 		error = EADDRINUSE;
843 		goto out;
844 	}
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_type = IFT_PPP;
853 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
854 	IFQ_SET_READY(&ifp->if_snd);
855 	ifp->if_softc = pxi;
856 	/* ifp->if_rdomain = req->pr_rdomain; */
857 
858 	s = splnet();
859 
860 	/* hook up pipex context */
861 	chain = PIPEX_ID_HASHTABLE(session->session_id);
862 	LIST_INSERT_HEAD(chain, session, id_chain);
863 	LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
864 	switch (req->pr_protocol) {
865 	case PIPEX_PROTO_PPTP:
866 	case PIPEX_PROTO_L2TP:
867 		chain = PIPEX_PEER_ADDR_HASHTABLE(
868 		    pipex_sockaddr_hash_key((struct sockaddr *)&session->peer));
869 		LIST_INSERT_HEAD(chain, session, peer_addr_chain);
870 		break;
871 	}
872 
873 	/* if first session is added, start timer */
874 	if (LIST_NEXT(session, session_list) == NULL)
875 		pipex_timer_start();
876 
877 	if_attach(ifp);
878 	if_addgroup(ifp, "pppx");
879 	if_alloc_sadl(ifp);
880 
881 #if NBPFILTER > 0
882 	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
883 #endif
884 	SET(ifp->if_flags, IFF_RUNNING);
885 
886 	if (RB_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
887 		panic("pppx_ifs modified while lock was held");
888 	LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
889 
890 	/* XXX ipv6 support?  how does the caller indicate it wants ipv6
891 	 * instead of ipv4?
892 	 */
893 	memset(&ifaddr, 0, sizeof(ifaddr));
894 	ifaddr.sin_family = AF_INET;
895 	ifaddr.sin_len = sizeof(ifaddr);
896 	ifaddr.sin_addr = req->pr_ip_srcaddr;
897 
898 	ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
899 
900 	ia->ia_addr.sin_family = AF_INET;
901 	ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
902 	ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
903 
904 	ia->ia_dstaddr.sin_family = AF_INET;
905 	ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
906 	ia->ia_dstaddr.sin_addr = req->pr_ip_address;
907 
908 	ia->ia_sockmask.sin_family = AF_INET;
909 	ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
910 	ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
911 
912 	ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
913 	ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
914 	ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
915 	ia->ia_ifa.ifa_ifp = ifp;
916 
917 	ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
918 
919 	error = in_ifinit(ifp, ia, &ifaddr, 1);
920 	if (error) {
921 		printf("pppx: unable to set addresses for %s, error=%d\n",
922 		    ifp->if_xname, error);
923 	} else {
924 		dohooks(ifp->if_addrhooks, 0);
925 	}
926 	splx(s);
927 
928 out:
929 	rw_exit_write(&pppx_ifs_lk);
930 
931 	return (error);
932 }
933 
934 int
935 pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
936 {
937 	struct pppx_if *pxi;
938 
939 	pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
940 	if (pxi == NULL)
941 		return (EINVAL);
942 
943 	req->pcr_stat = pxi->pxi_session.stat;
944 
945 	pppx_if_destroy(pxd, pxi);
946 	return (0);
947 }
948 
949 int
950 pppx_set_session_descr(struct pppx_dev *pxd,
951     struct pipex_session_descr_req *req)
952 {
953 	struct pppx_if *pxi;
954 
955 	pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
956 	if (pxi == NULL)
957 		return (EINVAL);
958 
959 	(void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
960 	strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
961 
962 	return (0);
963 }
964 
965 void
966 pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
967 {
968 	struct ifnet *ifp;
969 	struct pipex_session *session;
970 	int s;
971 
972 	session = &pxi->pxi_session;
973 	ifp = &pxi->pxi_if;
974 
975 	s = splnet();
976 	LIST_REMOVE(session, id_chain);
977 	LIST_REMOVE(session, session_list);
978 	switch (session->protocol) {
979 	case PIPEX_PROTO_PPTP:
980 	case PIPEX_PROTO_L2TP:
981 		LIST_REMOVE((struct pipex_session *)session,
982 		    peer_addr_chain);
983 		break;
984 	}
985 
986 	/* if final session is destroyed, stop timer */
987 	if (LIST_EMPTY(&pipex_session_list))
988 		pipex_timer_stop();
989 	splx(s);
990 
991 	if_detach(ifp);
992 
993 	rw_enter_write(&pppx_ifs_lk);
994 	if (RB_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
995 		panic("pppx_ifs modified while lock was held");
996 	LIST_REMOVE(pxi, pxi_list);
997 	rw_exit_write(&pppx_ifs_lk);
998 
999 	pool_put(pppx_if_pl, pxi);
1000 }
1001 
1002 void
1003 pppx_if_start(struct ifnet *ifp)
1004 {
1005 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1006 	struct mbuf *m;
1007 	int proto, s;
1008 
1009 	if (ISSET(ifp->if_flags, IFF_OACTIVE))
1010 		return;
1011 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
1012 		return;
1013 
1014 	for (;;) {
1015 		s = splnet();
1016 		IFQ_DEQUEUE(&ifp->if_snd, m);
1017 		splx(s);
1018 
1019 		if (m == NULL)
1020 			break;
1021 
1022 		proto = *mtod(m, int *);
1023 		m_adj(m, sizeof(proto));
1024 
1025 #if NBPFILTER > 0
1026 		if (ifp->if_bpf) {
1027 			switch (proto) {
1028 			case PPP_IP:
1029 				bpf_mtap_af(ifp->if_bpf, AF_INET, m,
1030 					BPF_DIRECTION_OUT);
1031 				break;
1032 			case PPP_IPV6:
1033 				bpf_mtap_af(ifp->if_bpf, AF_INET6, m,
1034 					BPF_DIRECTION_OUT);
1035 				break;
1036 			}
1037 		}
1038 #endif
1039 
1040 		ifp->if_obytes += m->m_pkthdr.len;
1041 		ifp->if_opackets++;
1042 
1043 		pipex_ppp_output(m, &pxi->pxi_session, proto);
1044 	}
1045 }
1046 
1047 int
1048 pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
1049     struct rtentry *rt)
1050 {
1051 	int error = 0;
1052 	int proto, s;
1053 
1054 	if (!ISSET(ifp->if_flags, IFF_UP)) {
1055 		m_freem(m);
1056 		error = ENETDOWN;
1057 		goto out;
1058 	}
1059 
1060 	switch (dst->sa_family) {
1061 	case AF_INET:
1062 		proto = PPP_IP;
1063 		break;
1064 	default:
1065 		m_freem(m);
1066 		error = EPFNOSUPPORT;
1067 		goto out;
1068 	}
1069 
1070 	M_PREPEND(m, sizeof(int), M_DONTWAIT);
1071 	if (m == NULL) {
1072 		error = ENOBUFS;
1073 		goto out;
1074 	}
1075 	*mtod(m, int *) = proto;
1076 
1077 	s = splnet();
1078 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
1079 	if (error) {
1080 		splx(s);
1081 		goto out;
1082 	}
1083 	if_start(ifp);
1084 	splx(s);
1085 
1086 out:
1087 	if (error)
1088 		ifp->if_oerrors++;
1089 	return (error);
1090 }
1091 
1092 int
1093 pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
1094 {
1095 	struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
1096 	struct ifreq *ifr = (struct ifreq *)addr;
1097 	struct ifaddr *ifa = (struct ifaddr *)addr;
1098 	int error = 0;
1099 
1100 	switch (cmd) {
1101 	case SIOCSIFADDR:
1102 		ifa->ifa_rtrequest = p2p_rtrequest;
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 RB_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
1129