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