aboutsummaryrefslogtreecommitdiff
path: root/sys/net/iflib.c
diff options
context:
space:
mode:
authorStephen Hurd <shurd@FreeBSD.org>2018-09-20 19:35:35 +0000
committerStephen Hurd <shurd@FreeBSD.org>2018-09-20 19:35:35 +0000
commit0c919c23706c7734a9ecb6b0a95717c37c4b3d56 (patch)
treeeefc71b302cf57472126385c02b083fc07315dd2 /sys/net/iflib.c
parent4bf0035fd1434190fc67a647879437a7919a4cf7 (diff)
downloadsrc-0c919c23706c7734a9ecb6b0a95717c37c4b3d56.tar.gz
src-0c919c23706c7734a9ecb6b0a95717c37c4b3d56.zip
Fix capabilities handling for iflib drivers
Various capabilities were not being handled correctly in the SIOCSIFCAP handler. Specifically: IFCAP_RXCSUM and IFCAP_RXCSUM_IPV6 could be set even if not supported It was impossible to disable IFCAP_RXCSUM and/or IFCAP_RXCSUM_IPV6 via ifconfig since it does ioctl() per command-line flag rather than combine them into a single call. IFCAP_VLAN_HWCSUM could not be modified via the ioctl() Setting any combination of the three IFCAP_WOL flags would set only IFCAP_WOL_MCAST | IFCAP_WOL_MAGIC. For example, setting only IFCAP_WOL_UCAST would result in both IFCAP_WOL_MCAST and IFCAP_WOL_MAGIC being enabled, but IFCAP_WOL_UCAST would not be enabled. Because if_vlancap() was called before if_togglecapenable(), vlan flags were sometimes not applied correctly. Interfaces were being unnecessarily stopped and restarted for WoL PR: 231151 Submitted by: Kaho Toshikazu <kaho@elam.kais.kyoto-u.ac.jp> Reported by: Shirkdog <mshirk@daemon-security.com> Reviewed by: galladin Approved by: re (gjb) Sponsored by: Limelight Networks Differential Revision: https://reviews.freebsd.org/D17158
Notes
Notes: svn path=/head/; revision=338838
Diffstat (limited to 'sys/net/iflib.c')
-rw-r--r--sys/net/iflib.c39
1 files changed, 26 insertions, 13 deletions
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 65bf07a0b2c1..d9a6e3b962d7 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -4100,9 +4100,10 @@ iflib_if_qflush(if_t ifp)
}
-#define IFCAP_FLAGS (IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
- IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
- IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | IFCAP_VLAN_HWTSO)
+#define IFCAP_FLAGS (IFCAP_HWCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \
+ IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_HWSTATS | \
+ IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | \
+ IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM)
static int
iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
@@ -4223,39 +4224,51 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data)
}
case SIOCSIFCAP:
{
- int mask, setmask;
+ int mask, setmask, oldmask;
- mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
+ oldmask = if_getcapenable(ifp);
+ mask = ifr->ifr_reqcap ^ oldmask;
+ mask &= ctx->ifc_softc_ctx.isc_capabilities;
setmask = 0;
#ifdef TCP_OFFLOAD
setmask |= mask & (IFCAP_TOE4|IFCAP_TOE6);
#endif
setmask |= (mask & IFCAP_FLAGS);
+ setmask |= (mask & IFCAP_WOL);
+
+ /*
+ * If we're disabling any RX csum, disable all the ones
+ * the driver supports. This assumes all supported are
+ * enabled.
+ *
+ * Otherwise, if they've changed, enable all of them.
+ */
+ if ((setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) <
+ (oldmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)))
+ setmask &= ~(IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
+ else if ((setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) !=
+ (oldmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)))
+ setmask |= (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6));
- if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
- setmask |= (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
- if ((mask & IFCAP_WOL) &&
- (if_getcapabilities(ifp) & IFCAP_WOL) != 0)
- setmask |= (mask & (IFCAP_WOL_MCAST|IFCAP_WOL_MAGIC));
- if_vlancap(ifp);
/*
* want to ensure that traffic has stopped before we change any of the flags
*/
if (setmask) {
CTX_LOCK(ctx);
bits = if_getdrvflags(ifp);
- if (bits & IFF_DRV_RUNNING)
+ if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
iflib_stop(ctx);
STATE_LOCK(ctx);
if_togglecapenable(ifp, setmask);
STATE_UNLOCK(ctx);
- if (bits & IFF_DRV_RUNNING)
+ if (bits & IFF_DRV_RUNNING && setmask & ~IFCAP_WOL)
iflib_init_locked(ctx);
STATE_LOCK(ctx);
if_setdrvflags(ifp, bits);
STATE_UNLOCK(ctx);
CTX_UNLOCK(ctx);
}
+ if_vlancap(ifp);
break;
}
case SIOCGPRIVATE_0: