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