diff options
Diffstat (limited to 'sys/net/if_lagg.c')
-rw-r--r-- | sys/net/if_lagg.c | 72 |
1 files changed, 57 insertions, 15 deletions
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index 2e489eb..22462b3 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -82,7 +82,7 @@ eventhandler_tag lagg_detach_cookie = NULL; static int lagg_clone_create(struct if_clone *, int, caddr_t); static void lagg_clone_destroy(struct ifnet *); static void lagg_lladdr(struct lagg_softc *, uint8_t *); -static int lagg_capabilities(struct lagg_softc *); +static void lagg_capabilities(struct lagg_softc *); static void lagg_port_lladdr(struct lagg_port *, uint8_t *); static void lagg_port_setlladdr(void *, int); static int lagg_port_create(struct lagg_softc *, struct ifnet *); @@ -305,27 +305,32 @@ lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr) (*sc->sc_lladdr)(sc); } -static int +static void lagg_capabilities(struct lagg_softc *sc) { struct lagg_port *lp; - int cap = ~0, priv; + int cap = ~0, ena = ~0; LAGG_WLOCK_ASSERT(sc); - /* Preserve private capabilities */ - priv = sc->sc_capabilities & IFCAP_LAGG_MASK; - /* Get capabilities from the lagg ports */ - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) - cap &= lp->lp_capabilities; - - if (sc->sc_ifflags & IFF_DEBUG) { - printf("%s: capabilities 0x%08x\n", - sc->sc_ifname, cap == ~0 ? priv : (cap | priv)); + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + cap &= lp->lp_ifp->if_capabilities; + ena &= lp->lp_ifp->if_capenable; } + cap = (cap == ~0 ? 0 : cap); + ena = (ena == ~0 ? 0 : ena); + + if (sc->sc_ifp->if_capabilities != cap || + sc->sc_ifp->if_capenable != ena) { + sc->sc_ifp->if_capabilities = cap; + sc->sc_ifp->if_capenable = ena; + getmicrotime(&sc->sc_ifp->if_lastchange); - return (cap == ~0 ? priv : (cap | priv)); + if (sc->sc_ifflags & IFF_DEBUG) + if_printf(sc->sc_ifp, + "capabilities 0x%08x enabled 0x%08x\n", cap, ena); + } } static void @@ -426,6 +431,15 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) if (ifp->if_type != IFT_ETHER) return (EPROTONOSUPPORT); + /* Allow the first Ethernet member to define the MTU */ + if (SLIST_EMPTY(&sc->sc_ports)) + sc->sc_ifp->if_mtu = ifp->if_mtu; + else if (sc->sc_ifp->if_mtu != ifp->if_mtu) { + if_printf(sc->sc_ifp, "invalid MTU for %s\n", + ifp->if_xname); + return (EINVAL); + } + if ((lp = malloc(sizeof(struct lagg_port), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) return (ENOMEM); @@ -478,7 +492,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) sc->sc_count++; /* Update lagg capabilities */ - sc->sc_capabilities = lagg_capabilities(sc); + lagg_capabilities(sc); /* Add multicast addresses and interface flags to this port */ lagg_ether_cmdmulti(lp, 1); @@ -583,7 +597,7 @@ lagg_port_destroy(struct lagg_port *lp, int runpd) free(lp, M_DEVBUF); /* Update lagg capabilities */ - sc->sc_capabilities = lagg_capabilities(sc); + lagg_capabilities(sc); return (0); } @@ -619,6 +633,27 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) lagg_port2req(lp, rp); LAGG_RUNLOCK(sc); break; + + case SIOCSIFCAP: + if (lp->lp_ioctl == NULL) { + error = EINVAL; + break; + } + error = (*lp->lp_ioctl)(ifp, cmd, data); + if (error) + break; + + /* Update lagg interface capabilities */ + LAGG_WLOCK(sc); + lagg_capabilities(sc); + LAGG_WUNLOCK(sc); + break; + + case SIOCSIFMTU: + /* Do not allow the MTU to be changed once joined */ + error = EINVAL; + break; + default: goto fallback; } @@ -934,6 +969,13 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); break; + + case SIOCSIFCAP: + case SIOCSIFMTU: + /* Do not allow the MTU or caps to be directly changed */ + error = EINVAL; + break; + default: error = ether_ioctl(ifp, cmd, data); break; |