aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke.mehrtens@intel.com>2019-02-15 11:58:54 -0500
committerDavid S. Miller <davem@davemloft.net>2019-02-15 23:23:50 -0500
commit3b89ea9c5902acccdbbdec307c85edd1bf52515e (patch)
treef791e18935f1ab08c3ec4801bee39f56e4a43764
parent197f9ab7f08ce4b9ece662f747c3991b2f0fbb57 (diff)
net: Fix for_each_netdev_feature on Big endian
The features attribute is of type u64 and stored in the native endianes on the system. The for_each_set_bit() macro takes a pointer to a 32 bit array and goes over the bits in this area. On little Endian systems this also works with an u64 as the most significant bit is on the highest address, but on big endian the words are swapped. When we expect bit 15 here we get bit 47 (15 + 32). This patch converts it more or less to its own for_each_set_bit() implementation which works on 64 bit integers directly. This is then completely in host endianness and should work like expected. Fixes: fd867d51f ("net/core: generic support for disabling netdev features down stack") Signed-off-by: Hauke Mehrtens <hauke.mehrtens@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdev_features.h23
-rw-r--r--net/core/dev.c4
2 files changed, 23 insertions, 4 deletions
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 2b2a6dce1630..fce28562bed2 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -11,6 +11,7 @@
11#define _LINUX_NETDEV_FEATURES_H 11#define _LINUX_NETDEV_FEATURES_H
12 12
13#include <linux/types.h> 13#include <linux/types.h>
14#include <asm/byteorder.h>
14 15
15typedef u64 netdev_features_t; 16typedef u64 netdev_features_t;
16 17
@@ -154,8 +155,26 @@ enum {
154#define NETIF_F_HW_TLS_TX __NETIF_F(HW_TLS_TX) 155#define NETIF_F_HW_TLS_TX __NETIF_F(HW_TLS_TX)
155#define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX) 156#define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX)
156 157
157#define for_each_netdev_feature(mask_addr, bit) \ 158/* Finds the next feature with the highest number of the range of start till 0.
158 for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT) 159 */
160static inline int find_next_netdev_feature(u64 feature, unsigned long start)
161{
162 /* like BITMAP_LAST_WORD_MASK() for u64
163 * this sets the most significant 64 - start to 0.
164 */
165 feature &= ~0ULL >> (-start & ((sizeof(feature) * 8) - 1));
166
167 return fls64(feature) - 1;
168}
169
170/* This goes for the MSB to the LSB through the set feature bits,
171 * mask_addr should be a u64 and bit an int
172 */
173#define for_each_netdev_feature(mask_addr, bit) \
174 for ((bit) = find_next_netdev_feature((mask_addr), \
175 NETDEV_FEATURE_COUNT); \
176 (bit) >= 0; \
177 (bit) = find_next_netdev_feature((mask_addr), (bit) - 1))
159 178
160/* Features valid for ethtool to change */ 179/* Features valid for ethtool to change */
161/* = all defined minus driver/device-class-related */ 180/* = all defined minus driver/device-class-related */
diff --git a/net/core/dev.c b/net/core/dev.c
index 8e276e0192a1..5d03889502eb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8152,7 +8152,7 @@ static netdev_features_t netdev_sync_upper_features(struct net_device *lower,
8152 netdev_features_t feature; 8152 netdev_features_t feature;
8153 int feature_bit; 8153 int feature_bit;
8154 8154
8155 for_each_netdev_feature(&upper_disables, feature_bit) { 8155 for_each_netdev_feature(upper_disables, feature_bit) {
8156 feature = __NETIF_F_BIT(feature_bit); 8156 feature = __NETIF_F_BIT(feature_bit);
8157 if (!(upper->wanted_features & feature) 8157 if (!(upper->wanted_features & feature)
8158 && (features & feature)) { 8158 && (features & feature)) {
@@ -8172,7 +8172,7 @@ static void netdev_sync_lower_features(struct net_device *upper,
8172 netdev_features_t feature; 8172 netdev_features_t feature;
8173 int feature_bit; 8173 int feature_bit;
8174 8174
8175 for_each_netdev_feature(&upper_disables, feature_bit) { 8175 for_each_netdev_feature(upper_disables, feature_bit) {
8176 feature = __NETIF_F_BIT(feature_bit); 8176 feature = __NETIF_F_BIT(feature_bit);
8177 if (!(features & feature) && (lower->features & feature)) { 8177 if (!(features & feature) && (lower->features & feature)) {
8178 netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n", 8178 netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n",