diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 73af7398850b..436f98870066 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2797,3 +2797,75 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, | |||
2797 | 2797 | ||
2798 | ps->dtim_count = dtim_count; | 2798 | ps->dtim_count = dtim_count; |
2799 | } | 2799 | } |
2800 | |||
2801 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | ||
2802 | const struct cfg80211_chan_def *chandef, | ||
2803 | enum ieee80211_chanctx_mode chanmode, | ||
2804 | u8 radar_detect) | ||
2805 | { | ||
2806 | struct ieee80211_local *local = sdata->local; | ||
2807 | struct ieee80211_sub_if_data *sdata_iter; | ||
2808 | enum nl80211_iftype iftype = sdata->wdev.iftype; | ||
2809 | int num[NUM_NL80211_IFTYPES]; | ||
2810 | struct ieee80211_chanctx *ctx; | ||
2811 | int num_different_channels = 1; | ||
2812 | int total = 1; | ||
2813 | |||
2814 | lockdep_assert_held(&local->chanctx_mtx); | ||
2815 | |||
2816 | if (WARN_ON(hweight32(radar_detect) > 1)) | ||
2817 | return -EINVAL; | ||
2818 | |||
2819 | if (WARN_ON(chanmode == IEEE80211_CHANCTX_SHARED && !chandef->chan)) | ||
2820 | return -EINVAL; | ||
2821 | |||
2822 | if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) | ||
2823 | return -EINVAL; | ||
2824 | |||
2825 | /* Always allow software iftypes */ | ||
2826 | if (local->hw.wiphy->software_iftypes & BIT(iftype)) { | ||
2827 | if (radar_detect) | ||
2828 | return -EINVAL; | ||
2829 | return 0; | ||
2830 | } | ||
2831 | |||
2832 | memset(num, 0, sizeof(num)); | ||
2833 | |||
2834 | if (iftype != NL80211_IFTYPE_UNSPECIFIED) | ||
2835 | num[iftype] = 1; | ||
2836 | |||
2837 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
2838 | if (ctx->conf.radar_enabled) | ||
2839 | radar_detect |= BIT(ctx->conf.def.width); | ||
2840 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { | ||
2841 | num_different_channels++; | ||
2842 | continue; | ||
2843 | } | ||
2844 | if ((chanmode == IEEE80211_CHANCTX_SHARED) && | ||
2845 | cfg80211_chandef_compatible(chandef, | ||
2846 | &ctx->conf.def)) | ||
2847 | continue; | ||
2848 | num_different_channels++; | ||
2849 | } | ||
2850 | |||
2851 | list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) { | ||
2852 | struct wireless_dev *wdev_iter; | ||
2853 | |||
2854 | wdev_iter = &sdata_iter->wdev; | ||
2855 | |||
2856 | if (sdata_iter == sdata || | ||
2857 | rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL || | ||
2858 | local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype)) | ||
2859 | continue; | ||
2860 | |||
2861 | num[wdev_iter->iftype]++; | ||
2862 | total++; | ||
2863 | } | ||
2864 | |||
2865 | if (total == 1 && !radar_detect) | ||
2866 | return 0; | ||
2867 | |||
2868 | return cfg80211_check_combinations(local->hw.wiphy, | ||
2869 | num_different_channels, | ||
2870 | radar_detect, num); | ||
2871 | } | ||