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