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