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