1 /* $NetBSD: if_agr.c,v 1.51 2020/01/29 04:30:41 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c)2005 YAMAMOTO Takashi, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: if_agr.c,v 1.51 2020/01/29 04:30:41 thorpej Exp $"); 31 32 #ifdef _KERNEL_OPT 33 #include "opt_inet.h" 34 #endif 35 36 #include <sys/param.h> 37 #include <sys/callout.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/systm.h> 41 #include <sys/types.h> 42 #include <sys/queue.h> 43 #include <sys/sockio.h> 44 #include <sys/proc.h> /* XXX for curproc */ 45 #include <sys/kauth.h> 46 #include <sys/xcall.h> 47 #include <sys/device.h> 48 #include <sys/module.h> 49 #include <sys/atomic.h> 50 51 #include <net/bpf.h> 52 #include <net/if.h> 53 #include <net/if_dl.h> 54 #include <net/if_types.h> 55 #include <net/if_ether.h> 56 #include <net/if_vlanvar.h> 57 58 #if defined(INET) 59 #include <netinet/in.h> 60 #include <netinet/if_inarp.h> 61 #endif 62 63 #include <net/agr/if_agrvar.h> 64 #include <net/agr/if_agrvar_impl.h> 65 #include <net/agr/if_agrioctl.h> 66 #include <net/agr/if_agrsubr.h> 67 #include <net/agr/if_agrethervar.h> 68 69 #include "ioconf.h" 70 71 static int agr_clone_create(struct if_clone *, int); 72 static int agr_clone_destroy(struct ifnet *); 73 static void agr_start(struct ifnet *); 74 static int agr_setconfig(struct agr_softc *, const struct agrreq *); 75 static int agr_getconfig(struct agr_softc *, struct agrreq *); 76 static int agr_getportlist(struct agr_softc *, struct agrreq *); 77 static int agr_addport(struct ifnet *, struct ifnet *); 78 static int agr_remport(struct ifnet *, struct ifnet *); 79 static int agrreq_copyin(const void *, struct agrreq *); 80 static int agrreq_copyout(void *, struct agrreq *); 81 static int agr_ioctl(struct ifnet *, u_long, void *); 82 static struct agr_port *agr_select_tx_port(struct agr_softc *, struct mbuf *); 83 static int agr_ioctl_filter(struct ifnet *, u_long, void *); 84 static void agr_reset_iftype(struct ifnet *); 85 static int agr_config_promisc(struct agr_softc *); 86 static int agrport_config_promisc_callback(struct agr_port *, void *); 87 static int agrport_config_promisc(struct agr_port *, bool); 88 static int agrport_cleanup(struct agr_softc *, struct agr_port *); 89 90 static int agr_enter(struct agr_softc *); 91 static void agr_exit(struct agr_softc *); 92 static int agr_pause(struct agr_softc *); 93 static void agr_evacuate(struct agr_softc *); 94 static void agr_sync(void); 95 static void agr_ports_lock(struct agr_softc *); 96 static void agr_ports_unlock(struct agr_softc *); 97 static bool agr_ports_enter(struct agr_softc *); 98 static void agr_ports_exit(struct agr_softc *); 99 100 static struct if_clone agr_cloner = 101 IF_CLONE_INITIALIZER("agr", agr_clone_create, agr_clone_destroy); 102 103 static u_int agr_count; 104 105 /* 106 * EXPORTED FUNCTIONS 107 */ 108 109 /* 110 * agrattch: device attach routine. 111 */ 112 113 void 114 agrattach(int count) 115 { 116 117 /* 118 * Nothing to do here, initialization is handled by the 119 * module initialization code in agrinit() below). 120 */ 121 } 122 123 static void 124 agrinit(void) 125 { 126 if_clone_attach(&agr_cloner); 127 } 128 129 static int 130 agrdetach(void) 131 { 132 int error = 0; 133 134 if (agr_count != 0) 135 error = EBUSY; 136 137 if (error == 0) 138 if_clone_detach(&agr_cloner); 139 140 return error; 141 } 142 143 /* 144 * agr_input: frame collector. 145 */ 146 147 void 148 agr_input(struct ifnet *ifp_port, struct mbuf *m) 149 { 150 struct ethercom *ec = (struct ethercom *)ifp_port; 151 struct agr_port *port; 152 struct ifnet *ifp; 153 154 port = ifp_port->if_agrprivate; 155 KASSERT(port); 156 ifp = port->port_agrifp; 157 if ((port->port_flags & AGRPORT_COLLECTING) == 0) { 158 m_freem(m); 159 if_statinc(ifp, if_ierrors); 160 return; 161 } 162 163 m_set_rcvif(m, ifp); 164 165 /* 166 * If VLANs are configured on the interface, check to 167 * see if the device performed the decapsulation and 168 * provided us with the tag. 169 */ 170 if (ec->ec_nvlans && vlan_has_tag(m)) { 171 MODULE_HOOK_CALL_VOID(if_vlan_vlan_input_hook, (ifp, m), 172 m_freem(m)); 173 return; 174 } 175 176 if_percpuq_enqueue(ifp->if_percpuq, m); 177 } 178 179 /* 180 * EXPORTED AGR-INTERNAL FUNCTIONS 181 */ 182 183 void 184 agr_lock(struct agr_softc *sc) 185 { 186 187 mutex_enter(&sc->sc_lock); 188 } 189 190 void 191 agr_unlock(struct agr_softc *sc) 192 { 193 194 mutex_exit(&sc->sc_lock); 195 } 196 197 /* 198 * agr_xmit_frame: transmit a pre-built frame. 199 */ 200 201 int 202 agr_xmit_frame(struct ifnet *ifp_port, struct mbuf *m) 203 { 204 int error; 205 206 struct sockaddr_storage dst0; 207 struct sockaddr *dst; 208 int hdrlen; 209 210 /* 211 * trim off link level header and let if_output re-add it. 212 * XXX better to introduce an API to transmit pre-built frames. 213 */ 214 215 hdrlen = ifp_port->if_hdrlen; 216 if (m->m_pkthdr.len < hdrlen) { 217 m_freem(m); 218 return EINVAL; 219 } 220 memset(&dst0, 0, sizeof(dst0)); 221 dst = (struct sockaddr *)&dst0; 222 dst->sa_family = pseudo_AF_HDRCMPLT; 223 dst->sa_len = hdrlen; 224 m_copydata(m, 0, hdrlen, &dst->sa_data); 225 m_adj(m, hdrlen); 226 227 error = if_output_lock(ifp_port, ifp_port, m, dst, NULL); 228 229 return error; 230 } 231 232 int 233 agrport_ioctl(struct agr_port *port, u_long cmd, void *arg) 234 { 235 struct ifnet *ifp = port->port_ifp; 236 237 KASSERT(ifp->if_agrprivate == (void *)port); 238 KASSERT(ifp->if_ioctl == agr_ioctl_filter); 239 240 return (*port->port_ioctl)(ifp, cmd, arg); 241 } 242 243 /* 244 * INTERNAL FUNCTIONS 245 */ 246 /* 247 * Check for vlan attach/detach. 248 * ec->ec_nvlans is directly modified by the vlan driver. 249 * We keep a local count in sc (sc->sc_nvlans) to detect 250 * when the vlan driver attaches or detaches. 251 * Note the agr interface must be up for this to work. 252 */ 253 static void 254 agr_vlan_check(struct ifnet *ifp, struct agr_softc *sc) 255 { 256 struct ethercom *ec = (void *)ifp; 257 258 /* vlans in sync? */ 259 if (sc->sc_nvlans == ec->ec_nvlans) { 260 return; 261 } 262 263 if (sc->sc_nvlans == 0) { 264 /* vlan added */ 265 agr_port_foreach(sc, agr_vlan_add, NULL); 266 sc->sc_nvlans = ec->ec_nvlans; 267 } else if (ec->ec_nvlans == 0) { 268 bool force_zero = false; 269 /* vlan removed */ 270 agr_port_foreach(sc, agr_vlan_del, &force_zero); 271 sc->sc_nvlans = 0; 272 } 273 } 274 275 static int 276 agr_clone_create(struct if_clone *ifc, int unit) 277 { 278 struct agr_softc *sc; 279 struct ifnet *ifp; 280 int error; 281 282 sc = agr_alloc_softc(); 283 error = agrtimer_init(sc); 284 if (error) { 285 agr_free_softc(sc); 286 return error; 287 } 288 TAILQ_INIT(&sc->sc_ports); 289 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NET); 290 mutex_init(&sc->sc_entry_mtx, MUTEX_DEFAULT, IPL_NONE); 291 cv_init(&sc->sc_insc_cv, "agrsoftc"); 292 cv_init(&sc->sc_ports_cv, "agrports"); 293 ifp = &sc->sc_if; 294 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 295 ifc->ifc_name, unit); 296 297 ifp->if_softc = sc; 298 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 299 ifp->if_start = agr_start; 300 ifp->if_ioctl = agr_ioctl; 301 IFQ_SET_READY(&ifp->if_snd); 302 303 if_attach(ifp); 304 305 agr_reset_iftype(ifp); 306 atomic_inc_uint(&agr_count); 307 return 0; 308 } 309 310 static void 311 agr_reset_iftype(struct ifnet *ifp) 312 { 313 314 ifp->if_type = IFT_OTHER; 315 ifp->if_dlt = DLT_NULL; 316 ifp->if_addrlen = 0; 317 if_alloc_sadl(ifp); 318 } 319 320 static int 321 agr_clone_destroy(struct ifnet *ifp) 322 { 323 struct agr_softc *sc = ifp->if_softc; 324 int error; 325 326 if ((error = agr_pause(sc)) != 0) 327 return error; 328 329 if_detach(ifp); 330 agrtimer_destroy(sc); 331 /* Now that the ifnet has been detached, and our 332 * component ifnets are disconnected, there can be 333 * no new threads in the softc. Wait for every 334 * thread to get out of the softc. 335 */ 336 agr_evacuate(sc); 337 mutex_destroy(&sc->sc_lock); 338 mutex_destroy(&sc->sc_entry_mtx); 339 cv_destroy(&sc->sc_insc_cv); 340 cv_destroy(&sc->sc_ports_cv); 341 agr_free_softc(sc); 342 343 atomic_dec_uint(&agr_count); 344 return 0; 345 } 346 347 static struct agr_port * 348 agr_select_tx_port(struct agr_softc *sc, struct mbuf *m) 349 { 350 351 return (*sc->sc_iftop->iftop_select_tx_port)(sc, m); 352 } 353 354 #if 0 /* "generic" version */ 355 static struct agr_port * 356 agr_select_tx_port(struct agr_softc *sc, struct mbuf *m) 357 { 358 struct agr_port *port; 359 uint32_t hash; 360 361 hash = (*sc->sc_iftop->iftop_hashmbuf)(sc, m); 362 if (sc->sc_nports == 0) 363 return NULL; 364 hash %= sc->sc_nports; 365 port = TAILQ_FIRST(&sc->sc_ports); 366 KASSERT(port != NULL); 367 while (hash--) { 368 port = TAILQ_NEXT(port, port_q); 369 KASSERT(port != NULL); 370 } 371 372 return port; 373 } 374 #endif /* 0 */ 375 376 static void 377 agr_start(struct ifnet *ifp) 378 { 379 struct agr_softc *sc = ifp->if_softc; 380 struct mbuf *m; 381 382 AGR_LOCK(sc); 383 384 while (/* CONSTCOND */ 1) { 385 struct agr_port *port; 386 387 IFQ_DEQUEUE(&ifp->if_snd, m); 388 if (m == NULL) { 389 break; 390 } 391 bpf_mtap(ifp, m, BPF_D_OUT); 392 port = agr_select_tx_port(sc, m); 393 net_stat_ref_t nsr = IF_STAT_GETREF(ifp); 394 if (port) { 395 int error; 396 397 error = agr_xmit_frame(port->port_ifp, m); 398 if (error) { 399 if_statinc_ref(nsr, if_oerrors); 400 } else { 401 if_statinc_ref(nsr, if_opackets); 402 } 403 } else { 404 m_freem(m); 405 if_statinc_ref(nsr, if_oerrors); 406 } 407 IF_STAT_PUTREF(ifp); 408 } 409 410 AGR_UNLOCK(sc); 411 412 ifp->if_flags &= ~IFF_OACTIVE; 413 } 414 415 static int 416 agr_setconfig(struct agr_softc *sc, const struct agrreq *ar) 417 { 418 struct ifnet *ifp = &sc->sc_if; 419 int cmd = ar->ar_cmd; 420 struct ifnet *ifp_port; 421 int error = 0; 422 char ifname[IFNAMSIZ]; 423 424 memset(ifname, 0, sizeof(ifname)); 425 error = copyin(ar->ar_buf, ifname, 426 MIN(ar->ar_buflen, sizeof(ifname) - 1)); 427 if (error) { 428 return error; 429 } 430 ifp_port = ifunit(ifname); 431 if (ifp_port == NULL) { 432 return ENOENT; 433 } 434 435 agr_ports_lock(sc); 436 switch (cmd) { 437 case AGRCMD_ADDPORT: 438 error = agr_addport(ifp, ifp_port); 439 break; 440 441 case AGRCMD_REMPORT: 442 error = agr_remport(ifp, ifp_port); 443 break; 444 445 default: 446 error = EINVAL; 447 break; 448 } 449 agr_ports_unlock(sc); 450 451 return error; 452 } 453 454 static int 455 agr_getportlist(struct agr_softc *sc, struct agrreq *ar) 456 { 457 struct agr_port *port; 458 struct agrportlist apl; 459 struct agrportinfo api; 460 char *cp = ar->ar_buf; 461 size_t bufleft = (cp == NULL) ? 0 : ar->ar_buflen; 462 int error; 463 464 if (cp != NULL) { 465 memset(&apl, 0, sizeof(apl)); 466 memset(&api, 0, sizeof(api)); 467 468 if (bufleft < sizeof(apl)) { 469 return E2BIG; 470 } 471 apl.apl_nports = sc->sc_nports; 472 error = copyout(&apl, cp, sizeof(apl)); 473 if (error) { 474 return error; 475 } 476 cp += sizeof(apl); 477 } 478 bufleft -= sizeof(apl); 479 480 TAILQ_FOREACH(port, &sc->sc_ports, port_q) { 481 if (cp != NULL) { 482 if (bufleft < sizeof(api)) { 483 return E2BIG; 484 } 485 memcpy(api.api_ifname, port->port_ifp->if_xname, 486 sizeof(api.api_ifname)); 487 api.api_flags = 0; 488 if (port->port_flags & AGRPORT_COLLECTING) { 489 api.api_flags |= AGRPORTINFO_COLLECTING; 490 } 491 if (port->port_flags & AGRPORT_DISTRIBUTING) { 492 api.api_flags |= AGRPORTINFO_DISTRIBUTING; 493 } 494 error = copyout(&api, cp, sizeof(api)); 495 if (error) { 496 return error; 497 } 498 cp += sizeof(api); 499 } 500 bufleft -= sizeof(api); 501 } 502 503 if (cp == NULL) { 504 ar->ar_buflen = -bufleft; /* necessary buffer size */ 505 } 506 507 return 0; 508 } 509 510 static int 511 agr_getconfig(struct agr_softc *sc, struct agrreq *ar) 512 { 513 int cmd = ar->ar_cmd; 514 int error; 515 516 (void)agr_ports_enter(sc); 517 switch (cmd) { 518 case AGRCMD_PORTLIST: 519 error = agr_getportlist(sc, ar); 520 break; 521 522 default: 523 error = EINVAL; 524 break; 525 } 526 agr_ports_exit(sc); 527 528 return error; 529 } 530 531 static int 532 agr_addport(struct ifnet *ifp, struct ifnet *ifp_port) 533 { 534 const struct ifaddr *ifa; 535 struct agr_softc *sc = ifp->if_softc; 536 struct agr_port *port = NULL; 537 int error = 0; 538 int s; 539 540 if (ifp_port->if_ioctl == NULL) { 541 error = EOPNOTSUPP; 542 goto out; 543 } 544 545 if (ifp_port->if_agrprivate) { 546 error = EBUSY; 547 goto out; 548 } 549 550 if (ifp_port->if_start == agr_start) { 551 error = EINVAL; 552 goto out; 553 } 554 555 port = malloc(sizeof(*port) + ifp_port->if_addrlen, M_DEVBUF, 556 M_WAITOK | M_ZERO); 557 if (port == NULL) { 558 error = ENOMEM; 559 goto out; 560 } 561 port->port_flags = AGRPORT_LARVAL; 562 563 s = pserialize_read_enter(); 564 IFADDR_READER_FOREACH(ifa, ifp_port) { 565 if (ifa->ifa_addr->sa_family != AF_LINK) { 566 pserialize_read_exit(s); 567 error = EBUSY; 568 goto out; 569 } 570 } 571 pserialize_read_exit(s); 572 573 if (sc->sc_nports == 0) { 574 switch (ifp_port->if_type) { 575 case IFT_ETHER: 576 sc->sc_iftop = &agrether_ops; 577 break; 578 579 default: 580 error = EPROTONOSUPPORT; /* XXX */ 581 goto out; 582 } 583 584 error = (*sc->sc_iftop->iftop_ctor)(sc, ifp_port); 585 if (error) 586 goto out; 587 agrtimer_start(sc); 588 } else { 589 if (ifp->if_type != ifp_port->if_type) { 590 error = EINVAL; 591 goto out; 592 } 593 if (ifp->if_addrlen != ifp_port->if_addrlen) { 594 error = EINVAL; 595 goto out; 596 } 597 } 598 599 memcpy(port->port_origlladdr, CLLADDR(ifp_port->if_sadl), 600 ifp_port->if_addrlen); 601 602 /* 603 * start to modify ifp_port. 604 */ 605 606 /* 607 * XXX this should probably be SIOCALIFADDR but that doesn't 608 * appear to work (ENOTTY). We want to change the mac address 609 * of each port to that of the first port. No need for arps 610 * since there are no inet addresses assigned to the ports. 611 */ 612 IFNET_LOCK(ifp_port); 613 error = if_addr_init(ifp_port, ifp->if_dl, true); 614 IFNET_UNLOCK(ifp_port); 615 616 if (error) { 617 printf("%s: if_addr_init error %d\n", __func__, error); 618 goto cleanup; 619 } 620 port->port_flags |= AGRPORT_LADDRCHANGED; 621 622 ifp->if_type = ifp_port->if_type; 623 AGR_LOCK(sc); 624 625 port->port_ifp = ifp_port; 626 ifp_port->if_agrprivate = port; 627 port->port_agrifp = ifp; 628 TAILQ_INSERT_TAIL(&sc->sc_ports, port, port_q); 629 sc->sc_nports++; 630 631 port->port_ioctl = ifp_port->if_ioctl; 632 ifp_port->if_ioctl = agr_ioctl_filter; 633 634 port->port_flags |= AGRPORT_ATTACHED; 635 636 AGR_UNLOCK(sc); 637 638 error = (*sc->sc_iftop->iftop_portinit)(sc, port); 639 if (error) { 640 printf("%s: portinit error %d\n", __func__, error); 641 goto cleanup; 642 } 643 644 agrport_config_promisc(port, (ifp->if_flags & IFF_PROMISC) != 0); 645 error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, true); 646 if (error) { 647 printf("%s: configmulti error %d\n", __func__, error); 648 goto cleanup; 649 } 650 651 AGR_LOCK(sc); 652 port->port_flags &= ~AGRPORT_LARVAL; 653 AGR_UNLOCK(sc); 654 out: 655 if (error && port) { 656 free(port, M_DEVBUF); 657 } 658 if (error == 0) 659 ifp->if_flags |= IFF_RUNNING; 660 return error; 661 662 cleanup: 663 if (agrport_cleanup(sc, port)) { 664 printf("%s: error on cleanup\n", __func__); 665 666 port = NULL; /* XXX */ 667 } 668 669 if (sc->sc_nports == 0) { 670 KASSERT(TAILQ_EMPTY(&sc->sc_ports)); 671 agrtimer_stop(sc); 672 (*sc->sc_iftop->iftop_dtor)(sc); 673 sc->sc_iftop = NULL; 674 agr_reset_iftype(ifp); 675 } else { 676 KASSERT(!TAILQ_EMPTY(&sc->sc_ports)); 677 } 678 679 goto out; 680 } 681 682 static int 683 agr_remport(struct ifnet *ifp, struct ifnet *ifp_port) 684 { 685 struct agr_softc *sc = ifp->if_softc; 686 struct agr_port *port; 687 int error = 0; 688 689 if (ifp_port->if_agrprivate == NULL) { 690 error = ENOENT; 691 return error; 692 } 693 694 port = ifp_port->if_agrprivate; 695 if (port->port_agrifp != ifp) { 696 error = EINVAL; 697 return error; 698 } 699 700 KASSERT(sc->sc_nports > 0); 701 702 AGR_LOCK(sc); 703 port->port_flags |= AGRPORT_DETACHING; 704 AGR_UNLOCK(sc); 705 706 error = (*sc->sc_iftop->iftop_portfini)(sc, port); 707 if (error) { 708 /* XXX XXX */ 709 printf("%s: portfini error %d\n", __func__, error); 710 goto out; 711 } 712 713 error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, false); 714 if (error) { 715 /* XXX XXX */ 716 printf("%s: configmulti_port error %d\n", __func__, error); 717 goto out; 718 } 719 720 error = agrport_cleanup(sc, port); 721 if (error) { 722 /* XXX XXX */ 723 printf("%s: agrport_cleanup error %d\n", __func__, error); 724 goto out; 725 } 726 727 free(port, M_DEVBUF); 728 729 out: 730 if (sc->sc_nports == 0) { 731 KASSERT(TAILQ_EMPTY(&sc->sc_ports)); 732 agrtimer_stop(sc); 733 (*sc->sc_iftop->iftop_dtor)(sc); 734 sc->sc_iftop = NULL; 735 /* XXX should purge all addresses? */ 736 agr_reset_iftype(ifp); 737 } else { 738 KASSERT(!TAILQ_EMPTY(&sc->sc_ports)); 739 } 740 741 return error; 742 } 743 744 static int 745 agrport_cleanup(struct agr_softc *sc, struct agr_port *port) 746 { 747 struct ifnet *ifp_port = port->port_ifp; 748 int error; 749 int result = 0; 750 751 error = agrport_config_promisc(port, false); 752 if (error) { 753 printf("%s: config_promisc error %d\n", __func__, error); 754 result = error; 755 } 756 757 if ((port->port_flags & AGRPORT_LADDRCHANGED)) { 758 #if 0 759 memcpy(LLADDR(ifp_port->if_sadl), port->port_origlladdr, 760 ifp_port->if_addrlen); 761 if (ifp_port->if_init != NULL) { 762 error = (*ifp_port->if_init)(ifp_port); 763 } 764 #else 765 union { 766 struct sockaddr sa; 767 struct sockaddr_dl sdl; 768 struct sockaddr_storage ss; 769 } u; 770 struct ifaddr ifa; 771 772 sockaddr_dl_init(&u.sdl, sizeof(u.ss), 773 0, ifp_port->if_type, NULL, 0, 774 port->port_origlladdr, ifp_port->if_addrlen); 775 memset(&ifa, 0, sizeof(ifa)); 776 ifa.ifa_addr = &u.sa; 777 error = agrport_ioctl(port, SIOCINITIFADDR, &ifa); 778 #endif 779 if (error) { 780 printf("%s: if_init error %d\n", __func__, error); 781 result = error; 782 } else { 783 port->port_flags &= ~AGRPORT_LADDRCHANGED; 784 } 785 } 786 787 AGR_LOCK(sc); 788 if ((port->port_flags & AGRPORT_ATTACHED)) { 789 ifp_port->if_agrprivate = NULL; 790 791 TAILQ_REMOVE(&sc->sc_ports, port, port_q); 792 sc->sc_nports--; 793 794 KASSERT(ifp_port->if_ioctl == agr_ioctl_filter); 795 ifp_port->if_ioctl = port->port_ioctl; 796 797 port->port_flags &= ~AGRPORT_ATTACHED; 798 } 799 AGR_UNLOCK(sc); 800 801 return result; 802 } 803 804 static int 805 agr_ioctl_multi(struct ifnet *ifp, u_long cmd, struct ifreq *ifr) 806 { 807 struct agr_softc *sc = ifp->if_softc; 808 int error; 809 810 error = (*sc->sc_iftop->iftop_configmulti_ifreq)(sc, ifr, 811 (cmd == SIOCADDMULTI)); 812 813 return error; 814 } 815 816 /* 817 * XXX an incomplete hack; can't filter ioctls handled ifioctl(). 818 * 819 * the intention here is to prevent operations on underlying interfaces 820 * so that their states are not changed in the way that agr(4) doesn't 821 * expect. cf. the BUGS section in the agr(4) manual page. 822 */ 823 static int 824 agr_ioctl_filter(struct ifnet *ifp, u_long cmd, void *arg) 825 { 826 struct agr_port *port = ifp->if_agrprivate; 827 int error; 828 829 KASSERT(port); 830 831 switch (cmd) { 832 case SIOCADDMULTI: /* add m'cast addr */ 833 case SIOCAIFADDR: /* add/chg IF alias */ 834 case SIOCALIFADDR: /* add IF addr */ 835 case SIOCDELMULTI: /* del m'cast addr */ 836 case SIOCDIFADDR: /* delete IF addr */ 837 case SIOCDIFPHYADDR: /* delete gif addrs */ 838 case SIOCDLIFADDR: /* delete IF addr */ 839 case SIOCINITIFADDR: 840 case SIOCSDRVSPEC: /* set driver-specific parameters */ 841 case SIOCSIFADDR: /* set ifnet address */ 842 case SIOCSIFBRDADDR: /* set broadcast addr */ 843 case SIOCSIFDSTADDR: /* set p-p address */ 844 case SIOCSIFGENERIC: /* generic IF set op */ 845 case SIOCSIFMEDIA: /* set net media */ 846 case SIOCSIFMETRIC: /* set IF metric */ 847 case SIOCSIFMTU: /* set ifnet mtu */ 848 case SIOCSIFNETMASK: /* set net addr mask */ 849 case SIOCSIFPHYADDR: /* set gif addres */ 850 case SIOCSLIFPHYADDR: /* set gif addrs */ 851 case SIOCSVH: /* set carp param */ 852 error = EBUSY; 853 break; 854 case SIOCSIFCAP: /* XXX */ 855 case SIOCSIFFLAGS: /* XXX */ 856 default: 857 error = agrport_ioctl(port, cmd, arg); 858 break; 859 } 860 return error; 861 } 862 863 static int 864 agrreq_copyin(const void *ubuf, struct agrreq *ar) 865 { 866 int error; 867 868 error = copyin(ubuf, ar, sizeof(*ar)); 869 if (error) { 870 return error; 871 } 872 873 if (ar->ar_version != AGRREQ_VERSION) { 874 return EINVAL; 875 } 876 877 return 0; 878 } 879 880 static int 881 agrreq_copyout(void *ubuf, struct agrreq *ar) 882 { 883 int error; 884 885 KASSERT(ar->ar_version == AGRREQ_VERSION); 886 887 error = copyout(ar, ubuf, sizeof(*ar)); 888 if (error) { 889 return error; 890 } 891 892 return 0; 893 } 894 895 /* Make sure that if any interrupt handlers are out of the softc. */ 896 static void 897 agr_sync(void) 898 { 899 900 if (!mp_online) 901 return; 902 903 xc_barrier(0); 904 } 905 906 static int 907 agr_pause(struct agr_softc *sc) 908 { 909 int error; 910 911 mutex_enter(&sc->sc_entry_mtx); 912 if ((error = sc->sc_noentry) != 0) 913 goto out; 914 915 sc->sc_noentry = EBUSY; 916 917 while (sc->sc_insc != 0) 918 cv_wait(&sc->sc_insc_cv, &sc->sc_entry_mtx); 919 920 if (sc->sc_nports == 0) { 921 sc->sc_noentry = ENXIO; 922 } else { 923 sc->sc_noentry = 0; 924 error = EBUSY; 925 } 926 cv_broadcast(&sc->sc_insc_cv); 927 out: 928 mutex_exit(&sc->sc_entry_mtx); 929 return error; 930 } 931 932 static void 933 agr_evacuate(struct agr_softc *sc) 934 { 935 mutex_enter(&sc->sc_entry_mtx); 936 cv_broadcast(&sc->sc_insc_cv); 937 while (sc->sc_insc != 0 || sc->sc_paused != 0) 938 cv_wait(&sc->sc_insc_cv, &sc->sc_entry_mtx); 939 mutex_exit(&sc->sc_entry_mtx); 940 941 agr_sync(); 942 } 943 944 static int 945 agr_enter(struct agr_softc *sc) 946 { 947 int error; 948 949 mutex_enter(&sc->sc_entry_mtx); 950 sc->sc_paused++; 951 while ((error = sc->sc_noentry) == EBUSY) 952 cv_wait(&sc->sc_insc_cv, &sc->sc_entry_mtx); 953 sc->sc_paused--; 954 if (error == 0) 955 sc->sc_insc++; 956 mutex_exit(&sc->sc_entry_mtx); 957 958 return error; 959 } 960 961 static void 962 agr_exit(struct agr_softc *sc) 963 { 964 mutex_enter(&sc->sc_entry_mtx); 965 if (--sc->sc_insc == 0) 966 cv_signal(&sc->sc_insc_cv); 967 mutex_exit(&sc->sc_entry_mtx); 968 } 969 970 static bool 971 agr_ports_enter(struct agr_softc *sc) 972 { 973 mutex_enter(&sc->sc_entry_mtx); 974 while (sc->sc_wrports) 975 cv_wait(&sc->sc_ports_cv, &sc->sc_entry_mtx); 976 sc->sc_rdports++; 977 mutex_exit(&sc->sc_entry_mtx); 978 979 return true; 980 } 981 982 static void 983 agr_ports_exit(struct agr_softc *sc) 984 { 985 mutex_enter(&sc->sc_entry_mtx); 986 if (--sc->sc_rdports == 0) 987 cv_signal(&sc->sc_ports_cv); 988 mutex_exit(&sc->sc_entry_mtx); 989 } 990 991 static void 992 agr_ports_lock(struct agr_softc *sc) 993 { 994 mutex_enter(&sc->sc_entry_mtx); 995 while (sc->sc_rdports != 0) 996 cv_wait(&sc->sc_ports_cv, &sc->sc_entry_mtx); 997 sc->sc_wrports = true; 998 mutex_exit(&sc->sc_entry_mtx); 999 } 1000 1001 static void 1002 agr_ports_unlock(struct agr_softc *sc) 1003 { 1004 mutex_enter(&sc->sc_entry_mtx); 1005 sc->sc_wrports = false; 1006 cv_signal(&sc->sc_ports_cv); 1007 mutex_exit(&sc->sc_entry_mtx); 1008 } 1009 1010 static int 1011 agr_ioctl(struct ifnet *ifp, const u_long cmd, void *data) 1012 { 1013 struct agr_softc *sc = ifp->if_softc; 1014 struct ifreq *ifr = (struct ifreq *)data; 1015 struct ifaddr *ifa = (struct ifaddr *)data; 1016 struct agrreq ar; 1017 int error; 1018 bool in_ports = false; 1019 int s; 1020 1021 if ((error = agr_enter(sc)) != 0) 1022 return error; 1023 1024 s = splnet(); 1025 1026 switch (cmd) { 1027 case SIOCINITIFADDR: 1028 in_ports = agr_ports_enter(sc); 1029 if (sc->sc_nports == 0) { 1030 error = EINVAL; 1031 break; 1032 } 1033 ifp->if_flags |= IFF_UP; 1034 switch (ifa->ifa_addr->sa_family) { 1035 #if defined(INET) 1036 case AF_INET: 1037 arp_ifinit(ifp, ifa); 1038 break; 1039 #endif 1040 default: 1041 break; 1042 } 1043 break; 1044 1045 #if 0 /* notyet */ 1046 case SIOCSIFMTU: 1047 #endif 1048 1049 case SIOCSIFFLAGS: 1050 /* 1051 * Check for a change in vlan status. This ioctl is the 1052 * only way we can tell that a vlan has attached or detached. 1053 * Note the agr interface must be up. 1054 */ 1055 agr_vlan_check(ifp, sc); 1056 1057 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 1058 break; 1059 agr_config_promisc(sc); 1060 break; 1061 1062 case SIOCSETAGR: 1063 splx(s); 1064 error = kauth_authorize_network(kauth_cred_get(), 1065 KAUTH_NETWORK_INTERFACE, 1066 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 1067 NULL); 1068 if (!error) { 1069 error = agrreq_copyin(ifr->ifr_data, &ar); 1070 } 1071 if (!error) { 1072 error = agr_setconfig(sc, &ar); 1073 } 1074 s = splnet(); 1075 break; 1076 1077 case SIOCGETAGR: 1078 splx(s); 1079 error = agrreq_copyin(ifr->ifr_data, &ar); 1080 if (!error) { 1081 error = agr_getconfig(sc, &ar); 1082 } 1083 if (!error) { 1084 error = agrreq_copyout(ifr->ifr_data, &ar); 1085 } 1086 s = splnet(); 1087 break; 1088 1089 case SIOCADDMULTI: 1090 case SIOCDELMULTI: 1091 in_ports = agr_ports_enter(sc); 1092 if (sc->sc_nports == 0) 1093 error = EINVAL; 1094 else 1095 error = agr_ioctl_multi(ifp, cmd, ifr); 1096 break; 1097 1098 default: 1099 error = ifioctl_common(ifp, cmd, data); 1100 break; 1101 } 1102 1103 if (in_ports) 1104 agr_ports_exit(sc); 1105 1106 splx(s); 1107 1108 agr_exit(sc); 1109 1110 return error; 1111 } 1112 1113 static int 1114 agr_config_promisc(struct agr_softc *sc) 1115 { 1116 int error; 1117 1118 agr_port_foreach(sc, agrport_config_promisc_callback, &error); 1119 1120 return error; 1121 } 1122 1123 static int 1124 agrport_config_promisc_callback(struct agr_port *port, void *arg) 1125 { 1126 struct agr_softc *sc = AGR_SC_FROM_PORT(port); 1127 int *errorp = arg; 1128 int error; 1129 bool promisc; 1130 1131 promisc = (sc->sc_if.if_flags & IFF_PROMISC) != 0; 1132 1133 error = agrport_config_promisc(port, promisc); 1134 if (error) { 1135 *errorp = error; 1136 } 1137 1138 return 0; 1139 } 1140 1141 static int 1142 agrport_config_promisc(struct agr_port *port, bool promisc) 1143 { 1144 int error; 1145 1146 if (( promisc && (port->port_flags & AGRPORT_PROMISC) != 0) || 1147 (!promisc && (port->port_flags & AGRPORT_PROMISC) == 0)) { 1148 return 0; 1149 } 1150 1151 error = ifpromisc(port->port_ifp, promisc); 1152 if (error == 0) { 1153 if (promisc) { 1154 port->port_flags |= AGRPORT_PROMISC; 1155 } else { 1156 port->port_flags &= ~AGRPORT_PROMISC; 1157 } 1158 } 1159 1160 return error; 1161 } 1162 1163 /* 1164 * Module infrastructure 1165 */ 1166 #include <net/if_module.h> 1167 1168 IF_MODULE(MODULE_CLASS_DRIVER, agr, NULL) 1169