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