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