To ease further DFS development regarding interface combinations, use the interface combinations structure to test for radar capabilities. Drivers can specify which channel widths they support, and in which modes. Right now only a single AP interface is allowed, but as the DFS code evolves other combinations can be enabled.
Unified · Split
| @@ -2125,6 +2125,7 @@ struct ieee80211_iface_limit { · 2124 unmodified lines | ||
| 2125 | 2125 | * @beacon_int_infra_match: In this combination, the beacon intervals |
| 2126 | 2126 | * between infrastructure and AP types must match. This is required |
| 2127 | 2127 | * only in special cases. |
| 2128 | + * @radar_detect_widths: bitmap of channel widths supported for radar detection | |
| 2128 | 2129 | * |
| 2129 | 2130 | * These examples can be expressed as follows: |
| 2130 | 2131 | * |
| @@ -2177,6 +2178,7 @@ struct ieee80211_iface_combination { · 46 unmodified lines | ||
| 2177 | 2178 | u16 max_interfaces; |
| 2178 | 2179 | u8 n_limits; |
| 2179 | 2180 | bool beacon_int_infra_match; |
| 2181 | + u8 radar_detect_widths; | |
| 2180 | 2182 | }; |
| 2181 | 2183 | |
| 2182 | 2184 | struct mac_address { |
| @@ -2984,6 +2984,8 @@ enum nl80211_iface_limit_attrs { · 2983 unmodified lines | ||
| 2984 | 2984 | * the infrastructure network's beacon interval. |
| 2985 | 2985 | * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many |
| 2986 | 2986 | * different channels may be used within this group. |
| 2987 | + * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap | |
| 2988 | + * of supported channel widths for radar detection. | |
| 2987 | 2989 | * @NUM_NL80211_IFACE_COMB: number of attributes |
| 2988 | 2990 | * @MAX_NL80211_IFACE_COMB: highest attribute number |
| 2989 | 2991 | * |
| @@ -3016,6 +3018,7 @@ enum nl80211_if_combination_attrs { · 26 unmodified lines | ||
| 3016 | 3018 | NL80211_IFACE_COMB_MAXNUM, |
| 3017 | 3019 | NL80211_IFACE_COMB_STA_AP_BI_MATCH, |
| 3018 | 3020 | NL80211_IFACE_COMB_NUM_CHANNELS, |
| 3021 | + NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | |
| 3019 | 3022 | |
| 3020 | 3023 | /* keep last */ |
| 3021 | 3024 | NUM_NL80211_IFACE_COMB, |
| @@ -382,8 +382,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) · 381 unmodified lines | ||
| 382 | 382 | |
| 383 | 383 | c = &wiphy->iface_combinations[i]; |
| 384 | 384 | |
| 385 | − /* Combinations with just one interface aren't real */ | |
| 386 | − if (WARN_ON(c->max_interfaces < 2)) | |
| 385 | + /* | |
| 386 | + * Combinations with just one interface aren't real, | |
| 387 | + * however we make an exception for DFS. | |
| 388 | + */ | |
| 389 | + if (WARN_ON((c->max_interfaces < 2) && !c->radar_detect_widths)) | |
| 387 | 390 | return -EINVAL; |
| 388 | 391 | |
| 389 | 392 | /* Need at least one channel */ |
| @@ -398,6 +401,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) · 8 unmodified lines | ||
| 398 | 401 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) |
| 399 | 402 | return -EINVAL; |
| 400 | 403 | |
| 404 | + /* DFS only works on one channel. */ | |
| 405 | + if (WARN_ON(c->radar_detect_widths && | |
| 406 | + (c->num_different_channels > 1))) | |
| 407 | + return -EINVAL; | |
| 408 | + | |
| 401 | 409 | if (WARN_ON(!c->n_limits)) |
| 402 | 410 | return -EINVAL; |
| 403 | 411 | |
| @@ -425,7 +425,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, · 424 unmodified lines | ||
| 425 | 425 | struct wireless_dev *wdev, |
| 426 | 426 | enum nl80211_iftype iftype, |
| 427 | 427 | struct ieee80211_channel *chan, |
| 428 | − enum cfg80211_chan_mode chanmode); | |
| 428 | + enum cfg80211_chan_mode chanmode, | |
| 429 | + u8 radar_detect); | |
| 429 | 430 | |
| 430 | 431 | static inline int |
| 431 | 432 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, |
| @@ -433,7 +434,7 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, · 1 unmodified line | ||
| 433 | 434 | enum nl80211_iftype iftype) |
| 434 | 435 | { |
| 435 | 436 | return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, |
| 436 | − CHAN_MODE_UNDEFINED); | |
| 437 | + CHAN_MODE_UNDEFINED, 0); | |
| 437 | 438 | } |
| 438 | 439 | |
| 439 | 440 | static inline int |
| @@ -450,7 +451,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, · 10 unmodified lines | ||
| 450 | 451 | enum cfg80211_chan_mode chanmode) |
| 451 | 452 | { |
| 452 | 453 | return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
| 453 | − chan, chanmode); | |
| 454 | + chan, chanmode, 0); | |
| 454 | 455 | } |
| 455 | 456 | |
| 456 | 457 | void |
| @@ -856,6 +856,9 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy, · 855 unmodified lines | ||
| 856 | 856 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, |
| 857 | 857 | c->max_interfaces)) |
| 858 | 858 | goto nla_put_failure; |
| 859 | + if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | |
| 860 | + c->radar_detect_widths)) | |
| 861 | + goto nla_put_failure; | |
| 859 | 862 | |
| 860 | 863 | nla_nest_end(msg, nl_combi); |
| 861 | 864 | } |
| @@ -1184,7 +1184,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, · 1183 unmodified lines | ||
| 1184 | 1184 | struct wireless_dev *wdev, |
| 1185 | 1185 | enum nl80211_iftype iftype, |
| 1186 | 1186 | struct ieee80211_channel *chan, |
| 1187 | − enum cfg80211_chan_mode chanmode) | |
| 1187 | + enum cfg80211_chan_mode chanmode, | |
| 1188 | + u8 radar_detect) | |
| 1188 | 1189 | { |
| 1189 | 1190 | struct wireless_dev *wdev_iter; |
| 1190 | 1191 | u32 used_iftypes = BIT(iftype); |
| @@ -1195,14 +1196,45 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, · 4 unmodified lines | ||
| 1195 | 1196 | enum cfg80211_chan_mode chmode; |
| 1196 | 1197 | int num_different_channels = 0; |
| 1197 | 1198 | int total = 1; |
| 1199 | + bool radar_required; | |
| 1198 | 1200 | int i, j; |
| 1199 | 1201 | |
| 1200 | 1202 | ASSERT_RTNL(); |
| 1201 | 1203 | lockdep_assert_held(&rdev->devlist_mtx); |
| 1202 | 1204 | |
| 1205 | + if (WARN_ON(hweight32(radar_detect) > 1)) | |
| 1206 | + return -EINVAL; | |
| 1207 | + | |
| 1208 | + switch (iftype) { | |
| 1209 | + case NL80211_IFTYPE_ADHOC: | |
| 1210 | + case NL80211_IFTYPE_AP: | |
| 1211 | + case NL80211_IFTYPE_AP_VLAN: | |
| 1212 | + case NL80211_IFTYPE_MESH_POINT: | |
| 1213 | + case NL80211_IFTYPE_P2P_GO: | |
| 1214 | + case NL80211_IFTYPE_WDS: | |
| 1215 | + radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); | |
| 1216 | + break; | |
| 1217 | + case NL80211_IFTYPE_P2P_CLIENT: | |
| 1218 | + case NL80211_IFTYPE_STATION: | |
| 1219 | + case NL80211_IFTYPE_MONITOR: | |
| 1220 | + radar_required = false; | |
| 1221 | + break; | |
| 1222 | + case NL80211_IFTYPE_P2P_DEVICE: | |
| 1223 | + case NUM_NL80211_IFTYPES: | |
| 1224 | + case NL80211_IFTYPE_UNSPECIFIED: | |
| 1225 | + default: | |
| 1226 | + return -EINVAL; | |
| 1227 | + } | |
| 1228 | + | |
| 1229 | + if (radar_required && !radar_detect) | |
| 1230 | + return -EINVAL; | |
| 1231 | + | |
| 1203 | 1232 | /* Always allow software iftypes */ |
| 1204 | − if (rdev->wiphy.software_iftypes & BIT(iftype)) | |
| 1233 | + if (rdev->wiphy.software_iftypes & BIT(iftype)) { | |
| 1234 | + if (radar_detect) | |
| 1235 | + return -EINVAL; | |
| 1205 | 1236 | return 0; |
| 1237 | + } | |
| 1206 | 1238 | |
| 1207 | 1239 | memset(num, 0, sizeof(num)); |
| 1208 | 1240 | memset(used_channels, 0, sizeof(used_channels)); |
| @@ -1275,7 +1307,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, · 66 unmodified lines | ||
| 1275 | 1307 | used_iftypes |= BIT(wdev_iter->iftype); |
| 1276 | 1308 | } |
| 1277 | 1309 | |
| 1278 | − if (total == 1) | |
| 1310 | + if (total == 1 && !radar_detect) | |
| 1279 | 1311 | return 0; |
| 1280 | 1312 | |
| 1281 | 1313 | for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { |
| @@ -1308,6 +1340,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, · 26 unmodified lines | ||
| 1308 | 1340 | } |
| 1309 | 1341 | } |
| 1310 | 1342 | |
| 1343 | + if (radar_detect && !(c->radar_detect_widths & radar_detect)) | |
| 1344 | + goto cont; | |
| 1345 | + | |
| 1311 | 1346 | /* |
| 1312 | 1347 | * Finally check that all iftypes that we're currently |
| 1313 | 1348 | * using are actually part of this combination. If they |