Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nl80211: add support for BSS coloring

This patch adds support for BSS color collisions to the wireless subsystem.
Add the required functionality to nl80211 that will notify about color
collisions, triggering the color change and notifying when it is completed.

Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: John Crispin <john@phrozen.org>
Link: https://lore.kernel.org/r/500b3582aec8fe2c42ef46f3117b148cb7cbceb5.1625247619.git.lorenzo@kernel.org
[remove unnecessary NULL initialisation]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

John Crispin and committed by
Johannes Berg
0d2ab3ae 8c89f7b3

+351
+92
include/net/cfg80211.h
··· 1253 1253 }; 1254 1254 1255 1255 /** 1256 + * struct cfg80211_color_change_settings - color change settings 1257 + * 1258 + * Used for bss color change 1259 + * 1260 + * @beacon_color_change: beacon data while performing the color countdown 1261 + * @counter_offsets_beacon: offsets of the counters within the beacon (tail) 1262 + * @counter_offsets_presp: offsets of the counters within the probe response 1263 + * @beacon_next: beacon data to be used after the color change 1264 + * @count: number of beacons until the color change 1265 + * @color: the color used after the change 1266 + */ 1267 + struct cfg80211_color_change_settings { 1268 + struct cfg80211_beacon_data beacon_color_change; 1269 + u16 counter_offset_beacon; 1270 + u16 counter_offset_presp; 1271 + struct cfg80211_beacon_data beacon_next; 1272 + u8 count; 1273 + u8 color; 1274 + }; 1275 + 1276 + /** 1256 1277 * struct iface_combination_params - input parameters for interface combinations 1257 1278 * 1258 1279 * Used to pass interface combination parameters ··· 4016 3995 * given TIDs. This callback may sleep. 4017 3996 * 4018 3997 * @set_sar_specs: Update the SAR (TX power) settings. 3998 + * 3999 + * @color_change: Initiate a color change. 4019 4000 */ 4020 4001 struct cfg80211_ops { 4021 4002 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); ··· 4345 4322 const u8 *peer, u8 tids); 4346 4323 int (*set_sar_specs)(struct wiphy *wiphy, 4347 4324 struct cfg80211_sar_specs *sar); 4325 + int (*color_change)(struct wiphy *wiphy, 4326 + struct net_device *dev, 4327 + struct cfg80211_color_change_settings *params); 4348 4328 }; 4349 4329 4350 4330 /* ··· 8243 8217 * @wiphy: the wiphy 8244 8218 */ 8245 8219 void cfg80211_bss_flush(struct wiphy *wiphy); 8220 + 8221 + /** 8222 + * cfg80211_bss_color_notify - notify about bss color event 8223 + * @dev: network device 8224 + * @gfp: allocation flags 8225 + * @cmd: the actual event we want to notify 8226 + * @count: the number of TBTTs until the color change happens 8227 + * @color_bitmap: representations of the colors that the local BSS is aware of 8228 + */ 8229 + int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, 8230 + enum nl80211_commands cmd, u8 count, 8231 + u64 color_bitmap); 8232 + 8233 + /** 8234 + * cfg80211_obss_color_collision_notify - notify about bss color collision 8235 + * @dev: network device 8236 + * @color_bitmap: representations of the colors that the local BSS is aware of 8237 + */ 8238 + static inline int cfg80211_obss_color_collision_notify(struct net_device *dev, 8239 + u64 color_bitmap) 8240 + { 8241 + return cfg80211_bss_color_notify(dev, GFP_KERNEL, 8242 + NL80211_CMD_OBSS_COLOR_COLLISION, 8243 + 0, color_bitmap); 8244 + } 8245 + 8246 + /** 8247 + * cfg80211_color_change_started_notify - notify color change start 8248 + * @dev: the device on which the color is switched 8249 + * @count: the number of TBTTs until the color change happens 8250 + * 8251 + * Inform the userspace about the color change that has started. 8252 + */ 8253 + static inline int cfg80211_color_change_started_notify(struct net_device *dev, 8254 + u8 count) 8255 + { 8256 + return cfg80211_bss_color_notify(dev, GFP_KERNEL, 8257 + NL80211_CMD_COLOR_CHANGE_STARTED, 8258 + count, 0); 8259 + } 8260 + 8261 + /** 8262 + * cfg80211_color_change_aborted_notify - notify color change abort 8263 + * @dev: the device on which the color is switched 8264 + * 8265 + * Inform the userspace about the color change that has aborted. 8266 + */ 8267 + static inline int cfg80211_color_change_aborted_notify(struct net_device *dev) 8268 + { 8269 + return cfg80211_bss_color_notify(dev, GFP_KERNEL, 8270 + NL80211_CMD_COLOR_CHANGE_ABORTED, 8271 + 0, 0); 8272 + } 8273 + 8274 + /** 8275 + * cfg80211_color_change_notify - notify color change completion 8276 + * @dev: the device on which the color was switched 8277 + * 8278 + * Inform the userspace about the color change that has completed. 8279 + */ 8280 + static inline int cfg80211_color_change_notify(struct net_device *dev) 8281 + { 8282 + return cfg80211_bss_color_notify(dev, GFP_KERNEL, 8283 + NL80211_CMD_COLOR_CHANGE_COMPLETED, 8284 + 0, 0); 8285 + } 8246 8286 8247 8287 #endif /* __NET_CFG80211_H */
+43
include/uapi/linux/nl80211.h
··· 1185 1185 * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to 1186 1186 * specify the wiphy index to be applied to. 1187 1187 * 1188 + * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever 1189 + * mac80211/drv detects a bss color collision. 1190 + * 1191 + * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that 1192 + * userspace wants to change the BSS color. 1193 + * 1194 + * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has 1195 + * started 1196 + * 1197 + * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has 1198 + * been aborted 1199 + * 1200 + * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change 1201 + * has completed 1202 + * 1188 1203 * @NL80211_CMD_MAX: highest used command number 1189 1204 * @__NL80211_CMD_AFTER_LAST: internal use 1190 1205 */ ··· 1431 1416 NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, 1432 1417 1433 1418 NL80211_CMD_SET_SAR_SPECS, 1419 + 1420 + NL80211_CMD_OBSS_COLOR_COLLISION, 1421 + 1422 + NL80211_CMD_COLOR_CHANGE_REQUEST, 1423 + 1424 + NL80211_CMD_COLOR_CHANGE_STARTED, 1425 + NL80211_CMD_COLOR_CHANGE_ABORTED, 1426 + NL80211_CMD_COLOR_CHANGE_COMPLETED, 1434 1427 1435 1428 /* add new commands above here */ 1436 1429 ··· 2583 2560 * disassoc events to indicate that an immediate reconnect to the AP 2584 2561 * is desired. 2585 2562 * 2563 + * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the 2564 + * %NL80211_CMD_OBSS_COLOR_COLLISION event. 2565 + * 2566 + * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's 2567 + * until the color switch event. 2568 + * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are 2569 + * switching to 2570 + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE 2571 + * information for the time while performing a color switch. 2572 + * 2586 2573 * @NUM_NL80211_ATTR: total number of nl80211_attrs available 2587 2574 * @NL80211_ATTR_MAX: highest attribute number currently defined 2588 2575 * @__NL80211_ATTR_AFTER_LAST: internal use ··· 3089 3056 NL80211_ATTR_SAR_SPEC, 3090 3057 3091 3058 NL80211_ATTR_DISABLE_HE, 3059 + 3060 + NL80211_ATTR_OBSS_COLOR_BITMAP, 3061 + 3062 + NL80211_ATTR_COLOR_CHANGE_COUNT, 3063 + NL80211_ATTR_COLOR_CHANGE_COLOR, 3064 + NL80211_ATTR_COLOR_CHANGE_ELEMS, 3092 3065 3093 3066 /* add attributes here, update the policy in nl80211.c */ 3094 3067 ··· 5992 5953 * frame protection for all management frames exchanged during the 5993 5954 * negotiation and range measurement procedure. 5994 5955 * 5956 + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision 5957 + * detection and change announcemnts. 5958 + * 5995 5959 * @NUM_NL80211_EXT_FEATURES: number of extended features. 5996 5960 * @MAX_NL80211_EXT_FEATURES: highest extended feature index. 5997 5961 */ ··· 6059 6017 NL80211_EXT_FEATURE_SECURE_LTF, 6060 6018 NL80211_EXT_FEATURE_SECURE_RTT, 6061 6019 NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, 6020 + NL80211_EXT_FEATURE_BSS_COLOR, 6062 6021 6063 6022 /* add new features before the definition below */ 6064 6023 NUM_NL80211_EXT_FEATURES,
+157
net/wireless/nl80211.c
··· 759 759 [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, 760 760 [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy), 761 761 [NL80211_ATTR_DISABLE_HE] = { .type = NLA_FLAG }, 762 + [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 }, 763 + [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, 764 + [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, 765 + [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), 762 766 }; 763 767 764 768 /* policy for the key attributes */ ··· 14804 14800 return ret; 14805 14801 } 14806 14802 14803 + static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) 14804 + { 14805 + struct cfg80211_registered_device *rdev = info->user_ptr[0]; 14806 + struct cfg80211_color_change_settings params = {}; 14807 + struct net_device *dev = info->user_ptr[1]; 14808 + struct wireless_dev *wdev = dev->ieee80211_ptr; 14809 + struct nlattr **tb; 14810 + u16 offset; 14811 + int err; 14812 + 14813 + if (!rdev->ops->color_change) 14814 + return -EOPNOTSUPP; 14815 + 14816 + if (!wiphy_ext_feature_isset(&rdev->wiphy, 14817 + NL80211_EXT_FEATURE_BSS_COLOR)) 14818 + return -EOPNOTSUPP; 14819 + 14820 + if (wdev->iftype != NL80211_IFTYPE_AP) 14821 + return -EOPNOTSUPP; 14822 + 14823 + if (!info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT] || 14824 + !info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR] || 14825 + !info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS]) 14826 + return -EINVAL; 14827 + 14828 + params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]); 14829 + params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]); 14830 + 14831 + err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_next); 14832 + if (err) 14833 + return err; 14834 + 14835 + tb = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*tb), GFP_KERNEL); 14836 + if (!tb) 14837 + return -ENOMEM; 14838 + 14839 + err = nla_parse_nested(tb, NL80211_ATTR_MAX, 14840 + info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS], 14841 + nl80211_policy, info->extack); 14842 + if (err) 14843 + goto out; 14844 + 14845 + err = nl80211_parse_beacon(rdev, tb, &params.beacon_color_change); 14846 + if (err) 14847 + goto out; 14848 + 14849 + if (!tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) { 14850 + err = -EINVAL; 14851 + goto out; 14852 + } 14853 + 14854 + if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) != sizeof(u16)) { 14855 + err = -EINVAL; 14856 + goto out; 14857 + } 14858 + 14859 + offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]); 14860 + if (offset >= params.beacon_color_change.tail_len) { 14861 + err = -EINVAL; 14862 + goto out; 14863 + } 14864 + 14865 + if (params.beacon_color_change.tail[offset] != params.count) { 14866 + err = -EINVAL; 14867 + goto out; 14868 + } 14869 + 14870 + params.counter_offset_beacon = offset; 14871 + 14872 + if (tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) { 14873 + if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) != 14874 + sizeof(u16)) { 14875 + err = -EINVAL; 14876 + goto out; 14877 + } 14878 + 14879 + offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]); 14880 + if (offset >= params.beacon_color_change.probe_resp_len) { 14881 + err = -EINVAL; 14882 + goto out; 14883 + } 14884 + 14885 + if (params.beacon_color_change.probe_resp[offset] != 14886 + params.count) { 14887 + err = -EINVAL; 14888 + goto out; 14889 + } 14890 + 14891 + params.counter_offset_presp = offset; 14892 + } 14893 + 14894 + wdev_lock(wdev); 14895 + err = rdev_color_change(rdev, dev, &params); 14896 + wdev_unlock(wdev); 14897 + 14898 + out: 14899 + kfree(tb); 14900 + return err; 14901 + } 14902 + 14807 14903 #define NL80211_FLAG_NEED_WIPHY 0x01 14808 14904 #define NL80211_FLAG_NEED_NETDEV 0x02 14809 14905 #define NL80211_FLAG_NEED_RTNL 0x04 ··· 15897 15793 .doit = nl80211_set_sar_specs, 15898 15794 .flags = GENL_UNS_ADMIN_PERM, 15899 15795 .internal_flags = NL80211_FLAG_NEED_WIPHY | 15796 + NL80211_FLAG_NEED_RTNL, 15797 + }, 15798 + { 15799 + .cmd = NL80211_CMD_COLOR_CHANGE_REQUEST, 15800 + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 15801 + .doit = nl80211_color_change, 15802 + .flags = GENL_UNS_ADMIN_PERM, 15803 + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | 15900 15804 NL80211_FLAG_NEED_RTNL, 15901 15805 }, 15902 15806 }; ··· 17535 17423 count, quiet); 17536 17424 } 17537 17425 EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); 17426 + 17427 + int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, 17428 + enum nl80211_commands cmd, u8 count, 17429 + u64 color_bitmap) 17430 + { 17431 + struct wireless_dev *wdev = dev->ieee80211_ptr; 17432 + struct wiphy *wiphy = wdev->wiphy; 17433 + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); 17434 + struct sk_buff *msg; 17435 + void *hdr; 17436 + 17437 + ASSERT_WDEV_LOCK(wdev); 17438 + 17439 + trace_cfg80211_bss_color_notify(dev, cmd, count, color_bitmap); 17440 + 17441 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); 17442 + if (!msg) 17443 + return -ENOMEM; 17444 + 17445 + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); 17446 + if (!hdr) 17447 + goto nla_put_failure; 17448 + 17449 + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) 17450 + goto nla_put_failure; 17451 + 17452 + if (cmd == NL80211_CMD_COLOR_CHANGE_STARTED && 17453 + nla_put_u32(msg, NL80211_ATTR_COLOR_CHANGE_COUNT, count)) 17454 + goto nla_put_failure; 17455 + 17456 + if (cmd == NL80211_CMD_OBSS_COLOR_COLLISION && 17457 + nla_put_u64_64bit(msg, NL80211_ATTR_OBSS_COLOR_BITMAP, 17458 + color_bitmap, NL80211_ATTR_PAD)) 17459 + goto nla_put_failure; 17460 + 17461 + genlmsg_end(msg, hdr); 17462 + 17463 + return genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), 17464 + msg, 0, NL80211_MCGRP_MLME, gfp); 17465 + 17466 + nla_put_failure: 17467 + nlmsg_free(msg); 17468 + return -EINVAL; 17469 + } 17470 + EXPORT_SYMBOL(cfg80211_bss_color_notify); 17538 17471 17539 17472 void 17540 17473 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
+13
net/wireless/rdev-ops.h
··· 1368 1368 return ret; 1369 1369 } 1370 1370 1371 + static inline int rdev_color_change(struct cfg80211_registered_device *rdev, 1372 + struct net_device *dev, 1373 + struct cfg80211_color_change_settings *params) 1374 + { 1375 + int ret; 1376 + 1377 + trace_rdev_color_change(&rdev->wiphy, dev, params); 1378 + ret = rdev->ops->color_change(&rdev->wiphy, dev, params); 1379 + trace_rdev_return_int(&rdev->wiphy, ret); 1380 + 1381 + return ret; 1382 + } 1383 + 1371 1384 #endif /* __CFG80211_RDEV_OPS */
+46
net/wireless/trace.h
··· 3597 3597 WIPHY_PR_ARG, __entry->type, __entry->num) 3598 3598 ); 3599 3599 3600 + TRACE_EVENT(rdev_color_change, 3601 + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, 3602 + struct cfg80211_color_change_settings *params), 3603 + TP_ARGS(wiphy, netdev, params), 3604 + TP_STRUCT__entry( 3605 + WIPHY_ENTRY 3606 + NETDEV_ENTRY 3607 + __field(u8, count) 3608 + __field(u16, bcn_ofs) 3609 + __field(u16, pres_ofs) 3610 + ), 3611 + TP_fast_assign( 3612 + WIPHY_ASSIGN; 3613 + NETDEV_ASSIGN; 3614 + __entry->count = params->count; 3615 + __entry->bcn_ofs = params->counter_offset_beacon; 3616 + __entry->pres_ofs = params->counter_offset_presp; 3617 + ), 3618 + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT 3619 + ", count: %u", 3620 + WIPHY_PR_ARG, NETDEV_PR_ARG, 3621 + __entry->count) 3622 + ); 3623 + 3624 + TRACE_EVENT(cfg80211_bss_color_notify, 3625 + TP_PROTO(struct net_device *netdev, 3626 + enum nl80211_commands cmd, 3627 + u8 count, u64 color_bitmap), 3628 + TP_ARGS(netdev, cmd, count, color_bitmap), 3629 + TP_STRUCT__entry( 3630 + NETDEV_ENTRY 3631 + __field(enum nl80211_bss_scan_width, cmd) 3632 + __field(u8, count) 3633 + __field(u64, color_bitmap) 3634 + ), 3635 + TP_fast_assign( 3636 + NETDEV_ASSIGN; 3637 + __entry->cmd = cmd; 3638 + __entry->count = count; 3639 + __entry->color_bitmap = color_bitmap; 3640 + ), 3641 + TP_printk(NETDEV_PR_FMT ", cmd: %x, count: %u, bitmap: %llx", 3642 + NETDEV_PR_ARG, __entry->cmd, __entry->count, 3643 + __entry->color_bitmap) 3644 + ); 3645 + 3600 3646 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ 3601 3647 3602 3648 #undef TRACE_INCLUDE_PATH