1 /* $OpenBSD: if_pppx.c,v 1.133 2024/12/30 02:46:00 guenther 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/pool.h> 54 #include <sys/mbuf.h> 55 #include <sys/errno.h> 56 #include <sys/socket.h> 57 #include <sys/ioctl.h> 58 #include <sys/vnode.h> 59 #include <sys/event.h> 60 #include <sys/mutex.h> 61 #include <sys/refcnt.h> 62 63 #include <net/if.h> 64 #include <net/if_types.h> 65 #include <netinet/in.h> 66 #include <netinet/if_ether.h> 67 #include <net/if_dl.h> 68 69 #include <netinet/in_var.h> 70 #include <netinet/ip.h> 71 #include <netinet/ip_var.h> 72 73 #ifdef INET6 74 #include <netinet6/in6_var.h> 75 #include <netinet/ip6.h> 76 #include <netinet6/nd6.h> 77 #endif /* INET6 */ 78 79 #include "bpfilter.h" 80 #if NBPFILTER > 0 81 #include <net/bpf.h> 82 #endif 83 84 #include "pf.h" 85 #if NPF > 0 86 #include <net/pfvar.h> 87 #endif 88 89 #include <net/ppp_defs.h> 90 #include <net/ppp-comp.h> 91 #include <crypto/arc4.h> 92 93 #ifdef PIPEX 94 #include <net/radix.h> 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 /* 118 * Locks used to protect struct members and global data 119 * I immutable after creation 120 * K kernel lock 121 * N net lock 122 * m pxd_mtx 123 */ 124 125 struct pppx_dev { 126 LIST_ENTRY(pppx_dev) pxd_entry; /* [K] */ 127 int pxd_unit; /* [I] */ 128 129 /* kq shizz */ 130 struct mutex pxd_mtx; 131 struct klist pxd_rklist; /* [m] */ 132 struct klist pxd_wklist; /* [m] */ 133 134 /* queue of packets for userland to service - protected by splnet */ 135 struct mbuf_queue pxd_svcq; 136 int pxd_waiting; /* [N] */ 137 LIST_HEAD(,pppx_if) pxd_pxis; /* [K] */ 138 }; 139 140 LIST_HEAD(, pppx_dev) pppx_devs = 141 LIST_HEAD_INITIALIZER(pppx_devs); /* [K] */ 142 struct pool pppx_if_pl; 143 144 struct pppx_dev *pppx_dev_lookup(dev_t); 145 struct pppx_dev *pppx_dev2pxd(dev_t); 146 147 struct pppx_if_key { 148 int pxik_session_id; /* [I] */ 149 int pxik_protocol; /* [I] */ 150 }; 151 152 struct pppx_if { 153 struct pppx_if_key pxi_key; /* [I] must be first 154 in the struct */ 155 struct refcnt pxi_refcnt; 156 157 RBT_ENTRY(pppx_if) pxi_entry; /* [K] */ 158 LIST_ENTRY(pppx_if) pxi_list; /* [K] */ 159 160 int pxi_ready; /* [K] */ 161 162 int pxi_unit; /* [I] */ 163 struct ifnet pxi_if; 164 struct pppx_dev *pxi_dev; /* [I] */ 165 struct pipex_session *pxi_session; /* [I] */ 166 }; 167 168 static inline int 169 pppx_if_cmp(const struct pppx_if *a, const struct pppx_if *b) 170 { 171 return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key)); 172 } 173 174 RBT_HEAD(pppx_ifs, pppx_if) pppx_ifs = RBT_INITIALIZER(&pppx_ifs); /* [N] */ 175 RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp); 176 177 int pppx_if_next_unit(void); 178 struct pppx_if *pppx_if_find_locked(struct pppx_dev *, int, int); 179 static inline struct pppx_if *pppx_if_find(struct pppx_dev *, int, int); 180 static inline void pppx_if_rele(struct pppx_if *); 181 int pppx_add_session(struct pppx_dev *, 182 struct pipex_session_req *); 183 int pppx_del_session(struct pppx_dev *, 184 struct pipex_session_close_req *); 185 int pppx_set_session_descr(struct pppx_dev *, 186 struct pipex_session_descr_req *); 187 188 void pppx_if_destroy(struct pppx_dev *, struct pppx_if *); 189 void pppx_if_qstart(struct ifqueue *); 190 int pppx_if_output(struct ifnet *, struct mbuf *, 191 struct sockaddr *, struct rtentry *); 192 int pppx_if_ioctl(struct ifnet *, u_long, caddr_t); 193 194 195 void pppxattach(int); 196 197 void filt_pppx_rdetach(struct knote *); 198 int filt_pppx_read(struct knote *, long); 199 int filt_pppx_modify(struct kevent *, struct knote *); 200 int filt_pppx_process(struct knote *, struct kevent *); 201 202 const struct filterops pppx_rd_filtops = { 203 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 204 .f_attach = NULL, 205 .f_detach = filt_pppx_rdetach, 206 .f_event = filt_pppx_read, 207 .f_modify = filt_pppx_modify, 208 .f_process = filt_pppx_process, 209 }; 210 211 void filt_pppx_wdetach(struct knote *); 212 int filt_pppx_write(struct knote *, long); 213 214 const struct filterops pppx_wr_filtops = { 215 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 216 .f_attach = NULL, 217 .f_detach = filt_pppx_wdetach, 218 .f_event = filt_pppx_write, 219 .f_modify = filt_pppx_modify, 220 .f_process = filt_pppx_process, 221 }; 222 223 struct pppx_dev * 224 pppx_dev_lookup(dev_t dev) 225 { 226 struct pppx_dev *pxd; 227 int unit = minor(dev); 228 229 LIST_FOREACH(pxd, &pppx_devs, pxd_entry) { 230 if (pxd->pxd_unit == unit) 231 return (pxd); 232 } 233 234 return (NULL); 235 } 236 237 struct pppx_dev * 238 pppx_dev2pxd(dev_t dev) 239 { 240 struct pppx_dev *pxd; 241 242 pxd = pppx_dev_lookup(dev); 243 244 return (pxd); 245 } 246 247 void 248 pppxattach(int n) 249 { 250 pool_init(&pppx_if_pl, sizeof(struct pppx_if), 0, IPL_NONE, 251 PR_WAITOK, "pppxif", NULL); 252 pipex_init(); 253 } 254 255 int 256 pppxopen(dev_t dev, int flags, int mode, struct proc *p) 257 { 258 struct pppx_dev *pxd; 259 260 pxd = malloc(sizeof(*pxd), M_DEVBUF, M_WAITOK | M_ZERO); 261 if (pppx_dev_lookup(dev) != NULL) { 262 free(pxd, M_DEVBUF, sizeof(*pxd)); 263 return (EBUSY); 264 } 265 266 pxd->pxd_unit = minor(dev); 267 mtx_init(&pxd->pxd_mtx, IPL_NET); 268 klist_init_mutex(&pxd->pxd_rklist, &pxd->pxd_mtx); 269 klist_init_mutex(&pxd->pxd_wklist, &pxd->pxd_mtx); 270 LIST_INIT(&pxd->pxd_pxis); 271 272 mq_init(&pxd->pxd_svcq, 128, IPL_NET); 273 LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry); 274 275 return 0; 276 } 277 278 int 279 pppxread(dev_t dev, struct uio *uio, int ioflag) 280 { 281 struct pppx_dev *pxd = pppx_dev2pxd(dev); 282 struct mbuf *m, *m0; 283 int error = 0; 284 size_t len; 285 286 if (!pxd) 287 return (ENXIO); 288 289 while ((m0 = mq_dequeue(&pxd->pxd_svcq)) == NULL) { 290 if (ISSET(ioflag, IO_NDELAY)) 291 return (EWOULDBLOCK); 292 293 NET_LOCK(); 294 pxd->pxd_waiting = 1; 295 error = rwsleep_nsec(pxd, &netlock, 296 (PZERO + 1)|PCATCH, "pppxread", INFSLP); 297 NET_UNLOCK(); 298 if (error != 0) { 299 return (error); 300 } 301 } 302 303 while (m0 != NULL && uio->uio_resid > 0 && error == 0) { 304 len = ulmin(uio->uio_resid, m0->m_len); 305 if (len != 0) 306 error = uiomove(mtod(m0, caddr_t), len, uio); 307 m = m_free(m0); 308 m0 = m; 309 } 310 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 pppx_if *pxi; 322 uint32_t proto; 323 struct mbuf *top, **mp, *m; 324 int tlen; 325 int error = 0; 326 size_t mlen; 327 328 if (uio->uio_resid < sizeof(*th) + sizeof(uint32_t) || 329 uio->uio_resid > MCLBYTES) 330 return (EMSGSIZE); 331 332 tlen = uio->uio_resid; 333 334 MGETHDR(m, M_DONTWAIT, MT_DATA); 335 if (m == NULL) 336 return (ENOBUFS); 337 mlen = MHLEN; 338 if (uio->uio_resid > MHLEN) { 339 MCLGET(m, M_DONTWAIT); 340 if (!(m->m_flags & M_EXT)) { 341 m_free(m); 342 return (ENOBUFS); 343 } 344 mlen = MCLBYTES; 345 } 346 347 top = NULL; 348 mp = ⊤ 349 350 while (error == 0 && uio->uio_resid > 0) { 351 m->m_len = ulmin(mlen, uio->uio_resid); 352 error = uiomove(mtod (m, caddr_t), m->m_len, uio); 353 *mp = m; 354 mp = &m->m_next; 355 if (error == 0 && uio->uio_resid > 0) { 356 MGET(m, M_DONTWAIT, MT_DATA); 357 if (m == NULL) { 358 error = ENOBUFS; 359 break; 360 } 361 mlen = MLEN; 362 if (uio->uio_resid >= MINCLSIZE) { 363 MCLGET(m, M_DONTWAIT); 364 if (!(m->m_flags & M_EXT)) { 365 error = ENOBUFS; 366 m_free(m); 367 break; 368 } 369 mlen = MCLBYTES; 370 } 371 } 372 } 373 374 if (error) { 375 m_freem(top); 376 return (error); 377 } 378 379 top->m_pkthdr.len = tlen; 380 381 /* Find the interface */ 382 th = mtod(top, struct pppx_hdr *); 383 m_adj(top, sizeof(struct pppx_hdr)); 384 385 pxi = pppx_if_find(pxd, th->pppx_id, th->pppx_proto); 386 if (pxi == NULL) { 387 m_freem(top); 388 return (EINVAL); 389 } 390 top->m_pkthdr.ph_ifidx = pxi->pxi_if.if_index; 391 392 #if NBPFILTER > 0 393 if (pxi->pxi_if.if_bpf) 394 bpf_mtap(pxi->pxi_if.if_bpf, top, BPF_DIRECTION_IN); 395 #endif 396 /* strip the tunnel header */ 397 proto = ntohl(*(uint32_t *)(th + 1)); 398 m_adj(top, sizeof(uint32_t)); 399 400 NET_LOCK(); 401 402 switch (proto) { 403 case AF_INET: 404 ipv4_input(&pxi->pxi_if, top); 405 break; 406 #ifdef INET6 407 case AF_INET6: 408 ipv6_input(&pxi->pxi_if, top); 409 break; 410 #endif 411 default: 412 m_freem(top); 413 error = EAFNOSUPPORT; 414 break; 415 } 416 417 NET_UNLOCK(); 418 419 pppx_if_rele(pxi); 420 421 return (error); 422 } 423 424 int 425 pppxioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 426 { 427 struct pppx_dev *pxd = pppx_dev2pxd(dev); 428 int error = 0; 429 430 switch (cmd) { 431 case PIPEXASESSION: 432 error = pppx_add_session(pxd, 433 (struct pipex_session_req *)addr); 434 break; 435 436 case PIPEXDSESSION: 437 error = pppx_del_session(pxd, 438 (struct pipex_session_close_req *)addr); 439 break; 440 441 case PIPEXSIFDESCR: 442 error = pppx_set_session_descr(pxd, 443 (struct pipex_session_descr_req *)addr); 444 break; 445 446 case FIONREAD: 447 *(int *)addr = mq_hdatalen(&pxd->pxd_svcq); 448 break; 449 450 default: 451 error = pipex_ioctl(pxd, cmd, addr); 452 break; 453 } 454 455 return (error); 456 } 457 458 int 459 pppxkqfilter(dev_t dev, struct knote *kn) 460 { 461 struct pppx_dev *pxd = pppx_dev2pxd(dev); 462 struct klist *klist; 463 464 switch (kn->kn_filter) { 465 case EVFILT_READ: 466 klist = &pxd->pxd_rklist; 467 kn->kn_fop = &pppx_rd_filtops; 468 break; 469 case EVFILT_WRITE: 470 klist = &pxd->pxd_wklist; 471 kn->kn_fop = &pppx_wr_filtops; 472 break; 473 default: 474 return (EINVAL); 475 } 476 477 kn->kn_hook = pxd; 478 479 klist_insert(klist, kn); 480 481 return (0); 482 } 483 484 void 485 filt_pppx_rdetach(struct knote *kn) 486 { 487 struct pppx_dev *pxd = kn->kn_hook; 488 489 klist_remove(&pxd->pxd_rklist, kn); 490 } 491 492 int 493 filt_pppx_read(struct knote *kn, long hint) 494 { 495 struct pppx_dev *pxd = kn->kn_hook; 496 497 MUTEX_ASSERT_LOCKED(&pxd->pxd_mtx); 498 499 kn->kn_data = mq_hdatalen(&pxd->pxd_svcq); 500 501 return (kn->kn_data > 0); 502 } 503 504 void 505 filt_pppx_wdetach(struct knote *kn) 506 { 507 struct pppx_dev *pxd = kn->kn_hook; 508 509 klist_remove(&pxd->pxd_wklist, kn); 510 } 511 512 int 513 filt_pppx_write(struct knote *kn, long hint) 514 { 515 /* We're always ready to accept a write. */ 516 return (1); 517 } 518 519 int 520 filt_pppx_modify(struct kevent *kev, struct knote *kn) 521 { 522 struct pppx_dev *pxd = kn->kn_hook; 523 int active; 524 525 mtx_enter(&pxd->pxd_mtx); 526 active = knote_modify(kev, kn); 527 mtx_leave(&pxd->pxd_mtx); 528 529 return (active); 530 } 531 532 int 533 filt_pppx_process(struct knote *kn, struct kevent *kev) 534 { 535 struct pppx_dev *pxd = kn->kn_hook; 536 int active; 537 538 mtx_enter(&pxd->pxd_mtx); 539 active = knote_process(kn, kev); 540 mtx_leave(&pxd->pxd_mtx); 541 542 return (active); 543 } 544 545 int 546 pppxclose(dev_t dev, int flags, int mode, struct proc *p) 547 { 548 struct pppx_dev *pxd; 549 struct pppx_if *pxi; 550 551 pxd = pppx_dev_lookup(dev); 552 553 while ((pxi = LIST_FIRST(&pxd->pxd_pxis))) { 554 pxi->pxi_ready = 0; 555 pppx_if_destroy(pxd, pxi); 556 } 557 558 LIST_REMOVE(pxd, pxd_entry); 559 560 mq_purge(&pxd->pxd_svcq); 561 562 klist_free(&pxd->pxd_rklist); 563 klist_free(&pxd->pxd_wklist); 564 565 free(pxd, M_DEVBUF, sizeof(*pxd)); 566 567 return (0); 568 } 569 570 int 571 pppx_if_next_unit(void) 572 { 573 struct pppx_if *pxi; 574 int unit = 0; 575 576 /* this is safe without splnet since we're not modifying it */ 577 do { 578 int found = 0; 579 RBT_FOREACH(pxi, pppx_ifs, &pppx_ifs) { 580 if (pxi->pxi_unit == unit) { 581 found = 1; 582 break; 583 } 584 } 585 586 if (found == 0) 587 break; 588 unit++; 589 } while (unit > 0); 590 591 return (unit); 592 } 593 594 struct pppx_if * 595 pppx_if_find_locked(struct pppx_dev *pxd, int session_id, int protocol) 596 { 597 struct pppx_if_key key; 598 struct pppx_if *pxi; 599 600 memset(&key, 0, sizeof(key)); 601 key.pxik_session_id = session_id; 602 key.pxik_protocol = protocol; 603 604 pxi = RBT_FIND(pppx_ifs, &pppx_ifs, (struct pppx_if *)&key); 605 if (pxi && pxi->pxi_ready == 0) 606 pxi = NULL; 607 608 return pxi; 609 } 610 611 static inline struct pppx_if * 612 pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol) 613 { 614 struct pppx_if *pxi; 615 616 if ((pxi = pppx_if_find_locked(pxd, session_id, protocol))) 617 refcnt_take(&pxi->pxi_refcnt); 618 619 return pxi; 620 } 621 622 static inline void 623 pppx_if_rele(struct pppx_if *pxi) 624 { 625 refcnt_rele_wake(&pxi->pxi_refcnt); 626 } 627 628 int 629 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req) 630 { 631 struct pppx_if *pxi; 632 struct pipex_session *session; 633 struct ifnet *ifp; 634 int unit, error = 0; 635 struct in_ifaddr *ia; 636 struct sockaddr_in ifaddr; 637 638 /* 639 * XXX: As long as `session' is allocated as part of a `pxi' 640 * it isn't possible to free it separately. So disallow 641 * the timeout feature until this is fixed. 642 */ 643 if (req->pr_timeout_sec != 0) 644 return (EINVAL); 645 646 error = pipex_init_session(&session, req); 647 if (error) 648 return (error); 649 650 pxi = pool_get(&pppx_if_pl, PR_WAITOK | PR_ZERO); 651 ifp = &pxi->pxi_if; 652 653 pxi->pxi_session = session; 654 655 /* try to set the interface up */ 656 unit = pppx_if_next_unit(); 657 if (unit < 0) { 658 error = ENOMEM; 659 goto out; 660 } 661 662 refcnt_init(&pxi->pxi_refcnt); 663 pxi->pxi_unit = unit; 664 pxi->pxi_key.pxik_session_id = req->pr_session_id; 665 pxi->pxi_key.pxik_protocol = req->pr_protocol; 666 pxi->pxi_dev = pxd; 667 668 if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL) { 669 error = EADDRINUSE; 670 goto out; 671 } 672 LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list); 673 674 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit); 675 ifp->if_mtu = req->pr_peer_mru; /* XXX */ 676 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP; 677 ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE; 678 ifp->if_qstart = pppx_if_qstart; 679 ifp->if_output = pppx_if_output; 680 ifp->if_ioctl = pppx_if_ioctl; 681 ifp->if_rtrequest = p2p_rtrequest; 682 ifp->if_type = IFT_PPP; 683 ifp->if_softc = pxi; 684 /* ifp->if_rdomain = req->pr_rdomain; */ 685 if_counters_alloc(ifp); 686 687 if_attach(ifp); 688 689 NET_LOCK(); 690 if_addgroup(ifp, "pppx"); 691 if_alloc_sadl(ifp); 692 NET_UNLOCK(); 693 694 #if NBPFILTER > 0 695 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t)); 696 #endif 697 698 /* XXX ipv6 support? how does the caller indicate it wants ipv6 699 * instead of ipv4? 700 */ 701 memset(&ifaddr, 0, sizeof(ifaddr)); 702 ifaddr.sin_family = AF_INET; 703 ifaddr.sin_len = sizeof(ifaddr); 704 ifaddr.sin_addr = req->pr_ip_srcaddr; 705 706 ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO); 707 refcnt_init_trace(&ia->ia_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR); 708 709 ia->ia_addr.sin_family = AF_INET; 710 ia->ia_addr.sin_len = sizeof(struct sockaddr_in); 711 ia->ia_addr.sin_addr = req->pr_ip_srcaddr; 712 713 ia->ia_dstaddr.sin_family = AF_INET; 714 ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in); 715 ia->ia_dstaddr.sin_addr = req->pr_ip_address; 716 717 ia->ia_sockmask.sin_family = AF_INET; 718 ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in); 719 ia->ia_sockmask.sin_addr = req->pr_ip_netmask; 720 721 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr); 722 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr); 723 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask); 724 ia->ia_ifa.ifa_ifp = ifp; 725 726 ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr; 727 728 NET_LOCK(); 729 error = in_ifinit(ifp, ia, &ifaddr, 1); 730 if (error) { 731 printf("pppx: unable to set addresses for %s, error=%d\n", 732 ifp->if_xname, error); 733 } else { 734 if_addrhooks_run(ifp); 735 } 736 NET_UNLOCK(); 737 738 error = pipex_link_session(session, ifp, pxd); 739 if (error) 740 goto detach; 741 742 NET_LOCK(); 743 SET(ifp->if_flags, IFF_RUNNING); 744 NET_UNLOCK(); 745 pxi->pxi_ready = 1; 746 747 return (error); 748 749 detach: 750 if_detach(ifp); 751 752 if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL) 753 panic("%s: inconsistent RB tree", __func__); 754 LIST_REMOVE(pxi, pxi_list); 755 out: 756 pool_put(&pppx_if_pl, pxi); 757 pipex_rele_session(session); 758 759 return (error); 760 } 761 762 int 763 pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req) 764 { 765 struct pppx_if *pxi; 766 767 pxi = pppx_if_find_locked(pxd, req->pcr_session_id, req->pcr_protocol); 768 if (pxi == NULL) 769 return (EINVAL); 770 771 pxi->pxi_ready = 0; 772 pipex_export_session_stats(pxi->pxi_session, &req->pcr_stat); 773 pppx_if_destroy(pxd, pxi); 774 return (0); 775 } 776 777 int 778 pppx_set_session_descr(struct pppx_dev *pxd, 779 struct pipex_session_descr_req *req) 780 { 781 struct pppx_if *pxi; 782 783 pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol); 784 if (pxi == NULL) 785 return (EINVAL); 786 787 (void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE); 788 strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE); 789 790 pppx_if_rele(pxi); 791 792 return (0); 793 } 794 795 void 796 pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi) 797 { 798 struct ifnet *ifp; 799 struct pipex_session *session; 800 801 session = pxi->pxi_session; 802 ifp = &pxi->pxi_if; 803 804 refcnt_finalize(&pxi->pxi_refcnt, "pxifinal"); 805 806 NET_LOCK(); 807 CLR(ifp->if_flags, IFF_RUNNING); 808 NET_UNLOCK(); 809 810 pipex_unlink_session(session); 811 if_detach(ifp); 812 813 pipex_rele_session(session); 814 if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL) 815 panic("%s: inconsistent RB tree", __func__); 816 LIST_REMOVE(pxi, pxi_list); 817 818 pool_put(&pppx_if_pl, pxi); 819 } 820 821 void 822 pppx_if_qstart(struct ifqueue *ifq) 823 { 824 struct ifnet *ifp = ifq->ifq_if; 825 struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc; 826 struct mbuf *m; 827 int proto; 828 829 while ((m = ifq_dequeue(ifq)) != NULL) { 830 proto = *mtod(m, int *); 831 m_adj(m, sizeof(proto)); 832 833 pipex_ppp_output(m, pxi->pxi_session, proto); 834 } 835 } 836 837 int 838 pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 839 struct rtentry *rt) 840 { 841 struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc; 842 struct pppx_hdr *th; 843 int error = 0; 844 int pipex_enable_local, proto; 845 846 pipex_enable_local = atomic_load_int(&pipex_enable); 847 848 NET_ASSERT_LOCKED(); 849 850 if (!ISSET(ifp->if_flags, IFF_RUNNING)) { 851 m_freem(m); 852 error = ENETDOWN; 853 goto out; 854 } 855 856 #if NBPFILTER > 0 857 if (ifp->if_bpf) 858 bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT); 859 #endif 860 if (pipex_enable_local) { 861 switch (dst->sa_family) { 862 #ifdef INET6 863 case AF_INET6: 864 proto = PPP_IPV6; 865 break; 866 #endif 867 case AF_INET: 868 proto = PPP_IP; 869 break; 870 default: 871 m_freem(m); 872 error = EPFNOSUPPORT; 873 goto out; 874 } 875 } else 876 proto = htonl(dst->sa_family); 877 878 M_PREPEND(m, sizeof(int), M_DONTWAIT); 879 if (m == NULL) { 880 error = ENOBUFS; 881 goto out; 882 } 883 *mtod(m, int *) = proto; 884 885 if (pipex_enable_local) 886 error = if_enqueue(ifp, m); 887 else { 888 M_PREPEND(m, sizeof(struct pppx_hdr), M_DONTWAIT); 889 if (m == NULL) { 890 error = ENOBUFS; 891 goto out; 892 } 893 th = mtod(m, struct pppx_hdr *); 894 th->pppx_proto = 0; /* not used */ 895 th->pppx_id = pxi->pxi_session->ppp_id; 896 error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m); 897 if (error == 0) { 898 if (pxi->pxi_dev->pxd_waiting) { 899 wakeup((caddr_t)pxi->pxi_dev); 900 pxi->pxi_dev->pxd_waiting = 0; 901 } 902 knote(&pxi->pxi_dev->pxd_rklist, 0); 903 } 904 } 905 906 out: 907 if (error) 908 counters_inc(ifp->if_counters, ifc_oerrors); 909 return (error); 910 } 911 912 int 913 pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) 914 { 915 struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc; 916 struct ifreq *ifr = (struct ifreq *)addr; 917 int error = 0; 918 919 switch (cmd) { 920 case SIOCSIFADDR: 921 break; 922 923 case SIOCSIFFLAGS: 924 break; 925 926 case SIOCADDMULTI: 927 case SIOCDELMULTI: 928 break; 929 930 case SIOCSIFMTU: 931 if (ifr->ifr_mtu < 512 || 932 ifr->ifr_mtu > pxi->pxi_session->peer_mru) 933 error = EINVAL; 934 else 935 ifp->if_mtu = ifr->ifr_mtu; 936 break; 937 938 default: 939 error = ENOTTY; 940 break; 941 } 942 943 return (error); 944 } 945 946 RBT_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp); 947 948 /* 949 * Locks used to protect struct members and global data 950 * I immutable after creation 951 * K kernel lock 952 * N net lock 953 * m sc_mtx 954 */ 955 956 struct pppac_softc { 957 struct ifnet sc_if; 958 dev_t sc_dev; /* [I] */ 959 int sc_ready; /* [K] */ 960 LIST_ENTRY(pppac_softc) 961 sc_entry; /* [K] */ 962 963 struct mutex sc_mtx; 964 struct klist sc_rklist; /* [m] */ 965 struct klist sc_wklist; /* [m] */ 966 967 struct pipex_session 968 *sc_multicast_session; 969 970 struct mbuf_queue 971 sc_mq; 972 }; 973 974 LIST_HEAD(pppac_list, pppac_softc); /* [K] */ 975 976 static void filt_pppac_rdetach(struct knote *); 977 static int filt_pppac_read(struct knote *, long); 978 static int filt_pppac_modify(struct kevent *, struct knote *); 979 static int filt_pppac_process(struct knote *, struct kevent *); 980 981 static const struct filterops pppac_rd_filtops = { 982 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 983 .f_attach = NULL, 984 .f_detach = filt_pppac_rdetach, 985 .f_event = filt_pppac_read, 986 .f_modify = filt_pppac_modify, 987 .f_process = filt_pppac_process, 988 }; 989 990 static void filt_pppac_wdetach(struct knote *); 991 static int filt_pppac_write(struct knote *, long); 992 993 static const struct filterops pppac_wr_filtops = { 994 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 995 .f_attach = NULL, 996 .f_detach = filt_pppac_wdetach, 997 .f_event = filt_pppac_write, 998 .f_modify = filt_pppac_modify, 999 .f_process = filt_pppac_process, 1000 }; 1001 1002 static struct pppac_list pppac_devs = LIST_HEAD_INITIALIZER(pppac_devs); 1003 1004 static int pppac_ioctl(struct ifnet *, u_long, caddr_t); 1005 1006 static int pppac_add_session(struct pppac_softc *, 1007 struct pipex_session_req *); 1008 static int pppac_del_session(struct pppac_softc *, 1009 struct pipex_session_close_req *); 1010 static int pppac_output(struct ifnet *, struct mbuf *, struct sockaddr *, 1011 struct rtentry *); 1012 static void pppac_qstart(struct ifqueue *); 1013 1014 static inline struct pppac_softc * 1015 pppac_lookup(dev_t dev) 1016 { 1017 struct pppac_softc *sc; 1018 1019 LIST_FOREACH(sc, &pppac_devs, sc_entry) { 1020 if (sc->sc_dev == dev) { 1021 if (sc->sc_ready == 0) 1022 break; 1023 1024 return (sc); 1025 } 1026 } 1027 1028 return (NULL); 1029 } 1030 1031 void 1032 pppacattach(int n) 1033 { 1034 pipex_init(); /* to be sure, to be sure */ 1035 } 1036 1037 int 1038 pppacopen(dev_t dev, int flags, int mode, struct proc *p) 1039 { 1040 struct pppac_softc *sc, *tmp; 1041 struct ifnet *ifp; 1042 struct pipex_session *session; 1043 1044 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 1045 sc->sc_dev = dev; 1046 LIST_FOREACH(tmp, &pppac_devs, sc_entry) { 1047 if (tmp->sc_dev == dev) { 1048 free(sc, M_DEVBUF, sizeof(*sc)); 1049 return (EBUSY); 1050 } 1051 } 1052 LIST_INSERT_HEAD(&pppac_devs, sc, sc_entry); 1053 1054 /* virtual pipex_session entry for multicast */ 1055 session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO); 1056 session->flags |= PIPEX_SFLAGS_MULTICAST; 1057 session->ownersc = sc; 1058 sc->sc_multicast_session = session; 1059 1060 mtx_init(&sc->sc_mtx, IPL_SOFTNET); 1061 klist_init_mutex(&sc->sc_rklist, &sc->sc_mtx); 1062 klist_init_mutex(&sc->sc_wklist, &sc->sc_mtx); 1063 mq_init(&sc->sc_mq, IFQ_MAXLEN, IPL_SOFTNET); 1064 1065 ifp = &sc->sc_if; 1066 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "pppac%u", minor(dev)); 1067 1068 ifp->if_softc = sc; 1069 ifp->if_type = IFT_L3IPVLAN; 1070 ifp->if_hdrlen = sizeof(uint32_t); /* for BPF */ 1071 ifp->if_mtu = MAXMCLBYTES - sizeof(uint32_t); 1072 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; 1073 ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE; 1074 ifp->if_rtrequest = p2p_rtrequest; /* XXX */ 1075 ifp->if_output = pppac_output; 1076 ifp->if_qstart = pppac_qstart; 1077 ifp->if_ioctl = pppac_ioctl; 1078 1079 if_counters_alloc(ifp); 1080 if_attach(ifp); 1081 if_alloc_sadl(ifp); 1082 1083 #if NBPFILTER > 0 1084 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t)); 1085 #endif 1086 1087 sc->sc_ready = 1; 1088 1089 return (0); 1090 } 1091 1092 int 1093 pppacread(dev_t dev, struct uio *uio, int ioflag) 1094 { 1095 struct pppac_softc *sc = pppac_lookup(dev); 1096 struct ifnet *ifp = &sc->sc_if; 1097 struct mbuf *m0, *m; 1098 int error = 0; 1099 size_t len; 1100 1101 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 1102 return (EHOSTDOWN); 1103 1104 m0 = mq_dequeue(&sc->sc_mq); 1105 if (m0 == NULL) { 1106 if (ISSET(ioflag, IO_NDELAY)) 1107 return (EWOULDBLOCK); 1108 1109 do { 1110 error = tsleep_nsec(sc, (PZERO + 1)|PCATCH, 1111 "pppacrd", INFSLP); 1112 if (error != 0) 1113 return (error); 1114 1115 m0 = mq_dequeue(&sc->sc_mq); 1116 } while (m0 == NULL); 1117 } 1118 1119 m = m0; 1120 while (uio->uio_resid > 0) { 1121 len = ulmin(uio->uio_resid, m->m_len); 1122 if (len != 0) { 1123 error = uiomove(mtod(m, caddr_t), len, uio); 1124 if (error != 0) 1125 break; 1126 } 1127 1128 m = m->m_next; 1129 if (m == NULL) 1130 break; 1131 } 1132 m_freem(m0); 1133 1134 return (error); 1135 } 1136 1137 int 1138 pppacwrite(dev_t dev, struct uio *uio, int ioflag) 1139 { 1140 struct pppac_softc *sc = pppac_lookup(dev); 1141 struct ifnet *ifp = &sc->sc_if; 1142 uint32_t proto; 1143 int error; 1144 struct mbuf *m; 1145 1146 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 1147 return (EHOSTDOWN); 1148 1149 if (uio->uio_resid < ifp->if_hdrlen || uio->uio_resid > MAXMCLBYTES) 1150 return (EMSGSIZE); 1151 1152 m = m_gethdr(M_DONTWAIT, MT_DATA); 1153 if (m == NULL) 1154 return (ENOMEM); 1155 1156 if (uio->uio_resid > MHLEN) { 1157 m_clget(m, M_WAITOK, uio->uio_resid); 1158 if (!ISSET(m->m_flags, M_EXT)) { 1159 m_free(m); 1160 return (ENOMEM); 1161 } 1162 } 1163 1164 m->m_pkthdr.len = m->m_len = uio->uio_resid; 1165 1166 error = uiomove(mtod(m, void *), m->m_len, uio); 1167 if (error != 0) { 1168 m_freem(m); 1169 return (error); 1170 } 1171 1172 #if NBPFILTER > 0 1173 if (ifp->if_bpf) 1174 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); 1175 #endif 1176 1177 /* strip the tunnel header */ 1178 proto = ntohl(*mtod(m, uint32_t *)); 1179 m_adj(m, sizeof(uint32_t)); 1180 1181 m->m_flags &= ~(M_MCAST|M_BCAST); 1182 m->m_pkthdr.ph_ifidx = ifp->if_index; 1183 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 1184 1185 #if NPF > 0 1186 pf_pkt_addr_changed(m); 1187 #endif 1188 1189 counters_pkt(ifp->if_counters, 1190 ifc_ipackets, ifc_ibytes, m->m_pkthdr.len); 1191 1192 NET_LOCK(); 1193 1194 switch (proto) { 1195 case AF_INET: 1196 ipv4_input(ifp, m); 1197 break; 1198 #ifdef INET6 1199 case AF_INET6: 1200 ipv6_input(ifp, m); 1201 break; 1202 #endif 1203 default: 1204 m_freem(m); 1205 error = EAFNOSUPPORT; 1206 break; 1207 } 1208 1209 NET_UNLOCK(); 1210 1211 return (error); 1212 } 1213 1214 int 1215 pppacioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 1216 { 1217 struct pppac_softc *sc = pppac_lookup(dev); 1218 int error = 0; 1219 1220 switch (cmd) { 1221 case FIONREAD: 1222 *(int *)data = mq_hdatalen(&sc->sc_mq); 1223 break; 1224 1225 case PIPEXASESSION: 1226 error = pppac_add_session(sc, (struct pipex_session_req *)data); 1227 break; 1228 case PIPEXDSESSION: 1229 error = pppac_del_session(sc, 1230 (struct pipex_session_close_req *)data); 1231 break; 1232 default: 1233 error = pipex_ioctl(sc, cmd, data); 1234 break; 1235 } 1236 1237 return (error); 1238 } 1239 1240 int 1241 pppackqfilter(dev_t dev, struct knote *kn) 1242 { 1243 struct pppac_softc *sc = pppac_lookup(dev); 1244 struct klist *klist; 1245 1246 switch (kn->kn_filter) { 1247 case EVFILT_READ: 1248 klist = &sc->sc_rklist; 1249 kn->kn_fop = &pppac_rd_filtops; 1250 break; 1251 case EVFILT_WRITE: 1252 klist = &sc->sc_wklist; 1253 kn->kn_fop = &pppac_wr_filtops; 1254 break; 1255 default: 1256 return (EINVAL); 1257 } 1258 1259 kn->kn_hook = sc; 1260 1261 klist_insert(klist, kn); 1262 1263 return (0); 1264 } 1265 1266 static void 1267 filt_pppac_rdetach(struct knote *kn) 1268 { 1269 struct pppac_softc *sc = kn->kn_hook; 1270 1271 klist_remove(&sc->sc_rklist, kn); 1272 } 1273 1274 static int 1275 filt_pppac_read(struct knote *kn, long hint) 1276 { 1277 struct pppac_softc *sc = kn->kn_hook; 1278 1279 MUTEX_ASSERT_LOCKED(&sc->sc_mtx); 1280 1281 kn->kn_data = mq_hdatalen(&sc->sc_mq); 1282 1283 return (kn->kn_data > 0); 1284 } 1285 1286 static void 1287 filt_pppac_wdetach(struct knote *kn) 1288 { 1289 struct pppac_softc *sc = kn->kn_hook; 1290 1291 klist_remove(&sc->sc_wklist, kn); 1292 } 1293 1294 static int 1295 filt_pppac_write(struct knote *kn, long hint) 1296 { 1297 /* We're always ready to accept a write. */ 1298 return (1); 1299 } 1300 1301 static int 1302 filt_pppac_modify(struct kevent *kev, struct knote *kn) 1303 { 1304 struct pppac_softc *sc = kn->kn_hook; 1305 int active; 1306 1307 mtx_enter(&sc->sc_mtx); 1308 active = knote_modify(kev, kn); 1309 mtx_leave(&sc->sc_mtx); 1310 1311 return (active); 1312 } 1313 1314 static int 1315 filt_pppac_process(struct knote *kn, struct kevent *kev) 1316 { 1317 struct pppac_softc *sc = kn->kn_hook; 1318 int active; 1319 1320 mtx_enter(&sc->sc_mtx); 1321 active = knote_process(kn, kev); 1322 mtx_leave(&sc->sc_mtx); 1323 1324 return (active); 1325 } 1326 1327 int 1328 pppacclose(dev_t dev, int flags, int mode, struct proc *p) 1329 { 1330 struct pppac_softc *sc = pppac_lookup(dev); 1331 struct ifnet *ifp = &sc->sc_if; 1332 1333 sc->sc_ready = 0; 1334 1335 NET_LOCK(); 1336 CLR(ifp->if_flags, IFF_RUNNING); 1337 NET_UNLOCK(); 1338 1339 if_detach(ifp); 1340 1341 klist_free(&sc->sc_rklist); 1342 klist_free(&sc->sc_wklist); 1343 1344 pool_put(&pipex_session_pool, sc->sc_multicast_session); 1345 pipex_destroy_all_sessions(sc); 1346 1347 LIST_REMOVE(sc, sc_entry); 1348 free(sc, M_DEVBUF, sizeof(*sc)); 1349 1350 return (0); 1351 } 1352 1353 static int 1354 pppac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1355 { 1356 /* struct ifreq *ifr = (struct ifreq *)data; */ 1357 int error = 0; 1358 1359 switch (cmd) { 1360 case SIOCSIFADDR: 1361 SET(ifp->if_flags, IFF_UP); /* XXX cry cry */ 1362 /* FALLTHROUGH */ 1363 case SIOCSIFFLAGS: 1364 if (ISSET(ifp->if_flags, IFF_UP)) 1365 SET(ifp->if_flags, IFF_RUNNING); 1366 else 1367 CLR(ifp->if_flags, IFF_RUNNING); 1368 break; 1369 case SIOCSIFMTU: 1370 break; 1371 case SIOCADDMULTI: 1372 case SIOCDELMULTI: 1373 /* XXX */ 1374 break; 1375 1376 default: 1377 error = ENOTTY; 1378 break; 1379 } 1380 1381 return (error); 1382 } 1383 1384 static int 1385 pppac_add_session(struct pppac_softc *sc, struct pipex_session_req *req) 1386 { 1387 int error; 1388 struct pipex_session *session; 1389 1390 error = pipex_init_session(&session, req); 1391 if (error != 0) 1392 return (error); 1393 error = pipex_link_session(session, &sc->sc_if, sc); 1394 if (error != 0) 1395 pipex_rele_session(session); 1396 1397 return (error); 1398 } 1399 1400 static int 1401 pppac_del_session(struct pppac_softc *sc, struct pipex_session_close_req *req) 1402 { 1403 struct pipex_session *session; 1404 1405 mtx_enter(&pipex_list_mtx); 1406 1407 session = pipex_lookup_by_session_id_locked(req->pcr_protocol, 1408 req->pcr_session_id); 1409 if (session == NULL || session->ownersc != sc) { 1410 mtx_leave(&pipex_list_mtx); 1411 return (EINVAL); 1412 } 1413 pipex_unlink_session_locked(session); 1414 1415 mtx_leave(&pipex_list_mtx); 1416 1417 pipex_export_session_stats(session, &req->psr_stat); 1418 pipex_rele_session(session); 1419 1420 return (0); 1421 } 1422 1423 static int 1424 pppac_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1425 struct rtentry *rt) 1426 { 1427 int error; 1428 1429 if (!ISSET(ifp->if_flags, IFF_RUNNING)) { 1430 error = EHOSTDOWN; 1431 goto drop; 1432 } 1433 1434 switch (dst->sa_family) { 1435 case AF_INET: 1436 #ifdef INET6 1437 case AF_INET6: 1438 #endif 1439 break; 1440 default: 1441 error = EAFNOSUPPORT; 1442 goto drop; 1443 } 1444 1445 m->m_pkthdr.ph_family = dst->sa_family; 1446 1447 return (if_enqueue(ifp, m)); 1448 1449 drop: 1450 m_freem(m); 1451 return (error); 1452 } 1453 1454 static void 1455 pppac_qstart(struct ifqueue *ifq) 1456 { 1457 struct ifnet *ifp = ifq->ifq_if; 1458 struct pppac_softc *sc = ifp->if_softc; 1459 struct mbuf *m, *m0; 1460 struct pipex_session *session; 1461 struct ip ip; 1462 int rv; 1463 1464 while ((m = ifq_dequeue(ifq)) != NULL) { 1465 #if NBPFILTER > 0 1466 if (ifp->if_bpf) { 1467 bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family, m, 1468 BPF_DIRECTION_OUT); 1469 } 1470 #endif 1471 1472 switch (m->m_pkthdr.ph_family) { 1473 case AF_INET: 1474 if (m->m_pkthdr.len < sizeof(struct ip)) 1475 goto bad; 1476 m_copydata(m, 0, sizeof(struct ip), &ip); 1477 if (IN_MULTICAST(ip.ip_dst.s_addr)) { 1478 /* pass a copy to pipex */ 1479 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT); 1480 if (m0 != NULL) 1481 pipex_ip_output(m0, 1482 sc->sc_multicast_session); 1483 else 1484 goto bad; 1485 } else { 1486 session = pipex_lookup_by_ip_address(ip.ip_dst); 1487 if (session != NULL) { 1488 pipex_ip_output(m, session); 1489 pipex_rele_session(session); 1490 m = NULL; 1491 } 1492 } 1493 break; 1494 } 1495 if (m == NULL) /* handled by pipex */ 1496 continue; 1497 1498 m = m_prepend(m, sizeof(uint32_t), M_DONTWAIT); 1499 if (m == NULL) 1500 goto bad; 1501 *mtod(m, uint32_t *) = htonl(m->m_pkthdr.ph_family); 1502 1503 rv = mq_enqueue(&sc->sc_mq, m); 1504 if (rv == 1) 1505 counters_inc(ifp->if_counters, ifc_collisions); 1506 continue; 1507 bad: 1508 counters_inc(ifp->if_counters, ifc_oerrors); 1509 if (m != NULL) 1510 m_freem(m); 1511 continue; 1512 } 1513 1514 if (!mq_empty(&sc->sc_mq)) { 1515 wakeup(sc); 1516 knote(&sc->sc_rklist, 0); 1517 } 1518 } 1519