aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--net/mac80211/chan.c697
1 files changed, 419 insertions, 278 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 76fc36a68750..e72cf0749d49 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* mac80211 - channel management
- * Copyright 2020 - 2021 Intel Corporation
+ * Copyright 2020 - 2022 Intel Corporation
*/
#include <linux/nl80211.h>
@@ -15,12 +15,12 @@
static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
int num = 0;
lockdep_assert_held(&local->chanctx_mtx);
- list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+ list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list)
num++;
return num;
@@ -29,12 +29,12 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
int num = 0;
lockdep_assert_held(&local->chanctx_mtx);
- list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+ list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
num++;
return num;
@@ -67,12 +67,12 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
}
static struct ieee80211_chanctx *
-ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata)
+ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
{
- struct ieee80211_local *local __maybe_unused = sdata->local;
+ struct ieee80211_local *local __maybe_unused = link->sdata->local;
struct ieee80211_chanctx_conf *conf;
- conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf)
return NULL;
@@ -85,16 +85,16 @@ ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *compat)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
lockdep_assert_held(&local->chanctx_mtx);
- list_for_each_entry(sdata, &ctx->reserved_vifs,
+ list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
if (!compat)
- compat = &sdata->reserved_chandef;
+ compat = &link->reserved_chandef;
- compat = cfg80211_chandef_compatible(&sdata->reserved_chandef,
+ compat = cfg80211_chandef_compatible(&link->reserved_chandef,
compat);
if (!compat)
break;
@@ -108,20 +108,22 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *compat)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
lockdep_assert_held(&local->chanctx_mtx);
- list_for_each_entry(sdata, &ctx->assigned_vifs,
+ list_for_each_entry(link, &ctx->assigned_links,
assigned_chanctx_list) {
- if (sdata->reserved_chanctx != NULL)
+ struct ieee80211_bss_conf *link_conf = link->conf;
+
+ if (link->reserved_chanctx)
continue;
if (!compat)
- compat = &sdata->vif.bss_conf.chandef;
+ compat = &link_conf->chandef;
compat = cfg80211_chandef_compatible(
- &sdata->vif.bss_conf.chandef, compat);
+ &link_conf->chandef, compat);
if (!compat)
break;
}
@@ -157,7 +159,7 @@ ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
if (ieee80211_chanctx_combined_chandef(local, ctx, def))
return true;
- if (!list_empty(&ctx->reserved_vifs) &&
+ if (!list_empty(&ctx->reserved_links) &&
ieee80211_chanctx_reserved_chandef(local, ctx, def))
return true;
@@ -193,13 +195,23 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
return NULL;
}
-static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta)
+static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
+ unsigned int link_id)
{
- enum ieee80211_sta_rx_bandwidth width = ieee80211_sta_cap_rx_bw(sta);
+ enum ieee80211_sta_rx_bandwidth width;
+ struct link_sta_info *link_sta;
+
+ link_sta = rcu_dereference(sta->link[link_id]);
+
+ /* no effect if this STA has no presence on this link */
+ if (!link_sta)
+ return NL80211_CHAN_WIDTH_20_NOHT;
+
+ width = ieee80211_sta_cap_rx_bw(link_sta);
switch (width) {
case IEEE80211_STA_RX_BW_20:
- if (sta->sta.ht_cap.ht_supported)
+ if (link_sta->pub->ht_cap.ht_supported)
return NL80211_CHAN_WIDTH_20;
else
return NL80211_CHAN_WIDTH_20_NOHT;
@@ -218,6 +230,8 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta)
* might be smaller than the configured bw (160).
*/
return NL80211_CHAN_WIDTH_160;
+ case IEEE80211_STA_RX_BW_320:
+ return NL80211_CHAN_WIDTH_320;
default:
WARN_ON(1);
return NL80211_CHAN_WIDTH_20;
@@ -225,46 +239,47 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta)
}
static enum nl80211_chan_width
-ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
+ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
+ unsigned int link_id)
{
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
struct sta_info *sta;
- rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
if (sdata != sta->sdata &&
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
continue;
- max_bw = max(max_bw, ieee80211_get_sta_bw(sta));
+ max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id));
}
- rcu_read_unlock();
return max_bw;
}
static enum nl80211_chan_width
-ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
- struct ieee80211_chanctx_conf *conf)
+ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx_conf *conf)
{
- struct ieee80211_sub_if_data *sdata;
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+ struct ieee80211_vif *vif = &sdata->vif;
+ int link_id;
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- struct ieee80211_vif *vif = &sdata->vif;
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
+ struct ieee80211_bss_conf *link_conf =
+ rcu_dereference(sdata->vif.link_conf[link_id]);
- if (!ieee80211_sdata_running(sdata))
+ if (!link_conf)
continue;
- if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
+ if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
continue;
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
- width = ieee80211_get_max_required_bw(sdata);
+ width = ieee80211_get_max_required_bw(sdata, link_id);
break;
case NL80211_IFTYPE_STATION:
/*
@@ -272,8 +287,8 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
* point, so take the width from the chandef, but
* account also for TDLS peers
*/
- width = max(vif->bss_conf.chandef.width,
- ieee80211_get_max_required_bw(sdata));
+ width = max(link_conf->chandef.width,
+ ieee80211_get_max_required_bw(sdata, link_id));
break;
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_NAN:
@@ -281,7 +296,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
- width = vif->bss_conf.chandef.width;
+ width = link_conf->chandef.width;
break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_UNSPECIFIED:
@@ -291,12 +306,37 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
case NL80211_IFTYPE_P2P_GO:
WARN_ON_ONCE(1);
}
+
+ max_bw = max(max_bw, width);
+ }
+ rcu_read_unlock();
+
+ return max_bw;
+}
+
+static enum nl80211_chan_width
+ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
+ struct ieee80211_chanctx_conf *conf)
+{
+ struct ieee80211_sub_if_data *sdata;
+ enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ enum nl80211_chan_width width;
+
+ if (!ieee80211_sdata_running(sdata))
+ continue;
+
+ width = ieee80211_get_chanctx_vif_max_required_bw(sdata, conf);
+
max_bw = max(max_bw, width);
}
/* use the configured bandwidth in case of monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
- if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf)
+ if (sdata &&
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf)
max_bw = max(max_bw, conf->def.width);
rcu_read_unlock();
@@ -348,7 +388,7 @@ static u32 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
}
/* calling this function is assuming that station vif is updated to
- * lates changes by calling ieee80211_vif_update_chandef
+ * lates changes by calling ieee80211_link_update_chandef
*/
static void ieee80211_chan_bw_change(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
@@ -361,29 +401,43 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list,
list) {
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
enum ieee80211_sta_rx_bandwidth new_sta_bw;
+ unsigned int link_id;
if (!ieee80211_sdata_running(sta->sdata))
continue;
- if (rcu_access_pointer(sta->sdata->vif.chanctx_conf) !=
- &ctx->conf)
- continue;
+ for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
+ struct ieee80211_bss_conf *link_conf =
+ rcu_dereference(sdata->vif.link_conf[link_id]);
+ struct link_sta_info *link_sta;
- new_sta_bw = ieee80211_sta_cur_vht_bw(sta);
+ if (!link_conf)
+ continue;
- /* nothing change */
- if (new_sta_bw == sta->sta.bandwidth)
- continue;
+ if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
+ continue;
- /* vif changed to narrow BW and narrow BW for station wasn't
- * requested or vise versa */
- if ((new_sta_bw < sta->sta.bandwidth) == !narrowed)
- continue;
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
+ continue;
+
+ new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta);
+
+ /* nothing change */
+ if (new_sta_bw == link_sta->pub->bandwidth)
+ continue;
+
+ /* vif changed to narrow BW and narrow BW for station wasn't
+ * requested or vise versa */
+ if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
+ continue;
- sta->sta.bandwidth = new_sta_bw;
- rate_control_rate_update(local, sband, sta,
- IEEE80211_RC_BW_CHANGED);
+ link_sta->pub->bandwidth = new_sta_bw;
+ rate_control_rate_update(local, sband, sta, link_id,
+ IEEE80211_RC_BW_CHANGED);
+ }
}
rcu_read_unlock();
}
@@ -417,7 +471,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
{
u32 changed;
- /* expected to handle only 20/40/80/160 channel widths */
+ /* expected to handle only 20/40/80/160/320 channel widths */
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
@@ -425,6 +479,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
+ case NL80211_CHAN_WIDTH_320:
break;
default:
WARN_ON(1);
@@ -505,9 +560,17 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (sdata->radar_required) {
- rcu_read_unlock();
- return true;
+ unsigned int link_id;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
+ struct ieee80211_link_data *link;
+
+ link = rcu_dereference(sdata->link[link_id]);
+
+ if (link && link->radar_required) {
+ rcu_read_unlock();
+ return true;
+ }
}
}
rcu_read_unlock();
@@ -528,15 +591,27 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local,
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ unsigned int link_id;
+
if (!ieee80211_sdata_running(sdata))
continue;
- if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
- continue;
- if (!sdata->radar_required)
- continue;
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
+ struct ieee80211_link_data *link;
- required = true;
- break;
+ link = rcu_dereference(sdata->link[link_id]);
+ if (!link)
+ continue;
+
+ if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
+ continue;
+ if (!link->radar_required)
+ continue;
+ required = true;
+ break;
+ }
+
+ if (required)
+ break;
}
rcu_read_unlock();
@@ -556,8 +631,8 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
if (!ctx)
return NULL;
- INIT_LIST_HEAD(&ctx->assigned_vifs);
- INIT_LIST_HEAD(&ctx->reserved_vifs);
+ INIT_LIST_HEAD(&ctx->assigned_links);
+ INIT_LIST_HEAD(&ctx->reserved_links);
ctx->conf.def = *chandef;
ctx->conf.rx_chains_static = 1;
ctx->conf.rx_chains_dynamic = 1;
@@ -683,21 +758,32 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ int link_id;
if (!ieee80211_sdata_running(sdata))
continue;
- if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
- continue;
+
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
- if (!compat)
- compat = &sdata->vif.bss_conf.chandef;
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
+ struct ieee80211_bss_conf *link_conf =
+ rcu_dereference(sdata->vif.link_conf[link_id]);
- compat = cfg80211_chandef_compatible(
- &sdata->vif.bss_conf.chandef, compat);
- if (WARN_ON_ONCE(!compat))
- break;
+ if (!link_conf)
+ continue;
+
+ if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
+ continue;
+
+ if (!compat)
+ compat = &link_conf->chandef;
+
+ compat = cfg80211_chandef_compatible(&link_conf->chandef,
+ compat);
+ if (WARN_ON_ONCE(!compat))
+ break;
+ }
}
/* TDLS peers can sometimes affect the chandef width */
@@ -745,9 +831,10 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
}
-static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_chanctx *new_ctx)
+static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
+ struct ieee80211_chanctx *new_ctx)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *curr_ctx = NULL;
@@ -756,31 +843,31 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
return -ENOTSUPP;
- conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ conf = rcu_dereference_protected(link->conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (conf) {
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
- drv_unassign_vif_chanctx(local, sdata, curr_ctx);
+ drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
conf = NULL;
- list_del(&sdata->assigned_chanctx_list);
+ list_del(&link->assigned_chanctx_list);
}
if (new_ctx) {
- ret = drv_assign_vif_chanctx(local, sdata, new_ctx);
+ ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
if (ret)
goto out;
conf = &new_ctx->conf;
- list_add(&sdata->assigned_chanctx_list,
- &new_ctx->assigned_vifs);
+ list_add(&link->assigned_chanctx_list,
+ &new_ctx->assigned_links);
}
out:
- rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
+ rcu_assign_pointer(link->conf->chanctx_conf, conf);
- sdata->vif.bss_conf.idle = !conf;
+ sdata->vif.cfg.idle = !conf;
if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
ieee80211_recalc_chanctx_chantype(local, curr_ctx);
@@ -796,8 +883,7 @@ out:
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
sdata->vif.type != NL80211_IFTYPE_MONITOR)
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_IDLE);
+ ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE);
ieee80211_check_fast_xmit_iface(sdata);
@@ -818,60 +904,64 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
u8 needed_static, needed_dynamic;
+ unsigned int link_id;
if (!ieee80211_sdata_running(sdata))
continue;
- if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
- &chanctx->conf)
- continue;
-
switch (sdata->vif.type) {
- case NL80211_IFTYPE_P2P_DEVICE:
- case NL80211_IFTYPE_NAN:
- continue;
case NL80211_IFTYPE_STATION:
if (!sdata->u.mgd.associated)
continue;
break;
- case NL80211_IFTYPE_AP_VLAN:
- continue;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
break;
default:
- WARN_ON_ONCE(1);
+ continue;
}
- switch (sdata->smps_mode) {
- default:
- WARN_ONCE(1, "Invalid SMPS mode %d\n",
- sdata->smps_mode);
- fallthrough;
- case IEEE80211_SMPS_OFF:
- needed_static = sdata->needed_rx_chains;
- needed_dynamic = sdata->needed_rx_chains;
- break;
- case IEEE80211_SMPS_DYNAMIC:
- needed_static = 1;
- needed_dynamic = sdata->needed_rx_chains;
- break;
- case IEEE80211_SMPS_STATIC:
- needed_static = 1;
- needed_dynamic = 1;
- break;
- }
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
+ struct ieee80211_link_data *link;
+
+ link = rcu_dereference(sdata->link[link_id]);
+
+ if (!link)
+ continue;
+
+ if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
+ continue;
- rx_chains_static = max(rx_chains_static, needed_static);
- rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
+ switch (link->smps_mode) {
+ default:
+ WARN_ONCE(1, "Invalid SMPS mode %d\n",
+ link->smps_mode);
+ fallthrough;
+ case IEEE80211_SMPS_OFF:
+ needed_static = link->needed_rx_chains;
+ needed_dynamic = link->needed_rx_chains;
+ break;
+ case IEEE80211_SMPS_DYNAMIC:
+ needed_static = 1;
+ needed_dynamic = link->needed_rx_chains;
+ break;
+ case IEEE80211_SMPS_STATIC:
+ needed_static = 1;
+ needed_dynamic = 1;
+ break;
+ }
+
+ rx_chains_static = max(rx_chains_static, needed_static);
+ rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
+ }
}
/* Disable SMPS for the monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
if (sdata &&
- rcu_access_pointer(sdata->vif.chanctx_conf) == &chanctx->conf)
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
rx_chains_dynamic = rx_chains_static = local->rx_chains;
rcu_read_unlock();
@@ -896,9 +986,12 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
}
static void
-__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
- bool clear)
+__ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
+ bool clear)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ unsigned int link_id = link->link_id;
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local __maybe_unused = sdata->local;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_chanctx_conf *conf;
@@ -914,40 +1007,50 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
* channel context pointer for a while, possibly pointing
* to a channel context that has already been freed.
*/
- conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ conf = rcu_dereference_protected(link_conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
WARN_ON(!conf);
if (clear)
conf = NULL;
- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
- rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
+ rcu_read_lock();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ struct ieee80211_bss_conf *vlan_conf;
+
+ vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]);
+ if (WARN_ON(!vlan_conf))
+ continue;
+
+ rcu_assign_pointer(vlan_conf->chanctx_conf, conf);
+ }
+ rcu_read_unlock();
}
-void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
- bool clear)
+void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
+ bool clear)
{
- struct ieee80211_local *local = sdata->local;
+ struct ieee80211_local *local = link->sdata->local;
mutex_lock(&local->chanctx_mtx);
- __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear);
+ __ieee80211_link_copy_chanctx_to_vlans(link, clear);
mutex_unlock(&local->chanctx_mtx);
}
-int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
+int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
{
- struct ieee80211_chanctx *ctx = sdata->reserved_chanctx;
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_chanctx *ctx = link->reserved_chanctx;
lockdep_assert_held(&sdata->local->chanctx_mtx);
if (WARN_ON(!ctx))
return -EINVAL;
- list_del(&sdata->reserved_chanctx_list);
- sdata->reserved_chanctx = NULL;
+ list_del(&link->reserved_chanctx_list);
+ link->reserved_chanctx = NULL;
if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
@@ -972,17 +1075,18 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
return 0;
}
-int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
- const struct cfg80211_chan_def *chandef,
- enum ieee80211_chanctx_mode mode,
- bool radar_required)
+int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
+ const struct cfg80211_chan_def *chandef,
+ enum ieee80211_chanctx_mode mode,
+ bool radar_required)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
lockdep_assert_held(&local->chanctx_mtx);
- curr_ctx = ieee80211_vif_get_chanctx(sdata);
+ curr_ctx = ieee80211_link_get_chanctx(link);
if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx)
return -ENOTSUPP;
@@ -996,11 +1100,11 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
if (!curr_ctx ||
(curr_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
- !list_empty(&curr_ctx->reserved_vifs)) {
+ !list_empty(&curr_ctx->reserved_links)) {
/*
- * Another vif already requested this context
+ * Another link already requested this context
* for a reservation. Find another one hoping
- * all vifs assigned to it will also switch
+ * all links assigned to it will also switch
* soon enough.
*
* TODO: This needs a little more work as some
@@ -1009,13 +1113,13 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
* provided some channel context juggling was
* performed.
*
- * Consider ctx1..3, vif1..6, each ctx has 2
- * vifs. vif1 and vif2 from ctx1 request new
+ * Consider ctx1..3, link1..6, each ctx has 2
+ * links. link1 and link2 from ctx1 request new
* different chandefs starting 2 in-place
* reserations with ctx4 and ctx5 replacing
- * ctx1 and ctx2 respectively. Next vif5 and
- * vif6 from ctx3 reserve ctx4. If vif3 and
- * vif4 remain on ctx2 as they are then this
+ * ctx1 and ctx2 respectively. Next link5 and
+ * link6 from ctx3 reserve ctx4. If link3 and
+ * link4 remain on ctx2 as they are then this
* fails unless `replace_ctx` from ctx5 is
* replaced with ctx3.
*/
@@ -1025,7 +1129,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
IEEE80211_CHANCTX_REPLACE_NONE)
continue;
- if (!list_empty(&ctx->reserved_vifs))
+ if (!list_empty(&ctx->reserved_links))
continue;
curr_ctx = ctx;
@@ -1040,7 +1144,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
if (!curr_ctx ||
(curr_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
- !list_empty(&curr_ctx->reserved_vifs))
+ !list_empty(&curr_ctx->reserved_links))
return -EBUSY;
new_ctx = ieee80211_alloc_chanctx(local, chandef, mode);
@@ -1059,29 +1163,31 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
}
}
- list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
- sdata->reserved_chanctx = new_ctx;
- sdata->reserved_chandef = *chandef;
- sdata->reserved_radar_required = radar_required;
- sdata->reserved_ready = false;
+ list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
+ link->reserved_chanctx = new_ctx;
+ link->reserved_chandef = *chandef;
+ link->reserved_radar_required = radar_required;
+ link->reserved_ready = false;
return 0;
}
static void
-ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
+ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+
switch (sdata->vif.type) {
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
ieee80211_queue_work(&sdata->local->hw,
- &sdata->csa_finalize_work);
+ &link->csa_finalize_work);
break;
case NL80211_IFTYPE_STATION:
ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.mgd.chswitch_work);
+ &link->u.mgd.chswitch_work);
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_AP_VLAN:
@@ -1098,23 +1204,36 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
}
static void
-ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata,
- const struct cfg80211_chan_def *chandef)
+ieee80211_link_update_chandef(struct ieee80211_link_data *link,
+ const struct cfg80211_chan_def *chandef)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ unsigned int link_id = link->link_id;
struct ieee80211_sub_if_data *vlan;
- sdata->vif.bss_conf.chandef = *chandef;
+ link->conf->chandef = *chandef;
if (sdata->vif.type != NL80211_IFTYPE_AP)
return;
- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
- vlan->vif.bss_conf.chandef = *chandef;
+ rcu_read_lock();
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+ struct ieee80211_bss_conf *vlan_conf;
+
+ vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]);
+ if (WARN_ON(!vlan_conf))
+ continue;
+
+ vlan_conf->chandef = *chandef;
+ }
+ rcu_read_unlock();
}
static int
-ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
+ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
struct ieee80211_chanctx *old_ctx, *new_ctx;
@@ -1125,10 +1244,10 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
lockdep_assert_held(&local->mtx);
lockdep_assert_held(&local->chanctx_mtx);
- new_ctx = sdata->reserved_chanctx;
- old_ctx = ieee80211_vif_get_chanctx(sdata);
+ new_ctx = link->reserved_chanctx;
+ old_ctx = ieee80211_link_get_chanctx(link);
- if (WARN_ON(!sdata->reserved_ready))
+ if (WARN_ON(!link->reserved_ready))
return -EBUSY;
if (WARN_ON(!new_ctx))
@@ -1142,23 +1261,24 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
return -EINVAL;
chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
- &sdata->reserved_chandef);
+ &link->reserved_chandef);
if (WARN_ON(!chandef))
return -EINVAL;
- if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
+ if (link_conf->chandef.width != link->reserved_chandef.width)
changed = BSS_CHANGED_BANDWIDTH;
- ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
+ ieee80211_link_update_chandef(link, &link->reserved_chandef);
ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef);
vif_chsw[0].vif = &sdata->vif;
vif_chsw[0].old_ctx = &old_ctx->conf;
vif_chsw[0].new_ctx = &new_ctx->conf;
+ vif_chsw[0].link_conf = link->conf;
- list_del(&sdata->reserved_chanctx_list);
- sdata->reserved_chanctx = NULL;
+ list_del(&link->reserved_chanctx_list);
+ link->reserved_chanctx = NULL;
err = drv_switch_vif_chanctx(local, vif_chsw, 1,
CHANCTX_SWMODE_REASSIGN_VIF);
@@ -1169,11 +1289,11 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
goto out;
}
- list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs);
- rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf);
+ list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
+ rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
if (sdata->vif.type == NL80211_IFTYPE_AP)
- __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
+ __ieee80211_link_copy_chanctx_to_vlans(link, false);
ieee80211_check_fast_xmit_iface(sdata);
@@ -1185,25 +1305,26 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
ieee80211_recalc_radar_chanctx(local, new_ctx);
if (changed)
- ieee80211_bss_info_change_notify(sdata, changed);
+ ieee80211_link_info_change_notify(sdata, link, changed);
out:
- ieee80211_vif_chanctx_reservation_complete(sdata);
+ ieee80211_link_chanctx_reservation_complete(link);
return err;
}
static int
-ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
+ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *old_ctx, *new_ctx;
const struct cfg80211_chan_def *chandef;
int err;
- old_ctx = ieee80211_vif_get_chanctx(sdata);
- new_ctx = sdata->reserved_chanctx;
+ old_ctx = ieee80211_link_get_chanctx(link);
+ new_ctx = link->reserved_chanctx;
- if (WARN_ON(!sdata->reserved_ready))
+ if (WARN_ON(!link->reserved_ready))
return -EINVAL;
if (WARN_ON(old_ctx))
@@ -1217,16 +1338,16 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
return -EINVAL;
chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
- &sdata->reserved_chandef);
+ &link->reserved_chandef);
if (WARN_ON(!chandef))
return -EINVAL;
ieee80211_change_chanctx(local, new_ctx, new_ctx, chandef);
- list_del(&sdata->reserved_chanctx_list);
- sdata->reserved_chanctx = NULL;
+ list_del(&link->reserved_chanctx_list);
+ link->reserved_chanctx = NULL;
- err = ieee80211_assign_vif_chanctx(sdata, new_ctx);
+ err = ieee80211_assign_link_chanctx(link, new_ctx);
if (err) {
if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
ieee80211_free_chanctx(local, new_ctx);
@@ -1235,19 +1356,20 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
}
out:
- ieee80211_vif_chanctx_reservation_complete(sdata);
+ ieee80211_link_chanctx_reservation_complete(link);
return err;
}
static bool
-ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata)
+ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_chanctx *old_ctx, *new_ctx;
lockdep_assert_held(&sdata->local->chanctx_mtx);
- new_ctx = sdata->reserved_chanctx;
- old_ctx = ieee80211_vif_get_chanctx(sdata);
+ new_ctx = link->reserved_chanctx;
+ old_ctx = ieee80211_link_get_chanctx(link);
if (!old_ctx)
return false;
@@ -1287,7 +1409,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
int n_vifs)
{
struct ieee80211_vif_chanctx_switch *vif_chsw;
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
struct ieee80211_chanctx *ctx, *old_ctx;
int i, err;
@@ -1308,16 +1430,16 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
goto out;
}
- list_for_each_entry(sdata, &ctx->reserved_vifs,
+ list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
- if (!ieee80211_vif_has_in_place_reservation(
- sdata))
+ if (!ieee80211_link_has_in_place_reservation(link))
continue;
- old_ctx = ieee80211_vif_get_chanctx(sdata);
- vif_chsw[i].vif = &sdata->vif;
+ old_ctx = ieee80211_link_get_chanctx(link);
+ vif_chsw[i].vif = &link->sdata->vif;
vif_chsw[i].old_ctx = &old_ctx->conf;
vif_chsw[i].new_ctx = &ctx->conf;
+ vif_chsw[i].link_conf = link->conf;
i++;
}
@@ -1343,7 +1465,7 @@ static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
- if (!list_empty(&ctx->replace_ctx->assigned_vifs))
+ if (!list_empty(&ctx->replace_ctx->assigned_links))
continue;
ieee80211_del_chanctx(local, ctx->replace_ctx);
@@ -1360,7 +1482,7 @@ err:
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
- if (!list_empty(&ctx->replace_ctx->assigned_vifs))
+ if (!list_empty(&ctx->replace_ctx->assigned_links))
continue;
ieee80211_del_chanctx(local, ctx);
@@ -1372,7 +1494,6 @@ err:
static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
{
- struct ieee80211_sub_if_data *sdata, *sdata_tmp;
struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
struct ieee80211_chanctx *new_ctx = NULL;
int err, n_assigned, n_reserved, n_ready;
@@ -1398,6 +1519,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
*/
list_for_each_entry(ctx, &local->chanctx_list, list) {
+ struct ieee80211_link_data *link;
+
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
@@ -1415,12 +1538,12 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
n_reserved = 0;
n_ready = 0;
- list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs,
+ list_for_each_entry(link, &ctx->replace_ctx->assigned_links,
assigned_chanctx_list) {
n_assigned++;
- if (sdata->reserved_chanctx) {
+ if (link->reserved_chanctx) {
n_reserved++;
- if (sdata->reserved_ready)
+ if (link->reserved_ready)
n_ready++;
}
}
@@ -1437,13 +1560,13 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
}
ctx->conf.radar_enabled = false;
- list_for_each_entry(sdata, &ctx->reserved_vifs,
+ list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
- if (ieee80211_vif_has_in_place_reservation(sdata) &&
- !sdata->reserved_ready)
+ if (ieee80211_link_has_in_place_reservation(link) &&
+ !link->reserved_ready)
return -EAGAIN;
- old_ctx = ieee80211_vif_get_chanctx(sdata);
+ old_ctx = ieee80211_link_get_chanctx(link);
if (old_ctx) {
if (old_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED)
@@ -1454,7 +1577,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
n_vifs_ctxless++;
}
- if (sdata->reserved_radar_required)
+ if (link->reserved_radar_required)
ctx->conf.radar_enabled = true;
}
}
@@ -1497,6 +1620,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
* context(s).
*/
list_for_each_entry(ctx, &local->chanctx_list, list) {
+ struct ieee80211_link_data *link, *link_tmp;
+
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
@@ -1505,31 +1630,34 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
goto err;
}
- list_for_each_entry(sdata, &ctx->reserved_vifs,
+ list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_bss_conf *link_conf = link->conf;
u32 changed = 0;
- if (!ieee80211_vif_has_in_place_reservation(sdata))
+ if (!ieee80211_link_has_in_place_reservation(link))
continue;
- rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
+ rcu_assign_pointer(link_conf->chanctx_conf,
+ &ctx->conf);
if (sdata->vif.type == NL80211_IFTYPE_AP)
- __ieee80211_vif_copy_chanctx_to_vlans(sdata,
- false);
+ __ieee80211_link_copy_chanctx_to_vlans(link,
+ false);
ieee80211_check_fast_xmit_iface(sdata);
- sdata->radar_required = sdata->reserved_radar_required;
+ link->radar_required = link->reserved_radar_required;
- if (sdata->vif.bss_conf.chandef.width !=
- sdata->reserved_chandef.width)
+ if (link_conf->chandef.width != link->reserved_chandef.width)
changed = BSS_CHANGED_BANDWIDTH;
- ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
+ ieee80211_link_update_chandef(link, &link->reserved_chandef);
if (changed)
- ieee80211_bss_info_change_notify(sdata,
- changed);
+ ieee80211_link_info_change_notify(sdata,
+ link,
+ changed);
ieee80211_recalc_txpower(sdata, false);
}
@@ -1539,17 +1667,17 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
- list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
+ list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
- if (ieee80211_vif_get_chanctx(sdata) != ctx)
+ if (ieee80211_link_get_chanctx(link) != ctx)
continue;
- list_del(&sdata->reserved_chanctx_list);
- list_move(&sdata->assigned_chanctx_list,
- &ctx->assigned_vifs);
- sdata->reserved_chanctx = NULL;
+ list_del(&link->reserved_chanctx_list);
+ list_move(&link->assigned_chanctx_list,
+ &ctx->assigned_links);
+ link->reserved_chanctx = NULL;
- ieee80211_vif_chanctx_reservation_complete(sdata);
+ ieee80211_link_chanctx_reservation_complete(link);
}
/*
@@ -1559,31 +1687,29 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
* reservation for originally requested interface has already
* succeeded at this point.
*/
- list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
+ list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
- if (WARN_ON(ieee80211_vif_has_in_place_reservation(
- sdata)))
+ if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
continue;
- if (WARN_ON(sdata->reserved_chanctx != ctx))
+ if (WARN_ON(link->reserved_chanctx != ctx))
continue;
- if (!sdata->reserved_ready)
+ if (!link->reserved_ready)
continue;
- if (ieee80211_vif_get_chanctx(sdata))
- err = ieee80211_vif_use_reserved_reassign(
- sdata);
+ if (ieee80211_link_get_chanctx(link))
+ err = ieee80211_link_use_reserved_reassign(link);
else
- err = ieee80211_vif_use_reserved_assign(sdata);
+ err = ieee80211_link_use_reserved_assign(link);
if (err) {
- sdata_info(sdata,
- "failed to finalize (re-)assign reservation (err=%d)\n",
- err);
- ieee80211_vif_unreserve_chanctx(sdata);
+ link_info(link,
+ "failed to finalize (re-)assign reservation (err=%d)\n",
+ err);
+ ieee80211_link_unreserve_chanctx(link);
cfg80211_stop_iface(local->hw.wiphy,
- &sdata->wdev,
+ &link->sdata->wdev,
GFP_KERNEL);
}
}
@@ -1609,21 +1735,25 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
err:
list_for_each_entry(ctx, &local->chanctx_list, list) {
+ struct ieee80211_link_data *link, *link_tmp;
+
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
- list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
+ list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
- ieee80211_vif_unreserve_chanctx(sdata);
- ieee80211_vif_chanctx_reservation_complete(sdata);
+ ieee80211_link_unreserve_chanctx(link);
+ ieee80211_link_chanctx_reservation_complete(link);
}
}
return err;
}
-static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+static void __ieee80211_link_release_channel(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
@@ -1631,38 +1761,37 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
lockdep_assert_held(&local->chanctx_mtx);
- conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ conf = rcu_dereference_protected(link_conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf)
return;
ctx = container_of(conf, struct ieee80211_chanctx, conf);
- if (sdata->reserved_chanctx) {
- if (sdata->reserved_chanctx->replace_state ==
- IEEE80211_CHANCTX_REPLACES_OTHER &&
- ieee80211_chanctx_num_reserved(local,
- sdata->reserved_chanctx) > 1)
+ if (link->reserved_chanctx) {
+ if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
+ ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1)
use_reserved_switch = true;
- ieee80211_vif_unreserve_chanctx(sdata);
+ ieee80211_link_unreserve_chanctx(link);
}
- ieee80211_assign_vif_chanctx(sdata, NULL);
+ ieee80211_assign_link_chanctx(link, NULL);
if (ieee80211_chanctx_refcount(local, ctx) == 0)
ieee80211_free_chanctx(local, ctx);
- sdata->radar_required = false;
+ link->radar_required = false;
/* Unreserving may ready an in-place reservation. */
if (use_reserved_switch)
ieee80211_vif_use_reserved_switch(local);
}
-int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
- const struct cfg80211_chan_def *chandef,
- enum ieee80211_chanctx_mode mode)
+int ieee80211_link_use_channel(struct ieee80211_link_data *link,
+ const struct cfg80211_chan_def *chandef,
+ enum ieee80211_chanctx_mode mode)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
u8 radar_detect_width = 0;
@@ -1670,7 +1799,11 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&local->mtx);
- WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
+ if (sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(link->link_id))) {
+ ieee80211_link_update_chandef(link, chandef);
+ return 0;
+ }
mutex_lock(&local->chanctx_mtx);
@@ -1682,14 +1815,14 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
if (ret > 0)
radar_detect_width = BIT(chandef->width);
- sdata->radar_required = ret;
+ link->radar_required = ret;
ret = ieee80211_check_combinations(sdata, chandef, mode,
radar_detect_width);
if (ret < 0)
goto out;
- __ieee80211_vif_release_channel(sdata);
+ __ieee80211_link_release_channel(link);
ctx = ieee80211_find_chanctx(local, chandef, mode);
if (!ctx)
@@ -1699,9 +1832,9 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
goto out;
}
- ieee80211_vif_update_chandef(sdata, chandef);
+ ieee80211_link_update_chandef(link, chandef);
- ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+ ret = ieee80211_assign_link_chanctx(link, ctx);
if (ret) {
/* if assign fails refcount stays the same */
if (ieee80211_chanctx_refcount(local, ctx) == 0)
@@ -1713,14 +1846,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_radar_chanctx(local, ctx);
out:
if (ret)
- sdata->radar_required = false;
+ link->radar_required = false;
mutex_unlock(&local->chanctx_mtx);
return ret;
}
-int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
+int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *new_ctx;
struct ieee80211_chanctx *old_ctx;
@@ -1729,8 +1863,8 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
lockdep_assert_held(&local->mtx);
lockdep_assert_held(&local->chanctx_mtx);
- new_ctx = sdata->reserved_chanctx;
- old_ctx = ieee80211_vif_get_chanctx(sdata);
+ new_ctx = link->reserved_chanctx;
+ old_ctx = ieee80211_link_get_chanctx(link);
if (WARN_ON(!new_ctx))
return -EINVAL;
@@ -1739,19 +1873,16 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
IEEE80211_CHANCTX_WILL_BE_REPLACED))
return -EINVAL;
- if (WARN_ON(sdata->reserved_ready))
+ if (WARN_ON(link->reserved_ready))
return -EINVAL;
- sdata->reserved_ready = true;
+ link->reserved_ready = true;
if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
if (old_ctx)
- err = ieee80211_vif_use_reserved_reassign(sdata);
- else
- err = ieee80211_vif_use_reserved_assign(sdata);
+ return ieee80211_link_use_reserved_reassign(link);
- if (err)
- return err;
+ return ieee80211_link_use_reserved_assign(link);
}
/*
@@ -1783,10 +1914,12 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
return 0;
}
-int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
- const struct cfg80211_chan_def *chandef,
- u32 *changed)
+int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
+ const struct cfg80211_chan_def *chandef,
+ u32 *changed)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_bss_conf *link_conf = link->conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
@@ -1798,18 +1931,18 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
return -EINVAL;
mutex_lock(&local->chanctx_mtx);
- if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) {
+ if (cfg80211_chandef_identical(chandef, &link_conf->chandef)) {
ret = 0;
goto out;
}
if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
- sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
+ link_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
ret = -EINVAL;
goto out;
}
- conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ conf = rcu_dereference_protected(link_conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf) {
ret = -EINVAL;
@@ -1844,7 +1977,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
break;
}
- ieee80211_vif_update_chandef(sdata, chandef);
+ ieee80211_link_update_chandef(link, chandef);
ieee80211_recalc_chanctx_chantype(local, ctx);
@@ -1855,19 +1988,24 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
return ret;
}
-void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+void ieee80211_link_release_channel(struct ieee80211_link_data *link)
{
- WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
-
- lockdep_assert_held(&sdata->local->mtx);
+ struct ieee80211_sub_if_data *sdata = link->sdata;
mutex_lock(&sdata->local->chanctx_mtx);
- __ieee80211_vif_release_channel(sdata);
+ if (rcu_access_pointer(link->conf->chanctx_conf)) {
+ lockdep_assert_held(&sdata->local->mtx);
+ __ieee80211_link_release_channel(link);
+ }
mutex_unlock(&sdata->local->chanctx_mtx);
}
-void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
+void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)
{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ unsigned int link_id = link->link_id;
+ struct ieee80211_bss_conf *link_conf = link->conf;
+ struct ieee80211_bss_conf *ap_conf;
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *ap;
struct ieee80211_chanctx_conf *conf;
@@ -1879,9 +2017,12 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
mutex_lock(&local->chanctx_mtx);
- conf = rcu_dereference_protected(ap->vif.chanctx_conf,
+ rcu_read_lock();
+ ap_conf = rcu_dereference(ap->vif.link_conf[link_id]);
+ conf = rcu_dereference_protected(ap_conf->chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
- rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
+ rcu_assign_pointer(link_conf->chanctx_conf, conf);
+ rcu_read_unlock();
mutex_unlock(&local->chanctx_mtx);
}