0ba97a2c0fee38637f0d21d844b03c3219cae091
[openwrt/staging/ldir.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Tue, 4 Jun 2024 21:01:50 +0200
3 Subject: [PATCH] wifi: cfg80211: extend interface combination check for
4 multi-radio
5
6 Add a field in struct iface_combination_params to check per-radio
7 interface combinations instead of per-wiphy ones.
8
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
10 ---
11
12 --- a/include/net/cfg80211.h
13 +++ b/include/net/cfg80211.h
14 @@ -1598,6 +1598,7 @@ struct cfg80211_color_change_settings {
15 *
16 * Used to pass interface combination parameters
17 *
18 + * @radio_idx: wiphy radio index or -1 for global
19 * @num_different_channels: the number of different channels we want
20 * to use for verification
21 * @radar_detect: a bitmap where each bit corresponds to a channel
22 @@ -1611,6 +1612,7 @@ struct cfg80211_color_change_settings {
23 * the verification
24 */
25 struct iface_combination_params {
26 + int radio_idx;
27 int num_different_channels;
28 u8 radar_detect;
29 int iftype_num[NUM_NL80211_IFTYPES];
30 @@ -4579,6 +4581,8 @@ struct mgmt_frame_regs {
31 *
32 * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
33 * @set_ttlm: set the TID to link mapping.
34 + * @get_radio_mask: get bitmask of radios in use.
35 + * (invoked with the wiphy mutex held)
36 */
37 struct cfg80211_ops {
38 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
39 @@ -4940,6 +4944,7 @@ struct cfg80211_ops {
40 struct cfg80211_set_hw_timestamp *hwts);
41 int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
42 struct cfg80211_ttlm_params *params);
43 + u32 (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev);
44 };
45
46 /*
47 --- a/net/mac80211/util.c
48 +++ b/net/mac80211/util.c
49 @@ -3930,6 +3930,7 @@ int ieee80211_check_combinations(struct
50 int total = 1;
51 struct iface_combination_params params = {
52 .radar_detect = radar_detect,
53 + .radio_idx = -1,
54 };
55
56 lockdep_assert_wiphy(local->hw.wiphy);
57 @@ -4020,7 +4021,9 @@ int ieee80211_max_num_channels(struct ie
58 struct ieee80211_chanctx *ctx;
59 u32 max_num_different_channels = 1;
60 int err;
61 - struct iface_combination_params params = {0};
62 + struct iface_combination_params params = {
63 + .radio_idx = -1,
64 + };
65
66 lockdep_assert_wiphy(local->hw.wiphy);
67
68 --- a/net/wireless/rdev-ops.h
69 +++ b/net/wireless/rdev-ops.h
70 @@ -1542,4 +1542,16 @@ rdev_set_ttlm(struct cfg80211_registered
71
72 return ret;
73 }
74 +
75 +static inline u32
76 +rdev_get_radio_mask(struct cfg80211_registered_device *rdev,
77 + struct net_device *dev)
78 +{
79 + struct wiphy *wiphy = &rdev->wiphy;
80 +
81 + if (!rdev->ops->get_radio_mask)
82 + return 0;
83 +
84 + return rdev->ops->get_radio_mask(wiphy, dev);
85 +}
86 #endif /* __CFG80211_RDEV_OPS */
87 --- a/net/wireless/util.c
88 +++ b/net/wireless/util.c
89 @@ -2305,13 +2305,16 @@ static int cfg80211_wdev_bi(struct wirel
90
91 static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
92 u32 *beacon_int_gcd,
93 - bool *beacon_int_different)
94 + bool *beacon_int_different,
95 + int radio_idx)
96 {
97 + struct cfg80211_registered_device *rdev;
98 struct wireless_dev *wdev;
99
100 *beacon_int_gcd = 0;
101 *beacon_int_different = false;
102
103 + rdev = wiphy_to_rdev(wiphy);
104 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
105 int wdev_bi;
106
107 @@ -2319,6 +2322,11 @@ static void cfg80211_calculate_bi_data(s
108 if (wdev->valid_links)
109 continue;
110
111 + /* skip wdevs not active on the given wiphy radio */
112 + if (radio_idx >= 0 &&
113 + !(rdev_get_radio_mask(rdev, wdev->netdev) & BIT(radio_idx)))
114 + continue;
115 +
116 wdev_bi = cfg80211_wdev_bi(wdev);
117
118 if (!wdev_bi)
119 @@ -2366,14 +2374,19 @@ int cfg80211_iter_combinations(struct wi
120 void *data),
121 void *data)
122 {
123 + const struct wiphy_radio *radio = NULL;
124 + const struct ieee80211_iface_combination *c, *cs;
125 const struct ieee80211_regdomain *regdom;
126 enum nl80211_dfs_regions region = 0;
127 - int i, j, iftype;
128 + int i, j, n, iftype;
129 int num_interfaces = 0;
130 u32 used_iftypes = 0;
131 u32 beacon_int_gcd;
132 bool beacon_int_different;
133
134 + if (params->radio_idx >= 0)
135 + radio = &wiphy->radio[params->radio_idx];
136 +
137 /*
138 * This is a bit strange, since the iteration used to rely only on
139 * the data given by the driver, but here it now relies on context,
140 @@ -2385,7 +2398,8 @@ int cfg80211_iter_combinations(struct wi
141 * interfaces (while being brought up) and channel/radar data.
142 */
143 cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
144 - &beacon_int_gcd, &beacon_int_different);
145 + &beacon_int_gcd, &beacon_int_different,
146 + params->radio_idx);
147
148 if (params->radar_detect) {
149 rcu_read_lock();
150 @@ -2402,13 +2416,18 @@ int cfg80211_iter_combinations(struct wi
151 used_iftypes |= BIT(iftype);
152 }
153
154 - for (i = 0; i < wiphy->n_iface_combinations; i++) {
155 - const struct ieee80211_iface_combination *c;
156 + if (radio) {
157 + cs = radio->iface_combinations;
158 + n = radio->n_iface_combinations;
159 + } else {
160 + cs = wiphy->iface_combinations;
161 + n = wiphy->n_iface_combinations;
162 + }
163 + for (i = 0; i < n; i++) {
164 struct ieee80211_iface_limit *limits;
165 u32 all_iftypes = 0;
166
167 - c = &wiphy->iface_combinations[i];
168 -
169 + c = &cs[i];
170 if (num_interfaces > c->max_interfaces)
171 continue;
172 if (params->num_different_channels > c->num_different_channels)