|
@@ -2797,3 +2797,75 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
|
|
|
|
|
|
ps->dtim_count = dtim_count;
|
|
|
}
|
|
|
+
|
|
|
+int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
|
|
+ const struct cfg80211_chan_def *chandef,
|
|
|
+ enum ieee80211_chanctx_mode chanmode,
|
|
|
+ u8 radar_detect)
|
|
|
+{
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ struct ieee80211_sub_if_data *sdata_iter;
|
|
|
+ enum nl80211_iftype iftype = sdata->wdev.iftype;
|
|
|
+ int num[NUM_NL80211_IFTYPES];
|
|
|
+ struct ieee80211_chanctx *ctx;
|
|
|
+ int num_different_channels = 1;
|
|
|
+ int total = 1;
|
|
|
+
|
|
|
+ lockdep_assert_held(&local->chanctx_mtx);
|
|
|
+
|
|
|
+ if (WARN_ON(hweight32(radar_detect) > 1))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (WARN_ON(chanmode == IEEE80211_CHANCTX_SHARED && !chandef->chan))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Always allow software iftypes */
|
|
|
+ if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
|
|
|
+ if (radar_detect)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(num, 0, sizeof(num));
|
|
|
+
|
|
|
+ if (iftype != NL80211_IFTYPE_UNSPECIFIED)
|
|
|
+ num[iftype] = 1;
|
|
|
+
|
|
|
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
|
|
|
+ if (ctx->conf.radar_enabled)
|
|
|
+ radar_detect |= BIT(ctx->conf.def.width);
|
|
|
+ if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
|
|
|
+ num_different_channels++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ((chanmode == IEEE80211_CHANCTX_SHARED) &&
|
|
|
+ cfg80211_chandef_compatible(chandef,
|
|
|
+ &ctx->conf.def))
|
|
|
+ continue;
|
|
|
+ num_different_channels++;
|
|
|
+ }
|
|
|
+
|
|
|
+ list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
|
|
|
+ struct wireless_dev *wdev_iter;
|
|
|
+
|
|
|
+ wdev_iter = &sdata_iter->wdev;
|
|
|
+
|
|
|
+ if (sdata_iter == sdata ||
|
|
|
+ rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
|
|
|
+ local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ num[wdev_iter->iftype]++;
|
|
|
+ total++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (total == 1 && !radar_detect)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return cfg80211_check_combinations(local->hw.wiphy,
|
|
|
+ num_different_channels,
|
|
|
+ radar_detect, num);
|
|
|
+}
|