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

nl80211: MBSSID and EMA support in AP mode

Add new attributes to configure support for multiple BSSID
and advanced multi-BSSID advertisements (EMA) in AP mode.

- NL80211_ATTR_MBSSID_CONFIG used for per interface configuration.
- NL80211_ATTR_MBSSID_ELEMS used to MBSSID elements for beacons.

Memory for the elements is allocated dynamically. This change frees
the memory in existing functions which call nl80211_parse_beacon(),
a comment is added to indicate the new references to do the same.

Signed-off-by: John Crispin <john@phrozen.org>
Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
Link: https://lore.kernel.org/r/20210916025437.29138-2-alokad@codeaurora.org
[don't leave ERR_PTR hanging around]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

John Crispin and committed by
Johannes Berg
dc1e3cb8 05075fe7

+293 -5
+44
include/net/cfg80211.h
··· 1057 1057 }; 1058 1058 1059 1059 /** 1060 + * struct cfg80211_mbssid_config - AP settings for multi bssid 1061 + * 1062 + * @tx_wdev: pointer to the transmitted interface in the MBSSID set 1063 + * @index: index of this AP in the multi bssid group. 1064 + * @ema: set to true if the beacons should be sent out in EMA mode. 1065 + */ 1066 + struct cfg80211_mbssid_config { 1067 + struct wireless_dev *tx_wdev; 1068 + u8 index; 1069 + bool ema; 1070 + }; 1071 + 1072 + /** 1073 + * struct cfg80211_mbssid_elems - Multiple BSSID elements 1074 + * 1075 + * @cnt: Number of elements in array %elems. 1076 + * 1077 + * @elem: Array of multiple BSSID element(s) to be added into Beacon frames. 1078 + * @elem.data: Data for multiple BSSID elements. 1079 + * @elem.len: Length of data. 1080 + */ 1081 + struct cfg80211_mbssid_elems { 1082 + u8 cnt; 1083 + struct { 1084 + const u8 *data; 1085 + size_t len; 1086 + } elem[]; 1087 + }; 1088 + 1089 + /** 1060 1090 * struct cfg80211_beacon_data - beacon data 1061 1091 * @head: head portion of beacon (before TIM IE) 1062 1092 * or %NULL if not changed ··· 1104 1074 * @assocresp_ies_len: length of assocresp_ies in octets 1105 1075 * @probe_resp_len: length of probe response template (@probe_resp) 1106 1076 * @probe_resp: probe response template (AP mode only) 1077 + * @mbssid_ies: multiple BSSID elements 1107 1078 * @ftm_responder: enable FTM responder functionality; -1 for no change 1108 1079 * (which also implies no change in LCI/civic location data) 1109 1080 * @lci: Measurement Report element content, starting with Measurement Token ··· 1122 1091 const u8 *probe_resp; 1123 1092 const u8 *lci; 1124 1093 const u8 *civicloc; 1094 + struct cfg80211_mbssid_elems *mbssid_ies; 1125 1095 s8 ftm_responder; 1126 1096 1127 1097 size_t head_len, tail_len; ··· 1237 1205 * @he_oper: HE operation IE (or %NULL if HE isn't enabled) 1238 1206 * @fils_discovery: FILS discovery transmission parameters 1239 1207 * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters 1208 + * @mbssid_config: AP settings for multiple bssid 1240 1209 */ 1241 1210 struct cfg80211_ap_settings { 1242 1211 struct cfg80211_chan_def chandef; ··· 1270 1237 struct cfg80211_he_bss_color he_bss_color; 1271 1238 struct cfg80211_fils_discovery fils_discovery; 1272 1239 struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; 1240 + struct cfg80211_mbssid_config mbssid_config; 1273 1241 }; 1274 1242 1275 1243 /** ··· 5037 5003 * %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes 5038 5004 * @sar_capa: SAR control capabilities 5039 5005 * @rfkill: a pointer to the rfkill structure 5006 + * 5007 + * @mbssid_max_interfaces: maximum number of interfaces supported by the driver 5008 + * in a multiple BSSID set. This field must be set to a non-zero value 5009 + * by the driver to advertise MBSSID support. 5010 + * @mbssid_max_ema_profile_periodicity: maximum profile periodicity supported by 5011 + * the driver. Setting this field to a non-zero value indicates that the 5012 + * driver supports enhanced multi-BSSID advertisements (EMA AP). 5040 5013 */ 5041 5014 struct wiphy { 5042 5015 struct mutex mtx; ··· 5187 5146 const struct cfg80211_sar_capa *sar_capa; 5188 5147 5189 5148 struct rfkill *rfkill; 5149 + 5150 + u8 mbssid_max_interfaces; 5151 + u8 ema_max_profile_periodicity; 5190 5152 5191 5153 char priv[] __aligned(NETDEV_ALIGN); 5192 5154 };
+75 -1
include/uapi/linux/nl80211.h
··· 360 360 * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes 361 361 * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from 362 362 * userspace to request deletion of a virtual interface, then requires 363 - * attribute %NL80211_ATTR_IFINDEX. 363 + * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are 364 + * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, 365 + * and if this command is used for the transmitting interface, then all 366 + * the non-transmitting interfaces are deleted as well. 364 367 * 365 368 * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified 366 369 * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. ··· 2627 2624 * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE 2628 2625 * information for the time while performing a color switch. 2629 2626 * 2627 + * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID 2628 + * advertisements (MBSSID) parameters in AP mode. 2629 + * Kernel uses this attribute to indicate the driver's support for MBSSID 2630 + * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. 2631 + * Userspace should use this attribute to configure per interface MBSSID 2632 + * parameters. 2633 + * See &enum nl80211_mbssid_config_attributes for details. 2634 + * 2635 + * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. 2636 + * Mandatory parameter for the transmitting interface to enable MBSSID. 2637 + * Optional for the non-transmitting interfaces. 2638 + * 2630 2639 * @NUM_NL80211_ATTR: total number of nl80211_attrs available 2631 2640 * @NL80211_ATTR_MAX: highest attribute number currently defined 2632 2641 * @__NL80211_ATTR_AFTER_LAST: internal use ··· 3141 3126 NL80211_ATTR_COLOR_CHANGE_COUNT, 3142 3127 NL80211_ATTR_COLOR_CHANGE_COLOR, 3143 3128 NL80211_ATTR_COLOR_CHANGE_ELEMS, 3129 + 3130 + NL80211_ATTR_MBSSID_CONFIG, 3131 + NL80211_ATTR_MBSSID_ELEMS, 3144 3132 3145 3133 /* add attributes here, update the policy in nl80211.c */ 3146 3134 ··· 7402 7384 7403 7385 __NL80211_SAR_ATTR_SPECS_LAST, 7404 7386 NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, 7387 + }; 7388 + 7389 + /** 7390 + * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced 7391 + * multi-BSSID advertisements (EMA) in AP mode. 7392 + * Kernel uses some of these attributes to advertise driver's support for 7393 + * MBSSID and EMA. 7394 + * Remaining attributes should be used by the userspace to configure the 7395 + * features. 7396 + * 7397 + * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid 7398 + * 7399 + * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise 7400 + * the maximum number of MBSSID interfaces supported by the driver. 7401 + * Driver should indicate MBSSID support by setting 7402 + * wiphy->mbssid_max_interfaces to a value more than or equal to 2. 7403 + * 7404 + * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel 7405 + * to advertise the maximum profile periodicity supported by the driver 7406 + * if EMA is enabled. Driver should indicate EMA support to the userspace 7407 + * by setting wiphy->mbssid_max_ema_profile_periodicity to 7408 + * a non-zero value. 7409 + * 7410 + * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of 7411 + * this BSS (u8) in the multiple BSSID set. 7412 + * Value must be set to 0 for the transmitting interface and non-zero for 7413 + * all non-transmitting interfaces. The userspace will be responsible 7414 + * for using unique indices for the interfaces. 7415 + * Range: 0 to wiphy->mbssid_max_interfaces-1. 7416 + * 7417 + * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for 7418 + * a non-transmitted profile which provides the interface index (u32) of 7419 + * the transmitted profile. The value must match one of the interface 7420 + * indices advertised by the kernel. Optional if the interface being set up 7421 + * is the transmitting one, however, if provided then the value must match 7422 + * the interface index of the same. 7423 + * 7424 + * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. 7425 + * Setting this flag is permitted only if the driver advertises EMA support 7426 + * by setting wiphy->mbssid_max_ema_profile_periodicity to non-zero. 7427 + * 7428 + * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal 7429 + * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute 7430 + */ 7431 + enum nl80211_mbssid_config_attributes { 7432 + __NL80211_MBSSID_CONFIG_ATTR_INVALID, 7433 + 7434 + NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, 7435 + NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, 7436 + NL80211_MBSSID_CONFIG_ATTR_INDEX, 7437 + NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, 7438 + NL80211_MBSSID_CONFIG_ATTR_EMA, 7439 + 7440 + /* keep last */ 7441 + __NL80211_MBSSID_CONFIG_ATTR_LAST, 7442 + NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, 7405 7443 }; 7406 7444 7407 7445 #endif /* __LINUX_NL80211_H */
+174 -4
net/wireless/nl80211.c
··· 437 437 [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), 438 438 }; 439 439 440 + static const struct nla_policy 441 + nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = { 442 + [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2), 443 + [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] = 444 + NLA_POLICY_MIN(NLA_U8, 1), 445 + [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 }, 446 + [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 }, 447 + [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG }, 448 + }; 449 + 440 450 static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { 441 451 [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, 442 452 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, ··· 773 763 [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, 774 764 [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, 775 765 [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), 766 + [NL80211_ATTR_MBSSID_CONFIG] = 767 + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), 768 + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, 776 769 }; 777 770 778 771 /* policy for the key attributes */ ··· 2220 2207 return -ENOBUFS; 2221 2208 } 2222 2209 2210 + static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg) 2211 + { 2212 + struct nlattr *config; 2213 + 2214 + if (!wiphy->mbssid_max_interfaces) 2215 + return 0; 2216 + 2217 + config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); 2218 + if (!config) 2219 + return -ENOBUFS; 2220 + 2221 + if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, 2222 + wiphy->mbssid_max_interfaces)) 2223 + goto fail; 2224 + 2225 + if (wiphy->ema_max_profile_periodicity && 2226 + nla_put_u8(msg, 2227 + NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, 2228 + wiphy->ema_max_profile_periodicity)) 2229 + goto fail; 2230 + 2231 + nla_nest_end(msg, config); 2232 + return 0; 2233 + 2234 + fail: 2235 + nla_nest_cancel(msg, config); 2236 + return -ENOBUFS; 2237 + } 2238 + 2223 2239 struct nl80211_dump_wiphy_state { 2224 2240 s64 filter_wiphy; 2225 2241 long start; ··· 2832 2790 break; 2833 2791 case 16: 2834 2792 if (nl80211_put_sar_specs(rdev, msg)) 2793 + goto nla_put_failure; 2794 + 2795 + if (nl80211_put_mbssid_support(&rdev->wiphy, msg)) 2835 2796 goto nla_put_failure; 2836 2797 2837 2798 /* done */ ··· 5026 4981 return 0; 5027 4982 } 5028 4983 4984 + static int nl80211_parse_mbssid_config(struct wiphy *wiphy, 4985 + struct net_device *dev, 4986 + struct nlattr *attrs, 4987 + struct cfg80211_mbssid_config *config, 4988 + u8 num_elems) 4989 + { 4990 + struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; 4991 + 4992 + if (!wiphy->mbssid_max_interfaces) 4993 + return -EOPNOTSUPP; 4994 + 4995 + if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL, 4996 + NULL) || 4997 + !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]) 4998 + return -EINVAL; 4999 + 5000 + config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]); 5001 + if (config->ema) { 5002 + if (!wiphy->ema_max_profile_periodicity) 5003 + return -EOPNOTSUPP; 5004 + 5005 + if (num_elems > wiphy->ema_max_profile_periodicity) 5006 + return -EINVAL; 5007 + } 5008 + 5009 + config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]); 5010 + if (config->index >= wiphy->mbssid_max_interfaces || 5011 + (!config->index && !num_elems)) 5012 + return -EINVAL; 5013 + 5014 + if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) { 5015 + u32 tx_ifindex = 5016 + nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]); 5017 + 5018 + if ((!config->index && tx_ifindex != dev->ifindex) || 5019 + (config->index && tx_ifindex == dev->ifindex)) 5020 + return -EINVAL; 5021 + 5022 + if (tx_ifindex != dev->ifindex) { 5023 + struct net_device *tx_netdev = 5024 + dev_get_by_index(wiphy_net(wiphy), tx_ifindex); 5025 + 5026 + if (!tx_netdev || !tx_netdev->ieee80211_ptr || 5027 + tx_netdev->ieee80211_ptr->wiphy != wiphy || 5028 + tx_netdev->ieee80211_ptr->iftype != 5029 + NL80211_IFTYPE_AP) { 5030 + dev_put(tx_netdev); 5031 + return -EINVAL; 5032 + } 5033 + 5034 + config->tx_wdev = tx_netdev->ieee80211_ptr; 5035 + } else { 5036 + config->tx_wdev = dev->ieee80211_ptr; 5037 + } 5038 + } else if (!config->index) { 5039 + config->tx_wdev = dev->ieee80211_ptr; 5040 + } else { 5041 + return -EINVAL; 5042 + } 5043 + 5044 + return 0; 5045 + } 5046 + 5047 + static struct cfg80211_mbssid_elems * 5048 + nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) 5049 + { 5050 + struct nlattr *nl_elems; 5051 + struct cfg80211_mbssid_elems *elems; 5052 + int rem_elems; 5053 + u8 i = 0, num_elems = 0; 5054 + 5055 + if (!wiphy->mbssid_max_interfaces) 5056 + return ERR_PTR(-EINVAL); 5057 + 5058 + nla_for_each_nested(nl_elems, attrs, rem_elems) 5059 + num_elems++; 5060 + 5061 + elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL); 5062 + if (!elems) 5063 + return ERR_PTR(-ENOMEM); 5064 + 5065 + nla_for_each_nested(nl_elems, attrs, rem_elems) { 5066 + elems->elem[i].data = nla_data(nl_elems); 5067 + elems->elem[i].len = nla_len(nl_elems); 5068 + i++; 5069 + } 5070 + elems->cnt = num_elems; 5071 + return elems; 5072 + } 5073 + 5029 5074 static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, 5030 5075 struct nlattr *attrs[], 5031 5076 struct cfg80211_beacon_data *bcn) ··· 5194 5059 } 5195 5060 } else { 5196 5061 bcn->ftm_responder = -1; 5062 + } 5063 + 5064 + if (attrs[NL80211_ATTR_MBSSID_ELEMS]) { 5065 + struct cfg80211_mbssid_elems *mbssid = 5066 + nl80211_parse_mbssid_elems(&rdev->wiphy, 5067 + attrs[NL80211_ATTR_MBSSID_ELEMS]); 5068 + 5069 + if (IS_ERR(mbssid)) 5070 + return PTR_ERR(mbssid); 5071 + 5072 + bcn->mbssid_ies = mbssid; 5197 5073 } 5198 5074 5199 5075 return 0; ··· 5693 5547 goto out; 5694 5548 } 5695 5549 5550 + if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) { 5551 + err = nl80211_parse_mbssid_config(&rdev->wiphy, dev, 5552 + info->attrs[NL80211_ATTR_MBSSID_CONFIG], 5553 + &params->mbssid_config, 5554 + params->beacon.mbssid_ies ? 5555 + params->beacon.mbssid_ies->cnt : 5556 + 0); 5557 + if (err) 5558 + goto out; 5559 + } 5560 + 5696 5561 nl80211_calculate_ap_params(params); 5697 5562 5698 5563 if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) ··· 5725 5568 5726 5569 out: 5727 5570 kfree(params->acl); 5571 + kfree(params->beacon.mbssid_ies); 5572 + if (params->mbssid_config.tx_wdev && 5573 + params->mbssid_config.tx_wdev->netdev && 5574 + params->mbssid_config.tx_wdev->netdev != dev) 5575 + dev_put(params->mbssid_config.tx_wdev->netdev); 5728 5576 kfree(params); 5729 5577 5730 5578 return err; ··· 5755 5593 5756 5594 err = nl80211_parse_beacon(rdev, info->attrs, &params); 5757 5595 if (err) 5758 - return err; 5596 + goto out; 5759 5597 5760 5598 wdev_lock(wdev); 5761 5599 err = rdev_change_beacon(rdev, dev, &params); 5762 5600 wdev_unlock(wdev); 5763 5601 5602 + out: 5603 + kfree(params.mbssid_ies); 5764 5604 return err; 5765 5605 } 5766 5606 ··· 9439 9275 9440 9276 err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after); 9441 9277 if (err) 9442 - return err; 9278 + goto free; 9443 9279 9444 9280 csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs), 9445 9281 GFP_KERNEL); 9446 - if (!csa_attrs) 9447 - return -ENOMEM; 9282 + if (!csa_attrs) { 9283 + err = -ENOMEM; 9284 + goto free; 9285 + } 9448 9286 9449 9287 err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX, 9450 9288 info->attrs[NL80211_ATTR_CSA_IES], ··· 9564 9398 wdev_unlock(wdev); 9565 9399 9566 9400 free: 9401 + kfree(params.beacon_after.mbssid_ies); 9402 + kfree(params.beacon_csa.mbssid_ies); 9567 9403 kfree(csa_attrs); 9568 9404 return err; 9569 9405 } ··· 15101 14933 wdev_unlock(wdev); 15102 14934 15103 14935 out: 14936 + kfree(params.beacon_next.mbssid_ies); 14937 + kfree(params.beacon_color_change.mbssid_ies); 15104 14938 kfree(tb); 15105 14939 return err; 15106 14940 }