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