lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 10 Aug 2022 11:06:24 +0800
From:   Jian Shen <shenjian15@...wei.com>
To:     <davem@...emloft.net>, <kuba@...nel.org>, <andrew@...n.ch>,
        <ecree.xilinx@...il.com>, <hkallweit1@...il.com>,
        <alexandr.lobakin@...el.com>, <saeed@...nel.org>, <leon@...nel.org>
CC:     <netdev@...r.kernel.org>, <linuxarm@...neuler.org>
Subject: [RFCv7 PATCH net-next 36/36] net: redefine the prototype of netdev_features_t

For the prototype of netdev_features_t is u64, and the number
of netdevice feature bits is 64 now. So there is no space to
introduce new feature bit. Change the prototype of netdev_features_t
from u64 to structure below:
	typedef struct {
		DECLARE_BITMAP(bits, NETDEV_FEATURE_COUNT);
	} netdev_features_t;

Rewrite the netdev_features helpers to adapt with new prototype.

To avoid mistake using NETIF_F_XXX as NETIF_F_XXX_BIT as
input macroes for above helpers, remove all the macroes
of NETIF_F_XXX for single feature bit. Serveal macroes remained
temporarily, by some precompile dependency.

With the prototype is no longer u64, the implementation of print
interface for netdev features(%pNF) is changed to bitmap. So
does the implementation of net/ethtool/.

Signed-off-by: Jian Shen <shenjian15@...wei.com>
---
 drivers/net/ethernet/amazon/ena/ena_netdev.c  |  12 +-
 .../net/ethernet/intel/i40e/i40e_debugfs.c    |  12 +-
 .../ethernet/netronome/nfp/nfp_net_common.c   |   4 +-
 .../net/ethernet/pensando/ionic/ionic_lif.c   |   4 +-
 include/linux/netdev_features.h               | 101 ++----------
 include/linux/netdev_features_helper.h        | 149 +++++++++++-------
 include/linux/netdevice.h                     |   7 +-
 include/linux/skbuff.h                        |   4 +-
 include/net/ip_tunnels.h                      |   2 +-
 lib/vsprintf.c                                |  11 +-
 net/ethtool/features.c                        |  96 ++++-------
 net/ethtool/ioctl.c                           |  46 ++++--
 net/mac80211/main.c                           |   3 +-
 13 files changed, 201 insertions(+), 250 deletions(-)

diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 8386aac68c93..97e74c8aafe2 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -3936,10 +3936,14 @@ static void ena_update_hints(struct ena_adapter *adapter,
 static void ena_update_host_info(struct ena_admin_host_info *host_info,
 				 struct net_device *netdev)
 {
-	host_info->supported_network_features[0] =
-		netdev->features & GENMASK_ULL(31, 0);
-	host_info->supported_network_features[1] =
-		(netdev->features & GENMASK_ULL(63, 32)) >> 32;
+#define DEV_FEATURE_WORDS	DIV_ROUND_UP(NETDEV_FEATURE_COUNT, 32)
+
+	u32 features[DEV_FEATURE_WORDS] = {0};
+
+	bitmap_to_arr32(features, netdev->features.bits, DEV_FEATURE_WORDS);
+
+	host_info->supported_network_features[0] = features[0];
+	host_info->supported_network_features[1] = features[1];
 }
 
 static void ena_timer_service(struct timer_list *t)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index c9dcd6d92c83..046882ab5593 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -131,12 +131,12 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 
 		dev_info(&pf->pdev->dev, "    netdev: name = %s, state = %lu, flags = 0x%08x\n",
 			 nd->name, nd->state, nd->flags);
-		dev_info(&pf->pdev->dev, "        features      = 0x%08lx\n",
-			 (unsigned long int)nd->features);
-		dev_info(&pf->pdev->dev, "        hw_features   = 0x%08lx\n",
-			 (unsigned long int)nd->hw_features);
-		dev_info(&pf->pdev->dev, "        vlan_features = 0x%08lx\n",
-			 (unsigned long int)nd->vlan_features);
+		dev_info(&pf->pdev->dev, "        features      = %pNF\n",
+			 &nd->features);
+		dev_info(&pf->pdev->dev, "        hw_features   = %pNF\n",
+			 &nd->hw_features);
+		dev_info(&pf->pdev->dev, "        vlan_features = %pNF\n",
+			 &nd->vlan_features);
 	}
 	dev_info(&pf->pdev->dev,
 		 "    flags = 0x%08lx, netdev_registered = %i, current_netdev_flags = 0x%04x\n",
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index bcd8513b3b43..9bcd420b0f36 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1736,8 +1736,8 @@ static int nfp_net_set_features(struct net_device *netdev,
 	if (err)
 		return err;
 
-	nn_dbg(nn, "Feature change 0x%llx -> 0x%llx (changed=0x%llx)\n",
-	       netdev->features, features, changed);
+	nn_dbg(nn, "Feature change %pNF -> %pNF (changed=%pNF)\n",
+	       &netdev->features, &features, &changed);
 
 	if (new_ctrl == nn->dp.ctrl)
 		return 0;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 75273f473caa..653c64091121 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1564,8 +1564,8 @@ static int ionic_set_features(struct net_device *netdev,
 	struct ionic_lif *lif = netdev_priv(netdev);
 	int err;
 
-	netdev_dbg(netdev, "%s: lif->features=0x%08llx new_features=0x%08llx\n",
-		   __func__, (u64)lif->netdev->features, (u64)features);
+	netdev_dbg(netdev, "%s: lif->features=%pNF new_features=%pNF\n",
+		   __func__, &lif->netdev->features, &features);
 
 	err = ionic_set_nic_features(lif, features);
 
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index a005c781fabf..8836c957f365 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -10,8 +10,6 @@
 #include <linux/cache.h>
 #include <asm/byteorder.h>
 
-typedef u64 netdev_features_t;
-
 struct netdev_feature_set {
 	unsigned int cnt;
 	unsigned short feature_bits[];
@@ -113,6 +111,10 @@ enum {
 	/**/NETDEV_FEATURE_COUNT
 };
 
+typedef struct {
+	DECLARE_BITMAP(bits, NETDEV_FEATURE_COUNT);
+} netdev_features_t;
+
 extern netdev_features_t netdev_ethtool_features __ro_after_init;
 extern netdev_features_t netdev_never_change_features __ro_after_init;
 extern netdev_features_t netdev_gso_features_mask __ro_after_init;
@@ -171,94 +173,16 @@ extern const struct netdev_feature_set netif_f_xfrm_feature_set;
 extern const struct netdev_feature_set netif_f_tls_feature_set;
 extern const struct netdev_feature_set netvsc_supported_hw_feature_set;
 
-/* copy'n'paste compression ;) */
-#define __NETIF_F_BIT(bit)	((netdev_features_t)1 << (bit))
-#define __NETIF_F(name)		__NETIF_F_BIT(NETIF_F_##name##_BIT)
-
-#define NETIF_F_FCOE_CRC	__NETIF_F(FCOE_CRC)
-#define NETIF_F_FCOE_MTU	__NETIF_F(FCOE_MTU)
-#define NETIF_F_FRAGLIST	__NETIF_F(FRAGLIST)
-#define NETIF_F_FSO		__NETIF_F(FSO)
-#define NETIF_F_GRO		__NETIF_F(GRO)
-#define NETIF_F_GRO_HW		__NETIF_F(GRO_HW)
-#define NETIF_F_GSO		__NETIF_F(GSO)
-#define NETIF_F_GSO_ROBUST	__NETIF_F(GSO_ROBUST)
-#define NETIF_F_HIGHDMA		__NETIF_F(HIGHDMA)
-#define NETIF_F_HW_CSUM		__NETIF_F(HW_CSUM)
-#define NETIF_F_HW_VLAN_CTAG_FILTER __NETIF_F(HW_VLAN_CTAG_FILTER)
-#define NETIF_F_HW_VLAN_CTAG_RX	__NETIF_F(HW_VLAN_CTAG_RX)
-#define NETIF_F_HW_VLAN_CTAG_TX	__NETIF_F(HW_VLAN_CTAG_TX)
-#define NETIF_F_IP_CSUM		__NETIF_F(IP_CSUM)
-#define NETIF_F_IPV6_CSUM	__NETIF_F(IPV6_CSUM)
-#define NETIF_F_LLTX		__NETIF_F(LLTX)
-#define NETIF_F_LOOPBACK	__NETIF_F(LOOPBACK)
-#define NETIF_F_LRO		__NETIF_F(LRO)
-#define NETIF_F_NETNS_LOCAL	__NETIF_F(NETNS_LOCAL)
-#define NETIF_F_NOCACHE_COPY	__NETIF_F(NOCACHE_COPY)
-#define NETIF_F_NTUPLE		__NETIF_F(NTUPLE)
-#define NETIF_F_RXCSUM		__NETIF_F(RXCSUM)
-#define NETIF_F_RXHASH		__NETIF_F(RXHASH)
-#define NETIF_F_SCTP_CRC	__NETIF_F(SCTP_CRC)
-#define NETIF_F_SG		__NETIF_F(SG)
-#define NETIF_F_TSO6		__NETIF_F(TSO6)
-#define NETIF_F_TSO_ECN		__NETIF_F(TSO_ECN)
-#define NETIF_F_TSO		__NETIF_F(TSO)
-#define NETIF_F_VLAN_CHALLENGED	__NETIF_F(VLAN_CHALLENGED)
-#define NETIF_F_RXFCS		__NETIF_F(RXFCS)
-#define NETIF_F_RXALL		__NETIF_F(RXALL)
-#define NETIF_F_GSO_GRE		__NETIF_F(GSO_GRE)
-#define NETIF_F_GSO_GRE_CSUM	__NETIF_F(GSO_GRE_CSUM)
-#define NETIF_F_GSO_IPXIP4	__NETIF_F(GSO_IPXIP4)
-#define NETIF_F_GSO_IPXIP6	__NETIF_F(GSO_IPXIP6)
-#define NETIF_F_GSO_UDP_TUNNEL	__NETIF_F(GSO_UDP_TUNNEL)
-#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM)
-#define NETIF_F_TSO_MANGLEID	__NETIF_F(TSO_MANGLEID)
-#define NETIF_F_GSO_PARTIAL	 __NETIF_F(GSO_PARTIAL)
-#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM)
-#define NETIF_F_GSO_SCTP	__NETIF_F(GSO_SCTP)
-#define NETIF_F_GSO_ESP		__NETIF_F(GSO_ESP)
-#define NETIF_F_GSO_UDP		__NETIF_F(GSO_UDP)
-#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
-#define NETIF_F_HW_VLAN_STAG_RX	__NETIF_F(HW_VLAN_STAG_RX)
-#define NETIF_F_HW_VLAN_STAG_TX	__NETIF_F(HW_VLAN_STAG_TX)
-#define NETIF_F_HW_L2FW_DOFFLOAD	__NETIF_F(HW_L2FW_DOFFLOAD)
-#define NETIF_F_HW_TC		__NETIF_F(HW_TC)
-#define NETIF_F_HW_ESP		__NETIF_F(HW_ESP)
-#define NETIF_F_HW_ESP_TX_CSUM	__NETIF_F(HW_ESP_TX_CSUM)
-#define	NETIF_F_RX_UDP_TUNNEL_PORT  __NETIF_F(RX_UDP_TUNNEL_PORT)
-#define NETIF_F_HW_TLS_RECORD	__NETIF_F(HW_TLS_RECORD)
-#define NETIF_F_GSO_UDP_L4	__NETIF_F(GSO_UDP_L4)
-#define NETIF_F_HW_TLS_TX	__NETIF_F(HW_TLS_TX)
-#define NETIF_F_HW_TLS_RX	__NETIF_F(HW_TLS_RX)
-#define NETIF_F_GRO_FRAGLIST	__NETIF_F(GRO_FRAGLIST)
-#define NETIF_F_GSO_FRAGLIST	__NETIF_F(GSO_FRAGLIST)
-#define NETIF_F_HW_MACSEC	__NETIF_F(HW_MACSEC)
-#define NETIF_F_GRO_UDP_FWD	__NETIF_F(GRO_UDP_FWD)
-#define NETIF_F_HW_HSR_TAG_INS	__NETIF_F(HW_HSR_TAG_INS)
-#define NETIF_F_HW_HSR_TAG_RM	__NETIF_F(HW_HSR_TAG_RM)
-#define NETIF_F_HW_HSR_FWD	__NETIF_F(HW_HSR_FWD)
-#define NETIF_F_HW_HSR_DUP	__NETIF_F(HW_HSR_DUP)
-
-/* Finds the next feature with the highest number of the range of start-1 till 0.
- */
-static inline int find_next_netdev_feature(u64 feature, unsigned long start)
-{
-	/* like BITMAP_LAST_WORD_MASK() for u64
-	 * this sets the most significant 64 - start to 0.
-	 */
-	feature &= ~0ULL >> (-start & ((sizeof(feature) * 8) - 1));
-
-	return fls64(feature) - 1;
-}
+#define NETIF_F_HW_VLAN_CTAG_TX
+#define NETIF_F_IPV6_CSUM
+#define NETIF_F_TSO
+#define NETIF_F_GSO
 
 /* This goes for the MSB to the LSB through the set feature bits,
  * mask_addr should be a u64 and bit an int
  */
 #define for_each_netdev_feature(mask_addr, bit)				\
-	for ((bit) = find_next_netdev_feature((mask_addr),		\
-					      NETDEV_FEATURE_COUNT);	\
-	     (bit) >= 0;						\
-	     (bit) = find_next_netdev_feature((mask_addr), (bit)))
+	for_each_set_bit(bit, (unsigned long *)(mask_addr.bits), NETDEV_FEATURE_COUNT)
 
 /* Features valid for ethtool to change */
 /* = all defined minus driver/device-class-related */
@@ -311,4 +235,11 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start)
 
 #define NETIF_F_GSO_ENCAP_ALL	netdev_gso_encap_all_features
 
+#define GSO_ENCAP_FEATURES	(((u64)1 << NETIF_F_GSO_GRE_BIT) |		\
+				 ((u64)1 << NETIF_F_GSO_GRE_CSUM_BIT) |		\
+				 ((u64)1 << NETIF_F_GSO_IPXIP4_BIT) |		\
+				 ((u64)1 << NETIF_F_GSO_IPXIP6_BIT) |		\
+				 (((u64)1 << NETIF_F_GSO_UDP_TUNNEL_BIT) |	\
+				  ((u64)1 << NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT)))
+
 #endif	/* _LINUX_NETDEV_FEATURES_H */
diff --git a/include/linux/netdev_features_helper.h b/include/linux/netdev_features_helper.h
index 476d36352160..479d120bd8bd 100644
--- a/include/linux/netdev_features_helper.h
+++ b/include/linux/netdev_features_helper.h
@@ -9,7 +9,7 @@
 
 static inline void netdev_features_zero(netdev_features_t *dst)
 {
-	*dst = 0;
+	bitmap_zero(dst->bits, NETDEV_FEATURE_COUNT);
 }
 
 /* active_feature prefer to netdev->features */
@@ -36,12 +36,12 @@ static inline void netdev_features_zero(netdev_features_t *dst)
 
 static inline void netdev_features_fill(netdev_features_t *dst)
 {
-	*dst = ~0ULL;
+	bitmap_fill(dst->bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline bool netdev_features_empty(const netdev_features_t src)
 {
-	return src == 0;
+	return bitmap_empty(src.bits, NETDEV_FEATURE_COUNT);
 }
 
 #define netdev_active_features_empty(ndev) \
@@ -69,7 +69,7 @@ static inline bool netdev_features_empty(const netdev_features_t src)
 static inline bool netdev_features_equal(const netdev_features_t src1,
 					 const netdev_features_t src2)
 {
-	return src1 == src2;
+	return bitmap_equal(src1.bits, src2.bits, NETDEV_FEATURE_COUNT);
 }
 
 #define netdev_active_features_equal(ndev, __features) \
@@ -97,7 +97,10 @@ static inline bool netdev_features_equal(const netdev_features_t src1,
 static inline netdev_features_t
 netdev_features_and(const netdev_features_t a, const netdev_features_t b)
 {
-	return a & b;
+	netdev_features_t dst;
+
+	bitmap_and(dst.bits, a.bits, b.bits, NETDEV_FEATURE_COUNT);
+	return dst;
 }
 
 #define netdev_active_features_and(ndev, __features) \
@@ -126,63 +129,74 @@ static inline void
 netdev_features_mask(netdev_features_t *dst,
 			   const netdev_features_t features)
 {
-	*dst = netdev_features_and(*dst, features);
+	bitmap_and(dst->bits, dst->bits, features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_active_features_mask(struct net_device *ndev,
 			    const netdev_features_t features)
 {
-	ndev->features = netdev_active_features_and(ndev, features);
+	bitmap_and(ndev->features.bits, ndev->features.bits, features.bits,
+		   NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_features_mask(struct net_device *ndev,
 			const netdev_features_t features)
 {
-	ndev->hw_features = netdev_hw_features_and(ndev, features);
+	bitmap_and(ndev->hw_features.bits, ndev->hw_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_wanted_features_mask(struct net_device *ndev,
 			    const netdev_features_t features)
 {
-	ndev->wanted_features = netdev_wanted_features_and(ndev, features);
+	bitmap_and(ndev->wanted_features.bits, ndev->wanted_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_vlan_features_mask(struct net_device *ndev,
 			  const netdev_features_t features)
 {
-	ndev->vlan_features = netdev_vlan_features_and(ndev, features);
+	bitmap_and(ndev->vlan_features.bits, ndev->vlan_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_enc_features_mask(struct net_device *ndev,
 			    const netdev_features_t features)
 {
-	ndev->hw_enc_features = netdev_hw_enc_features_and(ndev, features);
+	bitmap_and(ndev->hw_enc_features.bits, ndev->hw_enc_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_mpls_features_mask(struct net_device *ndev,
 			  const netdev_features_t features)
 {
-	ndev->mpls_features = netdev_mpls_features_and(ndev, features);
+	bitmap_and(ndev->mpls_features.bits, ndev->mpls_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_gso_partial_features_mask(struct net_device *ndev,
 				 const netdev_features_t features)
 {
-	ndev->gso_partial_features = netdev_mpls_features_and(ndev, features);
+	bitmap_and(ndev->gso_partial_features.bits,
+		   ndev->gso_partial_features.bits, features.bits,
+		   NETDEV_FEATURE_COUNT);
 }
 
 /* helpers for netdev features '|' operation */
 static inline netdev_features_t
 netdev_features_or(const netdev_features_t a, const netdev_features_t b)
 {
-	return a | b;
+	netdev_features_t dst;
+
+	bitmap_or(dst.bits, a.bits, b.bits, NETDEV_FEATURE_COUNT);
+	return dst;
 }
 
 #define netdev_active_features_or(ndev, __features) \
@@ -210,64 +224,69 @@ netdev_features_or(const netdev_features_t a, const netdev_features_t b)
 static inline void
 netdev_features_set(netdev_features_t *dst, const netdev_features_t features)
 {
-	*dst = netdev_features_or(*dst, features);
+	bitmap_or(dst->bits, dst->bits, features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_active_features_set(struct net_device *ndev,
 			   const netdev_features_t features)
 {
-	ndev->features = netdev_active_features_or(ndev, features);
+	bitmap_or(ndev->features.bits, ndev->features.bits, features.bits,
+		  NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_features_set(struct net_device *ndev,
 		       const netdev_features_t features)
 {
-	ndev->hw_features = netdev_hw_features_or(ndev, features);
+	bitmap_or(ndev->hw_features.bits, ndev->hw_features.bits, features.bits,
+		  NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_wanted_features_set(struct net_device *ndev,
 			   const netdev_features_t features)
 {
-	ndev->wanted_features = netdev_wanted_features_or(ndev, features);
+	bitmap_or(ndev->wanted_features.bits, ndev->wanted_features.bits,
+		  features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_vlan_features_set(struct net_device *ndev,
 			 const netdev_features_t features)
 {
-	ndev->vlan_features = netdev_vlan_features_or(ndev, features);
+	bitmap_or(ndev->vlan_features.bits, ndev->vlan_features.bits,
+		  features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_enc_features_set(struct net_device *ndev,
 			   const netdev_features_t features)
 {
-	ndev->hw_enc_features = netdev_hw_enc_features_or(ndev, features);
+	bitmap_or(ndev->hw_enc_features.bits, ndev->hw_enc_features.bits,
+		  features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_mpls_features_set(struct net_device *ndev,
 			 const netdev_features_t features)
 {
-	ndev->mpls_features = netdev_mpls_features_or(ndev, features);
+	bitmap_or(ndev->mpls_features.bits, ndev->mpls_features.bits,
+		  features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_gso_partial_features_set(struct net_device *ndev,
 				const netdev_features_t features)
 {
-	ndev->gso_partial_features = netdev_mpls_features_or(ndev, features);
+	bitmap_or(ndev->gso_partial_features.bits,
+		  ndev->gso_partial_features.bits, features.bits,
+		  NETDEV_FEATURE_COUNT);
 }
 
 static inline void netdev_feature_change(int nr, netdev_features_t *src)
 {
-	if (*src & __NETIF_F_BIT(nr))
-		*src &= ~(__NETIF_F_BIT(nr));
-	else
-		*src |= __NETIF_F_BIT(nr);
+	__change_bit(nr, src->bits);
 }
 
 #define netdev_active_feature_change(ndev, nr) \
@@ -295,7 +314,10 @@ static inline void netdev_feature_change(int nr, netdev_features_t *src)
 static inline netdev_features_t
 netdev_features_xor(const netdev_features_t a, const netdev_features_t b)
 {
-	return a ^ b;
+	netdev_features_t dst;
+
+	bitmap_xor(dst.bits, a.bits, b.bits, NETDEV_FEATURE_COUNT);
+	return dst;
 }
 
 #define netdev_active_features_xor(ndev, __features) \
@@ -323,64 +345,74 @@ netdev_features_xor(const netdev_features_t a, const netdev_features_t b)
 static inline void
 netdev_features_toggle(netdev_features_t *dst, const netdev_features_t features)
 {
-	*dst = netdev_features_xor(*dst, features);
+	bitmap_xor(dst->bits, dst->bits, features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_active_features_toggle(struct net_device *ndev,
 			      const netdev_features_t features)
 {
-	ndev->features = netdev_active_features_xor(ndev, features);
+	bitmap_xor(ndev->features.bits, ndev->features.bits, features.bits,
+		   NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_features_toggle(struct net_device *ndev,
 			      const netdev_features_t features)
 {
-	ndev->hw_features = netdev_hw_features_xor(ndev, features);
+	bitmap_xor(ndev->hw_features.bits, ndev->hw_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_wanted_features_toggle(struct net_device *ndev,
 				  const netdev_features_t features)
 {
-	ndev->wanted_features = netdev_wanted_features_xor(ndev, features);
+	bitmap_xor(ndev->wanted_features.bits, ndev->wanted_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_vlan_features_toggle(struct net_device *ndev,
 				const netdev_features_t features)
 {
-	ndev->vlan_features = netdev_vlan_features_xor(ndev, features);
+	bitmap_xor(ndev->vlan_features.bits, ndev->vlan_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_enc_features_toggle(struct net_device *ndev,
 			      const netdev_features_t features)
 {
-	ndev->hw_enc_features = netdev_hw_enc_features_xor(ndev, features);
+	bitmap_xor(ndev->hw_enc_features.bits, ndev->hw_enc_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_mpls_features_toggle(struct net_device *ndev,
 			    const netdev_features_t features)
 {
-	ndev->mpls_features = netdev_mpls_features_xor(ndev, features);
+	bitmap_xor(ndev->mpls_features.bits, ndev->mpls_features.bits,
+		   features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_gso_partial_features_toggle(struct net_device *ndev,
 				   const netdev_features_t features)
 {
-	ndev->gso_partial_features =
-			netdev_gso_partial_features_xor(ndev, features);
+	bitmap_xor(ndev->gso_partial_features.bits,
+		   ndev->gso_partial_features.bits, features.bits,
+		   NETDEV_FEATURE_COUNT);
 }
 
 /* helpers for netdev features '& ~' operation */
 static inline netdev_features_t
 netdev_features_andnot(const netdev_features_t a, const netdev_features_t b)
 {
-	return a & ~b;
+	netdev_features_t dst;
+
+	bitmap_andnot(dst.bits, a.bits, b.bits, NETDEV_FEATURE_COUNT);
+	return dst;
 }
 
 #define netdev_active_features_andnot(ndev, __features) \
@@ -428,63 +460,71 @@ netdev_features_andnot(const netdev_features_t a, const netdev_features_t b)
 static inline void
 netdev_features_clear(netdev_features_t *dst, const netdev_features_t features)
 {
-	*dst = netdev_features_andnot(*dst, features);
+	bitmap_andnot(dst->bits, dst->bits, features.bits,
+		      NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_active_features_clear(struct net_device *ndev,
 			     const netdev_features_t features)
 {
-	ndev->features = netdev_active_features_andnot(ndev, features);
+	bitmap_andnot(ndev->features.bits, ndev->features.bits, features.bits,
+		      NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_features_clear(struct net_device *ndev,
 			 const netdev_features_t features)
 {
-	ndev->hw_features = netdev_hw_features_andnot(ndev, features);
+	bitmap_andnot(ndev->features.bits, ndev->features.bits, features.bits,
+		      NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_wanted_features_clear(struct net_device *ndev,
 			     const netdev_features_t features)
 {
-	ndev->wanted_features = netdev_wanted_features_andnot(ndev, features);
+	bitmap_andnot(ndev->wanted_features.bits, ndev->wanted_features.bits,
+		      features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_vlan_features_clear(struct net_device *ndev,
 			   const netdev_features_t features)
 {
-	ndev->vlan_features = netdev_vlan_features_andnot(ndev, features);
+	bitmap_andnot(ndev->vlan_features.bits, ndev->vlan_features.bits,
+		      features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_hw_enc_features_clear(struct net_device *ndev,
 			     const netdev_features_t features)
 {
-	ndev->hw_enc_features = netdev_hw_enc_features_andnot(ndev, features);
+	bitmap_andnot(ndev->hw_enc_features.bits, ndev->hw_enc_features.bits,
+		      features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_mpls_features_clear(struct net_device *ndev,
 			   const netdev_features_t features)
 {
-	ndev->mpls_features = netdev_mpls_features_andnot(ndev, features);
+	bitmap_andnot(ndev->mpls_features.bits, ndev->mpls_features.bits,
+		      features.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline void
 netdev_gso_partial_features_clear(struct net_device *ndev,
 				  const netdev_features_t features)
 {
-	ndev->gso_partial_features =
-		netdev_gso_partial_features_andnot(ndev, features);
+	bitmap_andnot(ndev->gso_partial_features.bits,
+		      ndev->gso_partial_features.bits, features.bits,
+		      NETDEV_FEATURE_COUNT);
 }
 
 /* helpers for netdev features 'set bit' operation */
 static inline void netdev_feature_add(int nr, netdev_features_t *src)
 {
-	*src |= __NETIF_F_BIT(nr);
+	__set_bit(nr, src->bits);
 }
 
 #define netdev_active_feature_add(ndev, nr) \
@@ -543,7 +583,7 @@ netdev_features_set_array(const struct netdev_feature_set *set,
 /* helpers for netdev features 'clear bit' operation */
 static inline void netdev_feature_del(int nr, netdev_features_t *src)
 {
-	*src &= ~__NETIF_F_BIT(nr);
+	__clear_bit(nr, src->bits);
 }
 
 #define netdev_active_feature_del(ndev, nr) \
@@ -602,7 +642,7 @@ netdev_features_clear_array(const struct netdev_feature_set *set,
 static inline bool netdev_features_intersects(const netdev_features_t src1,
 					      const netdev_features_t src2)
 {
-	return (src1 & src2) > 0;
+	return bitmap_intersects(src1.bits, src2.bits, NETDEV_FEATURE_COUNT);
 }
 
 #define netdev_active_features_intersects(ndev, __features) \
@@ -669,20 +709,11 @@ static inline void netdev_gso_partial_features_copy(struct net_device *ndev,
 	ndev->gso_partial_features = src;
 }
 
-/* helpers for netdev features 'get' operation */
-#define netdev_active_features(ndev)	((ndev)->features)
-#define netdev_hw_features(ndev)	((ndev)->hw_features)
-#define netdev_wanted_features(ndev)	((ndev)->wanted_features)
-#define netdev_vlan_features(ndev)	((ndev)->vlan_features)
-#define netdev_hw_enc_features(ndev)	((ndev)->hw_enc_features)
-#define netdev_mpls_features(ndev)	((ndev)->mpls_features)
-#define netdev_gso_partial_features(ndev)	((ndev)->gso_partial_features)
-
 /* helpers for netdev features 'subset' */
 static inline bool netdev_features_subset(const netdev_features_t src1,
 					  const netdev_features_t src2)
 {
-	return (src1 & src2) == src2;
+	return bitmap_subset(src1.bits, src2.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline netdev_features_t netdev_intersect_features(netdev_features_t f1,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4741f81fa968..11b31e512d68 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2338,7 +2338,7 @@ struct net_device {
 /* helpers for netdev features 'test bit' operation */
 static inline bool netdev_feature_test(int nr, const netdev_features_t src)
 {
-	return (src & __NETIF_F_BIT(nr)) > 0;
+	return test_bit(nr, src.bits);
 }
 
 #define netdev_active_feature_test(ndev, nr) \
@@ -4888,7 +4888,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
 {
 #define GSO_INDEX(x)	((1ULL << (x)) >> NETIF_F_GSO_SHIFT)
 
-	netdev_features_t feature = (netdev_features_t)gso_type << NETIF_F_GSO_SHIFT;
+	netdev_features_t feature = netdev_empty_features;
 
 	/* check flags correspondence */
 	BUILD_BUG_ON(SKB_GSO_TCPV4   != GSO_INDEX(NETIF_F_TSO_BIT));
@@ -4911,7 +4911,8 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
 	BUILD_BUG_ON(SKB_GSO_UDP_L4 != GSO_INDEX(NETIF_F_GSO_UDP_L4_BIT));
 	BUILD_BUG_ON(SKB_GSO_FRAGLIST != GSO_INDEX(NETIF_F_GSO_FRAGLIST_BIT));
 
-	return (features & feature) == feature;
+	bitmap_from_u64(feature.bits, (u64)gso_type << NETIF_F_GSO_SHIFT);
+	return bitmap_subset(features.bits, feature.bits, NETDEV_FEATURE_COUNT);
 }
 
 static inline bool skb_gso_ok(struct sk_buff *skb, netdev_features_t features)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index ca8afa382bf2..2f4e6cd05754 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3989,8 +3989,8 @@ static inline bool skb_needs_linearize(struct sk_buff *skb,
 				       netdev_features_t features)
 {
 	return skb_is_nonlinear(skb) &&
-	       ((skb_has_frag_list(skb) && !(features & NETIF_F_FRAGLIST)) ||
-		(skb_shinfo(skb)->nr_frags && !(features & NETIF_F_SG)));
+	       ((skb_has_frag_list(skb) && !test_bit(NETIF_F_FRAGLIST_BIT, features.bits)) ||
+		(skb_shinfo(skb)->nr_frags && !test_bit(NETIF_F_SG_BIT, features.bits)));
 }
 
 static inline void skb_copy_from_linear_data(const struct sk_buff *skb,
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 63fac94f9ace..4cf7e596eb53 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -447,7 +447,7 @@ static inline int iptunnel_pull_offloads(struct sk_buff *skb)
 		err = skb_unclone(skb, GFP_ATOMIC);
 		if (unlikely(err))
 			return err;
-		skb_shinfo(skb)->gso_type &= ~(NETIF_F_GSO_ENCAP_ALL >>
+		skb_shinfo(skb)->gso_type &= ~(GSO_ENCAP_FEATURES >>
 					       NETIF_F_GSO_SHIFT);
 	}
 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 3c1853a9d1c0..d44e47681563 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1729,25 +1729,24 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
 }
 
 static noinline_for_stack
-char *netdev_bits(char *buf, char *end, const void *addr,
+char *netdev_bits(char *buf, char *end, void *addr,
 		  struct printf_spec spec,  const char *fmt)
 {
-	unsigned long long num;
-	int size;
+	netdev_features_t *features;
 
 	if (check_pointer(&buf, end, addr, spec))
 		return buf;
 
 	switch (fmt[1]) {
 	case 'F':
-		num = *(const netdev_features_t *)addr;
-		size = sizeof(netdev_features_t);
+		features = (netdev_features_t *)addr;
+		spec.field_width = NETDEV_FEATURE_COUNT;
 		break;
 	default:
 		return error_string(buf, end, "(%pN?)", spec);
 	}
 
-	return special_hex_number(buf, end, num, size);
+	return bitmap_string(buf, end, features->bits, spec, fmt);
 }
 
 static noinline_for_stack
diff --git a/net/ethtool/features.c b/net/ethtool/features.c
index 38efdab960ba..7650a63cb234 100644
--- a/net/ethtool/features.c
+++ b/net/ethtool/features.c
@@ -27,10 +27,7 @@ const struct nla_policy ethnl_features_get_policy[] = {
 
 static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t src)
 {
-	unsigned int i;
-
-	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++)
-		dest[i] = src >> (32 * i);
+	bitmap_to_arr32(dest, src.bits, NETDEV_FEATURE_COUNT);
 }
 
 static int features_prepare_data(const struct ethnl_req_info *req_base,
@@ -45,7 +42,7 @@ static int features_prepare_data(const struct ethnl_req_info *req_base,
 	ethnl_features_to_bitmap32(data->wanted, dev->wanted_features);
 	ethnl_features_to_bitmap32(data->active, dev->features);
 	ethnl_features_to_bitmap32(data->nochange, NETIF_F_NEVER_CHANGE);
-	all_features = GENMASK_ULL(NETDEV_FEATURE_COUNT - 1, 0);
+	netdev_features_fill(&all_features);
 	ethnl_features_to_bitmap32(data->all, all_features);
 
 	return 0;
@@ -131,28 +128,6 @@ const struct nla_policy ethnl_features_set_policy[] = {
 	[ETHTOOL_A_FEATURES_WANTED]	= { .type = NLA_NESTED },
 };
 
-static void ethnl_features_to_bitmap(unsigned long *dest, netdev_features_t val)
-{
-	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
-	unsigned int i;
-
-	for (i = 0; i < words; i++)
-		dest[i] = (unsigned long)(val >> (i * BITS_PER_LONG));
-}
-
-static netdev_features_t ethnl_bitmap_to_features(unsigned long *src)
-{
-	const unsigned int nft_bits = sizeof(netdev_features_t) * BITS_PER_BYTE;
-	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
-	netdev_features_t ret = netdev_empty_features;
-	unsigned int i;
-
-	for (i = 0; i < words; i++)
-		ret |= (netdev_features_t)(src[i]) << (i * BITS_PER_LONG);
-	ret &= ~(netdev_features_t)0 >> (nft_bits - NETDEV_FEATURE_COUNT);
-	return ret;
-}
-
 static int features_send_reply(struct net_device *dev, struct genl_info *info,
 			       const unsigned long *wanted,
 			       const unsigned long *wanted_mask,
@@ -209,16 +184,16 @@ static int features_send_reply(struct net_device *dev, struct genl_info *info,
 
 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
 {
-	DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(old_wanted, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT);
-	DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT);
 	struct ethnl_req_info req_info = {};
 	struct nlattr **tb = info->attrs;
+	netdev_features_t wanted_diff_mask;
+	netdev_features_t active_diff_mask;
+	netdev_features_t old_active;
+	netdev_features_t old_wanted;
+	netdev_features_t new_active;
+	netdev_features_t new_wanted;
+	netdev_features_t req_wanted;
+	netdev_features_t req_mask;
 	struct net_device *dev;
 	netdev_features_t tmp;
 	bool mod;
@@ -235,50 +210,47 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
 	dev = req_info.dev;
 
 	rtnl_lock();
-	ethnl_features_to_bitmap(old_active, dev->features);
-	ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
-	ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
+	old_active = dev->features;
+	old_wanted = dev->wanted_features;
+	ret = ethnl_parse_bitset(req_wanted.bits, req_mask.bits,
+				 NETDEV_FEATURE_COUNT,
 				 tb[ETHTOOL_A_FEATURES_WANTED],
 				 netdev_features_strings, info->extack);
 	if (ret < 0)
 		goto out_rtnl;
-	if (ethnl_bitmap_to_features(req_mask) & ~NETIF_F_ETHTOOL_BITS) {
+
+	if (!netdev_features_subset(req_mask, NETIF_F_ETHTOOL_BITS)) {
 		GENL_SET_ERR_MSG(info, "attempt to change non-ethtool features");
 		ret = -EINVAL;
 		goto out_rtnl;
 	}
 
 	/* set req_wanted bits not in req_mask from old_wanted */
-	bitmap_and(req_wanted, req_wanted, req_mask, NETDEV_FEATURE_COUNT);
-	bitmap_andnot(new_wanted, old_wanted, req_mask, NETDEV_FEATURE_COUNT);
-	bitmap_or(req_wanted, new_wanted, req_wanted, NETDEV_FEATURE_COUNT);
-	if (!bitmap_equal(req_wanted, old_wanted, NETDEV_FEATURE_COUNT)) {
-		dev->wanted_features &= ~dev->hw_features;
-		tmp = ethnl_bitmap_to_features(req_wanted) & dev->hw_features;
-		dev->wanted_features |= tmp;
+	netdev_features_mask(&req_wanted, req_mask);
+	new_wanted = netdev_features_andnot(old_wanted, req_mask);
+	netdev_features_set(&req_wanted, new_wanted);
+	if (!netdev_features_equal(req_wanted, old_wanted)) {
+		netdev_wanted_features_clear(dev, dev->hw_features);
+		tmp = netdev_hw_features_and(dev, req_wanted);
+		netdev_wanted_features_set(dev, tmp);
 		__netdev_update_features(dev);
 	}
-	ethnl_features_to_bitmap(new_active, dev->features);
-	mod = !bitmap_equal(old_active, new_active, NETDEV_FEATURE_COUNT);
+	new_active = dev->features;
+	mod = !netdev_features_equal(old_active, new_active);
 
 	ret = 0;
 	if (!(req_info.flags & ETHTOOL_FLAG_OMIT_REPLY)) {
 		bool compact = req_info.flags & ETHTOOL_FLAG_COMPACT_BITSETS;
 
-		bitmap_xor(wanted_diff_mask, req_wanted, new_active,
-			   NETDEV_FEATURE_COUNT);
-		bitmap_xor(active_diff_mask, old_active, new_active,
-			   NETDEV_FEATURE_COUNT);
-		bitmap_and(wanted_diff_mask, wanted_diff_mask, req_mask,
-			   NETDEV_FEATURE_COUNT);
-		bitmap_and(req_wanted, req_wanted, wanted_diff_mask,
-			   NETDEV_FEATURE_COUNT);
-		bitmap_and(new_active, new_active, active_diff_mask,
-			   NETDEV_FEATURE_COUNT);
-
-		ret = features_send_reply(dev, info, req_wanted,
-					  wanted_diff_mask, new_active,
-					  active_diff_mask, compact);
+		wanted_diff_mask = netdev_features_xor(req_wanted, new_active);
+		active_diff_mask = netdev_features_xor(old_active, new_active);
+		netdev_features_mask(&wanted_diff_mask, req_mask);
+		netdev_features_mask(&req_wanted, wanted_diff_mask);
+		netdev_features_mask(&new_active, active_diff_mask);
+
+		ret = features_send_reply(dev, info, req_wanted.bits,
+					  wanted_diff_mask.bits, new_active.bits,
+					  active_diff_mask.bits, compact);
 	}
 	if (mod)
 		netdev_features_change(dev);
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index e4718b24dd38..97df79c62420 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -89,6 +89,10 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 		.size = ETHTOOL_DEV_FEATURE_WORDS,
 	};
 	struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
+	u32 never_changed_arr[ETHTOOL_DEV_FEATURE_WORDS];
+	u32 wanted_arr[ETHTOOL_DEV_FEATURE_WORDS];
+	u32 active_arr[ETHTOOL_DEV_FEATURE_WORDS];
+	u32 hw_arr[ETHTOOL_DEV_FEATURE_WORDS];
 	u32 __user *sizeaddr;
 	u32 copy_size;
 	int i;
@@ -96,12 +100,16 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 	/* in case feature bits run out again */
 	BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
 
+	bitmap_to_arr32(hw_arr, dev->hw_features.bits, NETDEV_FEATURE_COUNT);
+	bitmap_to_arr32(wanted_arr, dev->wanted_features.bits, NETDEV_FEATURE_COUNT);
+	bitmap_to_arr32(active_arr, dev->features.bits, NETDEV_FEATURE_COUNT);
+	bitmap_to_arr32(never_changed_arr, netdev_never_change_features.bits,
+			NETDEV_FEATURE_COUNT);
 	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
-		features[i].available = (u32)(dev->hw_features >> (32 * i));
-		features[i].requested = (u32)(dev->wanted_features >> (32 * i));
-		features[i].active = (u32)(dev->features >> (32 * i));
-		features[i].never_changed =
-			(u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
+		features[i].available = hw_arr[i];
+		features[i].requested = wanted_arr[i];
+		features[i].active = active_arr[i];
+		features[i].never_changed = never_changed_arr[i];
 	}
 
 	sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
@@ -125,6 +133,8 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_sfeatures cmd;
 	struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
+	u32 wanted_arr[ETHTOOL_DEV_FEATURE_WORDS];
+	u32 valid_arr[ETHTOOL_DEV_FEATURE_WORDS];
 	netdev_features_t wanted = netdev_empty_features;
 	netdev_features_t valid = netdev_empty_features;
 	netdev_features_t tmp;
@@ -141,27 +151,29 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
 		return -EFAULT;
 
 	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
-		valid |= (netdev_features_t)features[i].valid << (32 * i);
-		wanted |= (netdev_features_t)features[i].requested << (32 * i);
+		valid_arr[i] = features[i].valid;
+		wanted_arr[i] = features[i].requested;
 	}
+	bitmap_from_arr32(valid.bits, valid_arr, NETDEV_FEATURE_COUNT);
+	bitmap_from_arr32(wanted.bits, wanted_arr, NETDEV_FEATURE_COUNT);
 
-	tmp = valid & ~NETIF_F_ETHTOOL_BITS;
-	if (tmp)
+	tmp = netdev_features_andnot(valid, NETIF_F_ETHTOOL_BITS);
+	if (!netdev_features_empty(tmp))
 		return -EINVAL;
 
-	tmp = valid & ~dev->hw_features;
-	if (tmp) {
-		valid &= dev->hw_features;
+	tmp = netdev_hw_features_andnot_r(dev, valid);
+	if (!netdev_features_empty(tmp)) {
+		netdev_features_mask(&valid, dev->hw_features);
 		ret |= ETHTOOL_F_UNSUPPORTED;
 	}
 
-	dev->wanted_features &= ~valid;
-	tmp = wanted & valid;
-	dev->wanted_features |= tmp;
+	netdev_wanted_features_clear(dev, valid);
+	tmp = netdev_features_and(wanted, valid);
+	netdev_wanted_features_set(dev, tmp);
 	__netdev_update_features(dev);
 
-	tmp = dev->wanted_features ^ dev->features;
-	if (tmp & valid)
+	tmp = netdev_wanted_features_xor(dev, dev->features);
+	if (netdev_features_intersects(tmp, valid))
 		ret |= ETHTOOL_F_WISH;
 
 	return ret;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 7a3d98473a0a..614f2e7b3eb7 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1046,7 +1046,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	}
 
 	/* Only HW csum features are currently compatible with mac80211 */
-	if (WARN_ON(hw->netdev_features & ~MAC80211_SUPPORTED_FEATURES))
+	if (WARN_ON(!netdev_features_empty(netdev_features_andnot(hw->netdev_features,
+								  MAC80211_SUPPORTED_FEATURES))))
 		return -EINVAL;
 
 	if (hw->max_report_rates == 0)
-- 
2.33.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ