@@ -1538,7 +1538,7 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
u32 params = 0;
u8 i = 0;
- tx_arvif = ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
+ tx_arvif = ath11k_vif_to_arvif(arvif->vif->bss_conf.mbssid_tx_vif);
beacons = ieee80211_beacon_get_template_ema_list(tx_arvif->ar->hw,
tx_arvif->vif, 0);
@@ -1596,8 +1596,8 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
struct sk_buff *bcn;
int ret;
- if (vif->mbssid_tx_vif) {
- tx_arvif = ath11k_vif_to_arvif(vif->mbssid_tx_vif);
+ if (vif->bss_conf.mbssid_tx_vif) {
+ tx_arvif = ath11k_vif_to_arvif(vif->bss_conf.mbssid_tx_vif);
if (tx_arvif != arvif) {
ar = tx_arvif->ar;
ab = ar->ab;
@@ -1639,11 +1639,11 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
/* Target does not expect beacon templates for the already up
* non-transmitting interfaces, and results in a crash if sent.
*/
- if (vif->mbssid_tx_vif &&
- arvif != ath11k_vif_to_arvif(vif->mbssid_tx_vif) && arvif->is_up)
+ if (vif->bss_conf.mbssid_tx_vif &&
+ arvif != ath11k_vif_to_arvif(vif->bss_conf.mbssid_tx_vif) && arvif->is_up)
return 0;
- if (vif->bss_conf.ema_ap && vif->mbssid_tx_vif)
+ if (vif->bss_conf.ema_ap && vif->bss_conf.mbssid_tx_vif)
return ath11k_mac_setup_bcn_tmpl_ema(arvif);
return ath11k_mac_setup_bcn_tmpl_mbssid(arvif);
@@ -1703,8 +1703,8 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif,
ether_addr_copy(arvif->bssid, info->bssid);
- if (arvif->vif->mbssid_tx_vif)
- tx_arvif = ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
+ if (arvif->vif->bss_conf.mbssid_tx_vif)
+ tx_arvif = ath11k_vif_to_arvif(arvif->vif->bss_conf.mbssid_tx_vif);
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid,
@@ -6334,7 +6334,7 @@ static int ath11k_mac_setup_vdev_params_mbssid(struct ath11k_vif *arvif,
struct ieee80211_vif *tx_vif;
*tx_vdev_id = 0;
- tx_vif = arvif->vif->mbssid_tx_vif;
+ tx_vif = arvif->vif->bss_conf.mbssid_tx_vif;
if (!tx_vif) {
*flags = WMI_HOST_VDEV_FLAGS_NON_MBSSID_AP;
return 0;
@@ -7350,7 +7350,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
ret);
- mbssid_tx_vif = arvif->vif->mbssid_tx_vif;
+ mbssid_tx_vif = arvif->vif->bss_conf.mbssid_tx_vif;
if (mbssid_tx_vif)
tx_arvif = ath11k_vif_to_arvif(mbssid_tx_vif);
@@ -1480,7 +1480,7 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif)
int ret = 0;
u8 i;
- tx_arvif = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
+ tx_arvif = ath12k_vif_to_arvif(arvif->vif->bss_conf.mbssid_tx_vif);
beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar),
tx_arvif->vif, 0);
if (!beacons || !beacons->cnt) {
@@ -1534,8 +1534,8 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
return 0;
- if (vif->mbssid_tx_vif) {
- tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif);
+ if (vif->bss_conf.mbssid_tx_vif) {
+ tx_arvif = ath12k_vif_to_arvif(vif->bss_conf.mbssid_tx_vif);
if (tx_arvif != arvif && arvif->is_up)
return 0;
@@ -1629,8 +1629,9 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif,
params.vdev_id = arvif->vdev_id;
params.aid = arvif->aid;
params.bssid = arvif->bssid;
- if (arvif->vif->mbssid_tx_vif) {
- params.tx_bssid = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif)->bssid;
+ if (arvif->vif->bss_conf.mbssid_tx_vif) {
+ params.tx_bssid =
+ ath12k_vif_to_arvif(arvif->vif->bss_conf.mbssid_tx_vif)->bssid;
params.nontx_profile_idx = info->bssid_index;
params.nontx_profile_cnt = 1 << info->bssid_indicator;
}
@@ -6225,7 +6226,7 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif,
u32 *flags, u32 *tx_vdev_id)
{
- struct ieee80211_vif *tx_vif = arvif->vif->mbssid_tx_vif;
+ struct ieee80211_vif *tx_vif = arvif->vif->bss_conf.mbssid_tx_vif;
struct ath12k *ar = arvif->ar;
struct ath12k_vif *tx_arvif;
@@ -7486,8 +7487,9 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
params.vdev_id = arvif->vdev_id;
params.aid = arvif->aid;
params.bssid = arvif->bssid;
- if (vif->mbssid_tx_vif) {
- params.tx_bssid = ath12k_vif_to_arvif(vif->mbssid_tx_vif)->bssid;
+ if (vif->bss_conf.mbssid_tx_vif) {
+ params.tx_bssid =
+ ath12k_vif_to_arvif(vif->bss_conf.mbssid_tx_vif)->bssid;
params.nontx_profile_idx = vif->bss_conf.bssid_index;
params.nontx_profile_cnt = 1 << vif->bss_conf.bssid_indicator;
}
@@ -2290,7 +2290,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
vif->type != NL80211_IFTYPE_OCB)
return;
- if (vif->mbssid_tx_vif && vif->mbssid_tx_vif != vif)
+ if (link_conf->mbssid_tx_vif && link_conf->mbssid_tx_vif != vif)
return;
if (vif->bss_conf.ema_ap) {
@@ -682,6 +682,8 @@ struct ieee80211_parsed_tpe {
* responder functionality.
* @ftmr_params: configurable lci/civic parameter when enabling FTM responder.
* @nontransmitted: this BSS is a nontransmitted BSS profile
+ * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
+ * @mbssid_tx_vif_linkid: Link id of Tx link for non-Tx link.
* @transmitter_bssid: the address of transmitter AP
* @bssid_index: index inside the multiple BSSID set
* @bssid_indicator: 2^bssid_indicator is the maximum number of APs in set
@@ -790,6 +792,8 @@ struct ieee80211_bss_conf {
struct ieee80211_ftm_responder_params *ftmr_params;
/* Multiple BSSID data */
bool nontransmitted;
+ struct ieee80211_vif *mbssid_tx_vif;
+ int mbssid_tx_vif_linkid;
u8 transmitter_bssid[ETH_ALEN];
u8 bssid_index;
u8 bssid_indicator;
@@ -2004,7 +2008,6 @@ enum ieee80211_neg_ttlm_res {
* @txq: the multicast data TX queue
* @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
* &enum ieee80211_offload_flags.
- * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
*/
struct ieee80211_vif {
enum nl80211_iftype type;
@@ -2032,8 +2035,6 @@ struct ieee80211_vif {
bool probe_req_reg;
bool rx_mcast_action_reg;
- struct ieee80211_vif *mbssid_tx_vif;
-
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
@@ -142,8 +142,10 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *link_conf)
{
struct ieee80211_sub_if_data *tx_sdata;
+ struct ieee80211_link_data *tx_link;
- sdata->vif.mbssid_tx_vif = NULL;
+ link_conf->mbssid_tx_vif = NULL;
+ link_conf->mbssid_tx_vif_linkid = -1;
link_conf->bssid_index = 0;
link_conf->nontransmitted = false;
link_conf->ema_ap = false;
@@ -157,9 +159,25 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
return -EINVAL;
if (tx_sdata == sdata) {
- sdata->vif.mbssid_tx_vif = &sdata->vif;
+ link_conf->mbssid_tx_vif = &sdata->vif;
+ link_conf->mbssid_tx_vif_linkid = link_conf->link_id;
} else {
- sdata->vif.mbssid_tx_vif = &tx_sdata->vif;
+ rcu_read_lock();
+ tx_link = rcu_dereference(tx_sdata->link[params.tx_link_id]);
+ if (!tx_link || !tx_link->conf) {
+ rcu_read_unlock();
+ return -ENOLINK;
+ }
+ /* Make sure input tx vif from user is really configured as a
+ * transmitting vif as per our internal data before referring it.
+ */
+ if (tx_link->conf->mbssid_tx_vif != &tx_sdata->vif) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ link_conf->mbssid_tx_vif = &tx_sdata->vif;
+ link_conf->mbssid_tx_vif_linkid = tx_link->link_id;
+ rcu_read_unlock();
link_conf->nontransmitted = true;
link_conf->bssid_index = params.index;
}
@@ -1641,7 +1659,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
kfree(link_conf->ftmr_params);
link_conf->ftmr_params = NULL;
- sdata->vif.mbssid_tx_vif = NULL;
link_conf->bssid_index = 0;
link_conf->nontransmitted = false;
link_conf->ema_ap = false;
@@ -1655,6 +1672,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
ieee80211_free_key_list(local, &keys);
}
+ ieee80211_stop_mbssid(sdata);
+ link_conf->mbssid_tx_vif = NULL;
+ link_conf->mbssid_tx_vif_linkid = -1;
link_conf->enable_beacon = false;
sdata->beacon_rate_set = false;
sdata->vif.cfg.ssid_len = 0;
@@ -3636,23 +3656,41 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id)
return;
}
- /* TODO: MBSSID with MLO changes */
- if (vif->mbssid_tx_vif == vif) {
+ if (link_data->conf->mbssid_tx_vif == vif &&
+ link_data->conf->mbssid_tx_vif_linkid == link_data->conf->link_id) {
/* Trigger ieee80211_csa_finish() on the non-transmitting
* interfaces when channel switch is received on
* transmitting interface
*/
struct ieee80211_sub_if_data *iter;
+ struct ieee80211_link_data *link_iter;
+ unsigned int link_id_iter;
+ unsigned long valid_links;
list_for_each_entry_rcu(iter, &local->interfaces, list) {
if (!ieee80211_sdata_running(iter))
continue;
- if (iter == sdata || iter->vif.mbssid_tx_vif != vif)
+ if (iter == sdata)
continue;
- wiphy_work_queue(iter->local->hw.wiphy,
- &iter->deflink.csa.finalize_work);
+ /* check link 0 by default for Non-ML non-tx vif's deflinks */
+ valid_links = iter->vif.valid_links | BIT(0);
+ for_each_set_bit(link_id_iter, &valid_links,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ link_iter = rcu_dereference(iter->link[link_id_iter]);
+ if (!link_iter)
+ continue;
+ /* Check if any of link of iterator sdata belongs
+ * to same mbssid group as the tx link
+ */
+ if (link_iter->conf->mbssid_tx_vif != vif ||
+ link_iter->conf->mbssid_tx_vif_linkid != link_data->link_id)
+ continue;
+
+ wiphy_work_queue(iter->local->hw.wiphy,
+ &link_iter->csa.finalize_work);
+ }
}
}
wiphy_work_queue(local->hw.wiphy, &link_data->csa.finalize_work);
@@ -4757,15 +4795,35 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_link_data *link,
ieee80211_link_info_change_notify(sdata, link, changed);
- if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) {
+ if (!link->conf->nontransmitted && link->conf->mbssid_tx_vif) {
struct ieee80211_sub_if_data *child;
+ unsigned int link_id_iter;
+ unsigned long valid_links;
+ struct ieee80211_link_data *link_iter;
list_for_each_entry(child, &sdata->local->interfaces, list) {
- if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) {
- child->vif.bss_conf.he_bss_color.color = color;
- child->vif.bss_conf.he_bss_color.enabled = enable;
+ if (child == sdata)
+ continue;
+
+ /* check deflink by default */
+ valid_links = child->vif.valid_links | BIT(0);
+ for_each_set_bit(link_id_iter, &valid_links,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ link_iter = sdata_dereference(child->link[link_id_iter],
+ child);
+ if (!link_iter)
+ continue;
+ /* Check if any of link of iterator sdata belongs
+ * to same mbssid group as the tx link
+ */
+ if (link_iter->conf->mbssid_tx_vif != &sdata->vif ||
+ link_iter->conf->mbssid_tx_vif_linkid != link->link_id)
+ continue;
+
+ link_iter->conf->he_bss_color.color = color;
+ link_iter->conf->he_bss_color.enabled = enable;
ieee80211_link_info_change_notify(child,
- &child->deflink,
+ link_iter,
BSS_CHANGED_HE_BSS_COLOR);
}
}
@@ -2708,6 +2708,7 @@ int ieee80211_req_neg_ttlm(struct ieee80211_sub_if_data *sdata,
void ieee80211_check_wbrf_support(struct ieee80211_local *local);
void ieee80211_add_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef);
void ieee80211_remove_wbrf(struct ieee80211_local *local, struct cfg80211_chan_def *chandef);
+void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata);
#if IS_ENABLED(CONFIG_MAC80211_KUNIT_TEST)
#define EXPORT_SYMBOL_IF_MAC80211_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym)
@@ -717,30 +717,80 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
ieee80211_add_virtual_monitor(local);
}
-static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
+void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata;
- struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif;
+ struct ieee80211_vif *tx_vif;
+ unsigned int link_id, tx_link_id, iter_link_id;
+ unsigned long iter_valid_links, valid_links;
+ struct ieee80211_link_data *link_iter, *link;
- if (!tx_vif)
- return;
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+ /* Check link 0 by default for non MLO. */
+ iter_valid_links = sdata->vif.valid_links | BIT(0);
+ /* Check if any of the links of current sdata is an MBSSID. */
+ for_each_set_bit(iter_link_id, &iter_valid_links,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ link_iter = sdata_dereference(sdata->link[iter_link_id], sdata);
+ if (!link_iter)
+ continue;
+
+ tx_link_id = link_iter->conf->mbssid_tx_vif_linkid;
+ tx_vif = link_iter->conf->mbssid_tx_vif;
+ if (!tx_vif)
+ continue;
- tx_sdata = vif_to_sdata(tx_vif);
- sdata->vif.mbssid_tx_vif = NULL;
+ tx_sdata = vif_to_sdata(tx_vif);
+ link_iter->conf->mbssid_tx_vif = NULL;
- list_for_each_entry_safe(non_tx_sdata, tmp_sdata,
- &tx_sdata->local->interfaces, list) {
- if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata &&
- non_tx_sdata->vif.mbssid_tx_vif == tx_vif &&
- ieee80211_sdata_running(non_tx_sdata)) {
- non_tx_sdata->vif.mbssid_tx_vif = NULL;
- dev_close(non_tx_sdata->wdev.netdev);
+ /* If we are not tx sdata reset tx sdata's tx_vif to avoid recusrion while
+ * closing tx sdata at the end of outer loop below.
+ */
+ if (sdata != tx_sdata) {
+ link = sdata_dereference(tx_sdata->link[tx_link_id], tx_sdata);
+ if (!link)
+ continue;
+ link->conf->mbssid_tx_vif = NULL;
+ }
+
+ /* loop through sdatas to find if any of their links
+ * belong to same mbssid group as the one getting deleted.
+ */
+ list_for_each_entry_safe(non_tx_sdata, tmp_sdata,
+ &tx_sdata->local->interfaces, list) {
+ if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata &&
+ ieee80211_sdata_running(non_tx_sdata)) {
+ valid_links = non_tx_sdata->vif.valid_links | BIT(0);
+ for_each_set_bit(link_id, &valid_links,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ link = sdata_dereference(non_tx_sdata->link[link_id],
+ non_tx_sdata);
+ if (!link)
+ continue;
+
+ /* If both tx vif and tx linkid is matching then it belongs
+ * to same MBSSID group.
+ */
+ if (link->conf->mbssid_tx_vif != tx_vif ||
+ link->conf->mbssid_tx_vif_linkid != tx_link_id)
+ continue;
+
+ link->conf->mbssid_tx_vif = NULL;
+
+ /* Remove all links of matching MLD until dynamic link
+ * removal can be supported.
+ */
+ cfg80211_stop_iface(non_tx_sdata->wdev.wiphy,
+ &non_tx_sdata->wdev, GFP_KERNEL);
+ }
+ }
}
- }
- if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) {
- tx_sdata->vif.mbssid_tx_vif = NULL;
- dev_close(tx_sdata->wdev.netdev);
+ /* If we are not tx sdata, remove links of tx sdata and proceed.
+ */
+ if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata))
+ cfg80211_stop_iface(tx_sdata->wdev.wiphy,
+ &tx_sdata->wdev, GFP_KERNEL);
}
}
@@ -748,20 +798,24 @@ static int ieee80211_stop(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- /* close dependent VLAN and MBSSID interfaces before locking wiphy */
+ /* close dependent VLAN interfaces before locking wiphy */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
-
- ieee80211_stop_mbssid(sdata);
}
wiphy_lock(sdata->local->hw.wiphy);
wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->activate_links_work);
+ /* Close the dependent MBSSID interfaces with wiphy lock as we may be terminating
+ * its partner links too in case of MLD.
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ ieee80211_stop_mbssid(sdata);
+
ieee80211_do_stop(sdata, true);
wiphy_unlock(sdata->local->hw.wiphy);
@@ -1581,7 +1581,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work)
container_of(work, struct wireless_dev, disconnect_wk);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
- wiphy_lock(wdev->wiphy);
+ wiphy_lock(&rdev->wiphy);
if (wdev->conn_owner_nlportid) {
switch (wdev->iftype) {
@@ -1618,5 +1618,5 @@ void cfg80211_autodisconnect_wk(struct work_struct *work)
}
}
- wiphy_unlock(wdev->wiphy);
+ wiphy_unlock(&rdev->wiphy);
}