]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: always use full chanctx compatible check
authorJohannes Berg <johannes.berg@intel.com>
Tue, 3 Mar 2026 14:26:18 +0000 (15:26 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 13 Mar 2026 06:11:14 +0000 (07:11 +0100)
For NPCA, we need to treat the channel request differently
for AP and other interfaces (APs can share NPCA, under the
assumption that userspace will set them up with the same
BSS color.) This is difficult if we have to check against
a chanreq made up from the chanctx, but this isn't a code
path that needs to be highly optimised, so just always use
the (originally) recheck functionality to check against
all users of the chanctx.

Link: https://patch.msgid.link/20260303152641.1a3ff6ead82b.I486f1a94b9a32e0b045815cbbb22679c8cef56e4@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/chan.c

index 4447cf03c41b9337a528b37244f4c8f79cc76ede..2f0c93f3ace60dc7da86cc71ff085270b344438b 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * mac80211 - channel management
- * Copyright 2020 - 2025 Intel Corporation
+ * Copyright 2020-2026 Intel Corporation
  */
 
 #include <linux/nl80211.h>
@@ -239,26 +239,47 @@ ieee80211_chanreq_compatible(const struct ieee80211_chan_req *a,
        return tmp;
 }
 
+/*
+ * When checking for compatible, check against all the links using
+ * the chanctx (except the one passed that might be changing) to
+ * allow changes to the AP's bandwidth for wider bandwidth OFDMA
+ * purposes, which wouldn't be treated as compatible by checking
+ * against the chanctx's oper/ap chandefs.
+ */
 static const struct ieee80211_chan_req *
-ieee80211_chanctx_compatible(struct ieee80211_chanctx *ctx,
-                            const struct ieee80211_chan_req *req,
-                            struct ieee80211_chan_req *tmp)
+_ieee80211_chanctx_compatible(struct ieee80211_local *local,
+                             struct ieee80211_link_data *skip_link,
+                             struct ieee80211_chanctx *ctx,
+                             const struct ieee80211_chan_req *req,
+                             struct ieee80211_chan_req *tmp)
 {
-       const struct ieee80211_chan_req *ret;
-       struct ieee80211_chan_req tmp2;
+       const struct ieee80211_chan_req *ret = req;
+       struct ieee80211_chanctx_user_iter iter;
 
-       *tmp = (struct ieee80211_chan_req){
-               .oper = ctx->conf.def,
-               .ap = ctx->conf.ap,
-       };
+       lockdep_assert_wiphy(local->hw.wiphy);
+
+       for_each_chanctx_user_all(local, ctx, &iter) {
+               if (iter.link && iter.link == skip_link)
+                       continue;
+
+               ret = ieee80211_chanreq_compatible(ret, iter.chanreq, tmp);
+               if (!ret)
+                       return NULL;
+       }
 
-       ret = ieee80211_chanreq_compatible(tmp, req, &tmp2);
-       if (!ret)
-               return NULL;
        *tmp = *ret;
        return tmp;
 }
 
+static const struct ieee80211_chan_req *
+ieee80211_chanctx_compatible(struct ieee80211_local *local,
+                            struct ieee80211_chanctx *ctx,
+                            const struct ieee80211_chan_req *req,
+                            struct ieee80211_chan_req *tmp)
+{
+       return _ieee80211_chanctx_compatible(local, NULL, ctx, req, tmp);
+}
+
 static const struct ieee80211_chan_req *
 ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *ctx,
@@ -756,7 +777,8 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
                if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
                        continue;
 
-               compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp);
+               compat = ieee80211_chanctx_compatible(local, ctx, chanreq,
+                                                     &tmp);
                if (!compat)
                        continue;
 
@@ -2128,40 +2150,6 @@ int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
        return 0;
 }
 
-/*
- * This is similar to ieee80211_chanctx_compatible(), but rechecks
- * against all the links actually using it (except the one that's
- * passed, since that one is changing).
- * This is done in order to allow changes to the AP's bandwidth for
- * wider bandwidth OFDMA purposes, which wouldn't be treated as
- * compatible by ieee80211_chanctx_recheck() but is OK if the link
- * requesting the update is the only one using it.
- */
-static const struct ieee80211_chan_req *
-ieee80211_chanctx_recheck(struct ieee80211_local *local,
-                         struct ieee80211_link_data *skip_link,
-                         struct ieee80211_chanctx *ctx,
-                         const struct ieee80211_chan_req *req,
-                         struct ieee80211_chan_req *tmp)
-{
-       const struct ieee80211_chan_req *ret = req;
-       struct ieee80211_chanctx_user_iter iter;
-
-       lockdep_assert_wiphy(local->hw.wiphy);
-
-       for_each_chanctx_user_all(local, ctx, &iter) {
-               if (iter.link == skip_link)
-                       continue;
-
-               ret = ieee80211_chanreq_compatible(ret, iter.chanreq, tmp);
-               if (!ret)
-                       return NULL;
-       }
-
-       *tmp = *ret;
-       return tmp;
-}
-
 int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
                                  const struct ieee80211_chan_req *chanreq,
                                  u64 *changed)
@@ -2198,7 +2186,7 @@ int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
 
        ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       compat = ieee80211_chanctx_recheck(local, link, ctx, chanreq, &tmp);
+       compat = _ieee80211_chanctx_compatible(local, link, ctx, chanreq, &tmp);
        if (!compat)
                return -EINVAL;