1 /* $NetBSD: if_agr.c,v 1.5 2006/05/15 09:07:59 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.5 2006/05/15 09:07:59 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 53 #if defined(INET) 54 #include <netinet/in.h> 55 #include <netinet/if_inarp.h> 56 #endif 57 58 #include <net/agr/if_agrvar.h> 59 #include <net/agr/if_agrvar_impl.h> 60 #include <net/agr/if_agrioctl.h> 61 #include <net/agr/if_agrsubr.h> 62 #include <net/agr/if_agrethervar.h> 63 64 void agrattach(int); 65 66 static int agr_clone_create(struct if_clone *, int); 67 static int agr_clone_destroy(struct ifnet *); 68 static void agr_start(struct ifnet *); 69 static int agr_setconfig(struct ifnet *, const struct agrreq *); 70 static int agr_getconfig(struct ifnet *, struct agrreq *); 71 static int agr_getportlist(struct ifnet *, struct agrreq *); 72 static int agr_addport(struct ifnet *, struct ifnet *); 73 static int agr_remport(struct ifnet *, struct ifnet *); 74 static int agrreq_copyin(const void *, struct agrreq *); 75 static int agrreq_copyout(void *, struct agrreq *); 76 static int agr_ioctl(struct ifnet *, u_long, caddr_t); 77 static struct agr_port *agr_select_tx_port(struct agr_softc *, struct mbuf *); 78 static int agr_ioctl_filter(struct ifnet *, u_long, caddr_t); 79 static void agr_reset_iftype(struct ifnet *); 80 static int agr_config_promisc(struct agr_softc *); 81 static int agrport_config_promisc_callback(struct agr_port *, void *); 82 static int agrport_config_promisc(struct agr_port *, boolean_t); 83 static int agrport_cleanup(struct agr_softc *, struct agr_port *); 84 85 static struct if_clone agr_cloner = 86 IF_CLONE_INITIALIZER("agr", agr_clone_create, agr_clone_destroy); 87 88 /* 89 * EXPORTED FUNCTIONS 90 */ 91 92 /* 93 * agrattch: device attach routine. 94 */ 95 96 void 97 agrattach(int count) 98 { 99 100 if_clone_attach(&agr_cloner); 101 } 102 103 /* 104 * agr_input: frame collector. 105 */ 106 107 void 108 agr_input(struct ifnet *ifp_port, struct mbuf *m) 109 { 110 struct agr_port *port; 111 struct ifnet *ifp; 112 113 port = ifp_port->if_agrprivate; 114 KASSERT(port); 115 ifp = port->port_agrifp; 116 if ((port->port_flags & AGRPORT_COLLECTING) == 0) { 117 m_freem(m); 118 ifp->if_ierrors++; 119 return; 120 } 121 122 ifp->if_ipackets++; 123 m->m_pkthdr.rcvif = ifp; 124 125 #if NBPFILTER > 0 126 if (ifp->if_bpf) { 127 bpf_mtap(ifp->if_bpf, m); 128 } 129 #endif 130 131 (*ifp->if_input)(ifp, m); 132 } 133 134 /* 135 * EXPORTED AGR-INTERNAL FUNCTIONS 136 */ 137 138 int 139 agr_lock(struct agr_softc *sc) 140 { 141 int s; 142 143 s = splnet(); 144 simple_lock(&sc->sc_lock); 145 146 return s; 147 } 148 149 void 150 agr_unlock(struct agr_softc *sc, int savedipl) 151 { 152 153 simple_unlock(&sc->sc_lock); 154 splx(savedipl); 155 } 156 157 void 158 agr_ioctl_lock(struct agr_softc *sc) 159 { 160 161 lockmgr(&sc->sc_ioctl_lock, LK_EXCLUSIVE, NULL); 162 } 163 164 void 165 agr_ioctl_unlock(struct agr_softc *sc) 166 { 167 168 lockmgr(&sc->sc_ioctl_lock, LK_RELEASE, NULL); 169 } 170 171 /* 172 * agr_xmit_frame: transmit a pre-built frame. 173 */ 174 175 int 176 agr_xmit_frame(struct ifnet *ifp_port, struct mbuf *m) 177 { 178 int error; 179 180 struct sockaddr_storage dst0; 181 struct sockaddr *dst; 182 int hdrlen; 183 184 /* 185 * trim off link level header and let if_output re-add it. 186 * XXX better to introduce an API to transmit pre-built frames. 187 */ 188 189 hdrlen = ifp_port->if_hdrlen; 190 if (m->m_pkthdr.len < hdrlen) { 191 m_freem(m); 192 return EINVAL; 193 } 194 memset(&dst0, 0, sizeof(dst0)); 195 dst = (struct sockaddr *)&dst0; 196 dst->sa_family = pseudo_AF_HDRCMPLT; 197 dst->sa_len = hdrlen; 198 m_copydata(m, 0, hdrlen, &dst->sa_data); 199 m_adj(m, hdrlen); 200 201 error = (*ifp_port->if_output)(ifp_port, m, dst, NULL); 202 203 return error; 204 } 205 206 int 207 agrport_ioctl(struct agr_port *port, u_long cmd, caddr_t arg) 208 { 209 struct ifnet *ifp = port->port_ifp; 210 211 KASSERT(ifp->if_agrprivate == (void *)port); 212 KASSERT(ifp->if_ioctl == agr_ioctl_filter); 213 214 return (*port->port_ioctl)(ifp, cmd, arg); 215 } 216 217 /* 218 * INTERNAL FUNCTIONS 219 */ 220 221 static int 222 agr_clone_create(struct if_clone *ifc, int unit) 223 { 224 struct agr_softc *sc; 225 struct ifnet *ifp; 226 227 sc = agr_alloc_softc(); 228 TAILQ_INIT(&sc->sc_ports); 229 lockinit(&sc->sc_ioctl_lock, PSOCK, "agrioctl", 0, 0); 230 simple_lock_init(&sc->sc_lock); 231 agrtimer_init(sc); 232 ifp = &sc->sc_if; 233 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 234 ifc->ifc_name, unit); 235 236 ifp->if_softc = sc; 237 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 238 ifp->if_start = agr_start; 239 ifp->if_ioctl = agr_ioctl; 240 IFQ_SET_READY(&ifp->if_snd); 241 242 if_attach(ifp); 243 244 agr_reset_iftype(ifp); 245 246 return 0; 247 } 248 249 static void 250 agr_reset_iftype(struct ifnet *ifp) 251 { 252 253 ifp->if_type = IFT_OTHER; 254 ifp->if_dlt = DLT_NULL; 255 ifp->if_addrlen = 0; 256 if_alloc_sadl(ifp); 257 } 258 259 static int 260 agr_clone_destroy(struct ifnet *ifp) 261 { 262 struct agr_softc *sc = ifp->if_softc; 263 int error; 264 int s; 265 266 agr_ioctl_lock(sc); 267 268 s = AGR_LOCK(sc); 269 if (sc->sc_nports > 0) { 270 error = EBUSY; 271 } else { 272 error = 0; 273 } 274 AGR_UNLOCK(sc, s); 275 276 agr_ioctl_unlock(sc); 277 278 if (error == 0) { 279 if_detach(ifp); 280 agr_free_softc(sc); 281 } 282 283 return error; 284 } 285 286 static struct agr_port * 287 agr_select_tx_port(struct agr_softc *sc, struct mbuf *m) 288 { 289 290 return (*sc->sc_iftop->iftop_select_tx_port)(sc, m); 291 } 292 293 #if 0 /* "generic" version */ 294 static struct agr_port * 295 agr_select_tx_port(struct agr_softc *sc, struct mbuf *m) 296 { 297 struct agr_port *port; 298 uint32_t hash; 299 300 hash = (*sc->sc_iftop->iftop_hashmbuf)(sc, m); 301 if (sc->sc_nports == 0) 302 return NULL; 303 hash %= sc->sc_nports; 304 port = TAILQ_FIRST(&sc->sc_ports); 305 KASSERT(port != NULL); 306 while (hash--) { 307 port = TAILQ_NEXT(port, port_q); 308 KASSERT(port != NULL); 309 } 310 311 return port; 312 } 313 #endif /* 0 */ 314 315 static void 316 agr_start(struct ifnet *ifp) 317 { 318 struct agr_softc *sc = ifp->if_softc; 319 struct mbuf *m; 320 int s; 321 322 s = AGR_LOCK(sc); 323 324 while (/* CONSTCOND */ 1) { 325 struct agr_port *port; 326 327 IFQ_DEQUEUE(&ifp->if_snd, m); 328 if (m == NULL) { 329 break; 330 } 331 #if NBPFILTER > 0 332 if (ifp->if_bpf) { 333 bpf_mtap(ifp->if_bpf, m); 334 } 335 #endif 336 port = agr_select_tx_port(sc, m); 337 if (port) { 338 int error; 339 340 error = agr_xmit_frame(port->port_ifp, m); 341 if (error) { 342 ifp->if_oerrors++; 343 } else { 344 ifp->if_opackets++; 345 } 346 } else { 347 m_freem(m); 348 ifp->if_oerrors++; 349 } 350 } 351 352 AGR_UNLOCK(sc, s); 353 354 ifp->if_flags &= ~IFF_OACTIVE; 355 } 356 357 static int 358 agr_setconfig(struct ifnet *ifp, const struct agrreq *ar) 359 { 360 int cmd = ar->ar_cmd; 361 struct ifnet *ifp_port; 362 int error = 0; 363 char ifname[IFNAMSIZ]; 364 365 error = copyin(ar->ar_buf, ifname, MIN(ar->ar_buflen, sizeof(ifname))); 366 if (error) { 367 return error; 368 } 369 ifp_port = ifunit(ifname); 370 if (ifp_port == NULL) { 371 return ENOENT; 372 } 373 374 switch (cmd) { 375 case AGRCMD_ADDPORT: 376 error = agr_addport(ifp, ifp_port); 377 break; 378 379 case AGRCMD_REMPORT: 380 error = agr_remport(ifp, ifp_port); 381 break; 382 383 default: 384 error = EINVAL; 385 break; 386 } 387 388 return error; 389 } 390 391 static int 392 agr_getportlist(struct ifnet *ifp, struct agrreq *ar) 393 { 394 struct agr_softc *sc = ifp->if_softc; 395 struct agr_port *port; 396 struct agrportlist apl; 397 struct agrportinfo api; 398 char *cp = ar->ar_buf; 399 size_t bufleft = (cp == NULL) ? 0 : ar->ar_buflen; 400 int error; 401 402 if (cp != NULL) { 403 memset(&apl, 0, sizeof(apl)); 404 memset(&api, 0, sizeof(api)); 405 406 if (bufleft < sizeof(apl)) { 407 return E2BIG; 408 } 409 apl.apl_nports = sc->sc_nports; 410 error = copyout(&apl, cp, sizeof(apl)); 411 if (error) { 412 return error; 413 } 414 cp += sizeof(apl); 415 } 416 bufleft -= sizeof(apl); 417 418 TAILQ_FOREACH(port, &sc->sc_ports, port_q) { 419 if (cp != NULL) { 420 if (bufleft < sizeof(api)) { 421 return E2BIG; 422 } 423 memcpy(api.api_ifname, port->port_ifp->if_xname, 424 sizeof(api.api_ifname)); 425 api.api_flags = 0; 426 if (port->port_flags & AGRPORT_COLLECTING) { 427 api.api_flags |= AGRPORTINFO_COLLECTING; 428 } 429 if (port->port_flags & AGRPORT_DISTRIBUTING) { 430 api.api_flags |= AGRPORTINFO_DISTRIBUTING; 431 } 432 error = copyout(&api, cp, sizeof(api)); 433 if (error) { 434 return error; 435 } 436 cp += sizeof(api); 437 } 438 bufleft -= sizeof(api); 439 } 440 441 if (cp == NULL) { 442 ar->ar_buflen = -bufleft; /* necessary buffer size */ 443 } 444 445 return 0; 446 } 447 448 static int 449 agr_getconfig(struct ifnet *ifp, struct agrreq *ar) 450 { 451 int cmd = ar->ar_cmd; 452 int error; 453 454 switch (cmd) { 455 case AGRCMD_PORTLIST: 456 error = agr_getportlist(ifp, ar); 457 break; 458 459 default: 460 error = EINVAL; 461 break; 462 } 463 464 return error; 465 } 466 467 static int 468 agr_addport(struct ifnet *ifp, struct ifnet *ifp_port) 469 { 470 struct agr_softc *sc = ifp->if_softc; 471 struct agr_port *port = NULL; 472 int error = 0; 473 int s; 474 475 if (ifp_port->if_ioctl == NULL) { 476 error = EOPNOTSUPP; 477 goto out; 478 } 479 480 if (ifp_port->if_agrprivate) { 481 error = EBUSY; 482 goto out; 483 } 484 485 if (ifp_port->if_start == agr_start) { 486 error = EINVAL; 487 goto out; 488 } 489 490 port = malloc(sizeof(*port) + ifp_port->if_addrlen, M_DEVBUF, 491 M_WAITOK | M_ZERO); 492 if (port == NULL) { 493 error = ENOMEM; 494 goto out; 495 } 496 port->port_flags = AGRPORT_LARVAL; 497 498 if (TAILQ_NEXT(TAILQ_FIRST(&ifp_port->if_addrlist), ifa_list) != NULL) { 499 error = EBUSY; 500 goto out; 501 } 502 503 if (sc->sc_nports == 0) { 504 switch (ifp_port->if_type) { 505 case IFT_ETHER: 506 sc->sc_iftop = &agrether_ops; 507 break; 508 509 default: 510 error = EPROTONOSUPPORT; /* XXX */ 511 goto out; 512 } 513 514 error = (*sc->sc_iftop->iftop_ctor)(sc, ifp_port); 515 if (error) 516 goto out; 517 agrtimer_start(sc); 518 } else { 519 if (ifp->if_type != ifp_port->if_type) { 520 error = EINVAL; 521 goto out; 522 } 523 if (ifp->if_addrlen != ifp_port->if_addrlen) { 524 error = EINVAL; 525 goto out; 526 } 527 } 528 529 memcpy(port->port_origlladdr, LLADDR(ifp_port->if_sadl), 530 ifp_port->if_addrlen); 531 532 /* 533 * start to modify ifp_port. 534 */ 535 536 error = (*ifp_port->if_ioctl)(ifp_port, SIOCSIFADDR, 537 (caddr_t)TAILQ_FIRST(&ifp->if_addrlist)); 538 539 if (error) { 540 printf("%s: SIOCSIFADDR error %d\n", __func__, error); 541 goto cleanup; 542 } 543 port->port_flags |= AGRPORT_LADDRCHANGED; 544 545 ifp->if_type = ifp_port->if_type; 546 s = AGR_LOCK(sc); 547 548 port->port_ifp = ifp_port; 549 ifp_port->if_agrprivate = port; 550 port->port_agrifp = ifp; 551 TAILQ_INSERT_TAIL(&sc->sc_ports, port, port_q); 552 sc->sc_nports++; 553 554 port->port_ioctl = ifp_port->if_ioctl; 555 ifp_port->if_ioctl = agr_ioctl_filter; 556 557 port->port_flags |= AGRPORT_ATTACHED; 558 559 AGR_UNLOCK(sc, s); 560 561 error = (*sc->sc_iftop->iftop_portinit)(sc, port); 562 if (error) { 563 printf("%s: portinit error %d\n", __func__, error); 564 goto cleanup; 565 } 566 567 ifp->if_flags |= IFF_RUNNING; 568 569 agrport_config_promisc(port, (ifp->if_flags & IFF_PROMISC) != 0); 570 error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, TRUE); 571 if (error) { 572 printf("%s: configmulti error %d\n", __func__, error); 573 goto cleanup; 574 } 575 576 s = AGR_LOCK(sc); 577 port->port_flags &= ~AGRPORT_LARVAL; 578 AGR_UNLOCK(sc, s); 579 out: 580 if (error && port) { 581 free(port, M_DEVBUF); 582 } 583 return error; 584 585 cleanup: 586 if (agrport_cleanup(sc, port)) { 587 printf("%s: error on cleanup\n", __func__); 588 589 port = NULL; /* XXX */ 590 } 591 592 if (sc->sc_nports == 0) { 593 KASSERT(TAILQ_EMPTY(&sc->sc_ports)); 594 agrtimer_stop(sc); 595 (*sc->sc_iftop->iftop_dtor)(sc); 596 sc->sc_iftop = NULL; 597 agr_reset_iftype(ifp); 598 } else { 599 KASSERT(!TAILQ_EMPTY(&sc->sc_ports)); 600 } 601 602 goto out; 603 } 604 605 static int 606 agr_remport(struct ifnet *ifp, struct ifnet *ifp_port) 607 { 608 struct agr_softc *sc = ifp->if_softc; 609 struct agr_port *port; 610 int error = 0; 611 int s; 612 613 if (ifp_port->if_agrprivate == NULL) { 614 error = ENOENT; 615 return error; 616 } 617 618 port = ifp_port->if_agrprivate; 619 if (port->port_agrifp != ifp) { 620 error = EINVAL; 621 return error; 622 } 623 624 KASSERT(sc->sc_nports > 0); 625 626 #if 0 627 if (sc->sc_nports == 1 && 628 TAILQ_NEXT(TAILQ_FIRST(&ifp->if_addrlist), ifa_list) != NULL) { 629 error = EBUSY; 630 return error; 631 } 632 #endif 633 634 s = AGR_LOCK(sc); 635 port->port_flags |= AGRPORT_DETACHING; 636 AGR_UNLOCK(sc, s); 637 638 error = (*sc->sc_iftop->iftop_portfini)(sc, port); 639 if (error) { 640 /* XXX XXX */ 641 printf("%s: portfini error %d\n", __func__, error); 642 goto out; 643 } 644 645 error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, FALSE); 646 if (error) { 647 /* XXX XXX */ 648 printf("%s: configmulti_port error %d\n", __func__, error); 649 goto out; 650 } 651 652 error = agrport_cleanup(sc, port); 653 if (error) { 654 /* XXX XXX */ 655 printf("%s: agrport_cleanup error %d\n", __func__, error); 656 goto out; 657 } 658 659 free(port, M_DEVBUF); 660 661 out: 662 if (sc->sc_nports == 0) { 663 KASSERT(TAILQ_EMPTY(&sc->sc_ports)); 664 agrtimer_stop(sc); 665 (*sc->sc_iftop->iftop_dtor)(sc); 666 sc->sc_iftop = NULL; 667 /* XXX should purge all addresses? */ 668 agr_reset_iftype(ifp); 669 } else { 670 KASSERT(!TAILQ_EMPTY(&sc->sc_ports)); 671 } 672 673 return error; 674 } 675 676 static int 677 agrport_cleanup(struct agr_softc *sc, struct agr_port *port) 678 { 679 struct ifnet *ifp_port = port->port_ifp; 680 int error; 681 int result = 0; 682 int s; 683 684 error = agrport_config_promisc(port, FALSE); 685 if (error) { 686 printf("%s: config_promisc error %d\n", __func__, error); 687 result = error; 688 } 689 690 if ((port->port_flags & AGRPORT_LADDRCHANGED)) { 691 #if 0 692 memcpy(LLADDR(ifp_port->if_sadl), port->port_origlladdr, 693 ifp_port->if_addrlen); 694 if (ifp_port->if_init != NULL) { 695 error = (*ifp_port->if_init)(ifp_port); 696 } 697 #else 698 struct sockaddr_dl *sdl; 699 struct ifaddr ifa; 700 int sdllen; 701 int addrlen; 702 703 addrlen = ifp_port->if_addrlen; 704 sdllen = sizeof(*sdl) - sizeof(sdl->sdl_data) + addrlen; 705 sdl = malloc(sdllen, M_TEMP, M_WAITOK); 706 if (sdl == NULL) { 707 error = ENOMEM; 708 } else { 709 memset(sdl, 0, sdllen); 710 sdl->sdl_len = sdllen; 711 sdl->sdl_family = AF_LINK; 712 sdl->sdl_type = ifp_port->if_type; 713 sdl->sdl_alen = addrlen; 714 memcpy(LLADDR(sdl), port->port_origlladdr, addrlen); 715 memset(&ifa, 0, sizeof(ifa)); 716 ifa.ifa_addr = (struct sockaddr *)sdl; 717 error = agrport_ioctl(port, SIOCSIFADDR, (caddr_t)&ifa); 718 free(sdl, M_TEMP); 719 } 720 #endif 721 if (error) { 722 printf("%s: if_init error %d\n", __func__, error); 723 result = error; 724 } else { 725 port->port_flags &= ~AGRPORT_LADDRCHANGED; 726 } 727 } 728 729 s = AGR_LOCK(sc); 730 if ((port->port_flags & AGRPORT_ATTACHED)) { 731 ifp_port->if_agrprivate = NULL; 732 733 TAILQ_REMOVE(&sc->sc_ports, port, port_q); 734 sc->sc_nports--; 735 736 KASSERT(ifp_port->if_ioctl == agr_ioctl_filter); 737 ifp_port->if_ioctl = port->port_ioctl; 738 739 port->port_flags &= ~AGRPORT_ATTACHED; 740 } 741 AGR_UNLOCK(sc, s); 742 743 return result; 744 } 745 746 static int 747 agr_ioctl_multi(struct ifnet *ifp, u_long cmd, struct ifreq *ifr) 748 { 749 struct agr_softc *sc = ifp->if_softc; 750 int error; 751 752 error = (*sc->sc_iftop->iftop_configmulti_ifreq)(sc, ifr, 753 (cmd == SIOCADDMULTI)); 754 755 return error; 756 } 757 758 /* XXX an incomplete hack; can't filter ioctls handled ifioctl(). */ 759 static int 760 agr_ioctl_filter(struct ifnet *ifp, u_long cmd, caddr_t arg) 761 { 762 struct agr_port *port = ifp->if_agrprivate; 763 int error; 764 765 KASSERT(port); 766 767 switch (cmd) { 768 case SIOCGIFADDR: 769 case SIOCGIFMEDIA: 770 case SIOCSIFFLAGS: /* XXX */ 771 error = agrport_ioctl(port, cmd, arg); 772 break; 773 default: 774 error = EBUSY; 775 break; 776 } 777 return error; 778 } 779 780 static int 781 agrreq_copyin(const void *ubuf, struct agrreq *ar) 782 { 783 int error; 784 785 error = copyin(ubuf, ar, sizeof(*ar)); 786 if (error) { 787 return error; 788 } 789 790 if (ar->ar_version != AGRREQ_VERSION) { 791 return EINVAL; 792 } 793 794 return 0; 795 } 796 797 static int 798 agrreq_copyout(void *ubuf, struct agrreq *ar) 799 { 800 int error; 801 802 KASSERT(ar->ar_version == AGRREQ_VERSION); 803 804 error = copyout(ar, ubuf, sizeof(*ar)); 805 if (error) { 806 return error; 807 } 808 809 return 0; 810 } 811 812 static int 813 agr_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 814 { 815 struct agr_softc *sc = ifp->if_softc; 816 struct ifreq *ifr = (struct ifreq *)data; 817 struct ifaddr *ifa = (struct ifaddr *)data; 818 struct sockaddr *sa; 819 struct agrreq ar; 820 struct proc *p; 821 int error = 0; 822 int s; 823 824 agr_ioctl_lock(sc); 825 826 s = splnet(); 827 828 switch (cmd) { 829 case SIOCSIFADDR: 830 if (sc->sc_nports == 0) { 831 error = EINVAL; 832 break; 833 } 834 ifp->if_flags |= IFF_UP; 835 switch (ifa->ifa_addr->sa_family) { 836 #if defined(INET) 837 case AF_INET: 838 arp_ifinit(ifp, ifa); 839 break; 840 #endif 841 default: 842 break; 843 } 844 break; 845 846 case SIOCGIFADDR: 847 sa = (struct sockaddr *)&ifr->ifr_data; 848 memcpy(sa->sa_data, LLADDR(ifp->if_sadl), ifp->if_addrlen); 849 break; 850 851 #if 0 /* notyet */ 852 case SIOCSIFMTU: 853 #endif 854 855 case SIOCSIFFLAGS: 856 agr_config_promisc(sc); 857 break; 858 859 case SIOCSETAGR: 860 splx(s); 861 p = curproc; /* XXX */ 862 error = kauth_authorize_generic(p->p_cred, KAUTH_GENERIC_ISSUSER, 863 &p->p_acflag); 864 if (!error) { 865 error = agrreq_copyin(ifr->ifr_data, &ar); 866 } 867 if (!error) { 868 error = agr_setconfig(ifp, &ar); 869 } 870 s = splnet(); 871 break; 872 873 case SIOCGETAGR: 874 splx(s); 875 error = agrreq_copyin(ifr->ifr_data, &ar); 876 if (!error) { 877 error = agr_getconfig(ifp, &ar); 878 } 879 if (!error) { 880 error = agrreq_copyout(ifr->ifr_data, &ar); 881 } 882 s = splnet(); 883 break; 884 885 case SIOCADDMULTI: 886 case SIOCDELMULTI: 887 if (sc->sc_nports == 0) { 888 error = EINVAL; 889 break; 890 } 891 error = agr_ioctl_multi(ifp, cmd, ifr); 892 break; 893 894 default: 895 error = EINVAL; 896 break; 897 } 898 899 splx(s); 900 901 agr_ioctl_unlock(sc); 902 903 return error; 904 } 905 906 static int 907 agr_config_promisc(struct agr_softc *sc) 908 { 909 int error; 910 911 agr_port_foreach(sc, agrport_config_promisc_callback, &error); 912 913 return error; 914 } 915 916 static int 917 agrport_config_promisc_callback(struct agr_port *port, void *arg) 918 { 919 struct agr_softc *sc = AGR_SC_FROM_PORT(port); 920 int *errorp = arg; 921 int error; 922 boolean_t promisc; 923 924 promisc = (sc->sc_if.if_flags & IFF_PROMISC) != 0; 925 926 error = agrport_config_promisc(port, promisc); 927 if (error) { 928 *errorp = error; 929 } 930 931 return 0; 932 } 933 934 static int 935 agrport_config_promisc(struct agr_port *port, boolean_t promisc) 936 { 937 int error; 938 939 if (( promisc && (port->port_flags & AGRPORT_PROMISC) != 0) || 940 (!promisc && (port->port_flags & AGRPORT_PROMISC) == 0)) { 941 return 0; 942 } 943 944 error = ifpromisc(port->port_ifp, promisc); 945 if (error == 0) { 946 if (promisc) { 947 port->port_flags |= AGRPORT_PROMISC; 948 } else { 949 port->port_flags &= ~AGRPORT_PROMISC; 950 } 951 } 952 953 return error; 954 } 955