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