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