wifi: mac80211: isolate driver from inactive links
In order to let the driver select active links and properly make multi-link connections, as a first step isolate the driver from inactive links, and set the active links to be only the association link for client-side interfaces. For AP side nothing changes since APs always have to have all their links active. To simplify things, update the for_each_sta_active_link() API to include the appropriate vif pointer. This also implies not allocating a chanctx for an inactive link, which requires a few more changes. Since we now no longer try to program multiple links to the driver, remove the check in the MLME code. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
261ce88795
commit
efe9c2bfd1
@ -1799,6 +1799,9 @@ struct ieee80211_vif_cfg {
|
|||||||
* @link_conf: in case of MLD, the per-link BSS configuration,
|
* @link_conf: in case of MLD, the per-link BSS configuration,
|
||||||
* indexed by link ID
|
* indexed by link ID
|
||||||
* @valid_links: bitmap of valid links, or 0 for non-MLO.
|
* @valid_links: bitmap of valid links, or 0 for non-MLO.
|
||||||
|
* @active_links: The bitmap of active links, or 0 for non-MLO.
|
||||||
|
* The driver shouldn't change this directly, but use the
|
||||||
|
* API calls meant for that purpose.
|
||||||
* @addr: address of this interface
|
* @addr: address of this interface
|
||||||
* @p2p: indicates whether this AP or STA interface is a p2p
|
* @p2p: indicates whether this AP or STA interface is a p2p
|
||||||
* interface, i.e. a GO or p2p-sta respectively
|
* interface, i.e. a GO or p2p-sta respectively
|
||||||
@ -1834,7 +1837,7 @@ struct ieee80211_vif {
|
|||||||
struct ieee80211_vif_cfg cfg;
|
struct ieee80211_vif_cfg cfg;
|
||||||
struct ieee80211_bss_conf bss_conf;
|
struct ieee80211_bss_conf bss_conf;
|
||||||
struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
|
struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||||
u16 valid_links;
|
u16 valid_links, active_links;
|
||||||
u8 addr[ETH_ALEN] __aligned(2);
|
u8 addr[ETH_ALEN] __aligned(2);
|
||||||
bool p2p;
|
bool p2p;
|
||||||
|
|
||||||
@ -1861,12 +1864,11 @@ struct ieee80211_vif {
|
|||||||
u8 drv_priv[] __aligned(sizeof(void *));
|
u8 drv_priv[] __aligned(sizeof(void *));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FIXME: for now loop over all the available links; later will be changed
|
#define for_each_vif_active_link(vif, link, link_id) \
|
||||||
* to loop only over the active links.
|
for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \
|
||||||
*/
|
if ((!(vif)->active_links || \
|
||||||
#define for_each_vif_active_link(vif, link, link_id) \
|
(vif)->active_links & BIT(link_id)) && \
|
||||||
for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \
|
(link = rcu_dereference((vif)->link_conf[link_id])))
|
||||||
if ((link = rcu_dereference((vif)->link_conf[link_id])))
|
|
||||||
|
|
||||||
static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
|
static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
@ -2264,13 +2266,13 @@ struct ieee80211_sta {
|
|||||||
u8 drv_priv[] __aligned(sizeof(void *));
|
u8 drv_priv[] __aligned(sizeof(void *));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FIXME: need to loop only over links which are active and check the actual
|
/* FIXME: check the locking correctly */
|
||||||
* lock
|
#define for_each_sta_active_link(vif, sta, link_sta, link_id) \
|
||||||
*/
|
for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \
|
||||||
#define for_each_sta_active_link(sta, link_sta, link_id) \
|
if ((!(vif)->active_links || \
|
||||||
for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \
|
(vif)->active_links & BIT(link_id)) && \
|
||||||
if (((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
|
((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
|
||||||
1))) \
|
1)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum sta_notify_cmd - sta notify command
|
* enum sta_notify_cmd - sta notify command
|
||||||
|
@ -1799,6 +1799,12 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,
|
|||||||
|
|
||||||
lockdep_assert_held(&local->mtx);
|
lockdep_assert_held(&local->mtx);
|
||||||
|
|
||||||
|
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);
|
mutex_lock(&local->chanctx_mtx);
|
||||||
|
|
||||||
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
|
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
|
||||||
|
@ -192,6 +192,10 @@ int drv_conf_tx(struct ieee80211_local *local,
|
|||||||
if (!check_sdata_in_driver(sdata))
|
if (!check_sdata_in_driver(sdata))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
if (sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(link->link_id)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (params->cw_min == 0 || params->cw_min > params->cw_max) {
|
if (params->cw_min == 0 || params->cw_min > params->cw_max) {
|
||||||
/*
|
/*
|
||||||
* If we can't configure hardware anyway, don't warn. We may
|
* If we can't configure hardware anyway, don't warn. We may
|
||||||
@ -272,6 +276,60 @@ void drv_reset_tsf(struct ieee80211_local *local,
|
|||||||
trace_drv_return_void(local);
|
trace_drv_return_void(local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int drv_assign_vif_chanctx(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_bss_conf *link_conf,
|
||||||
|
struct ieee80211_chanctx *ctx)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
drv_verify_link_exists(sdata, link_conf);
|
||||||
|
if (!check_sdata_in_driver(sdata))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(link_conf->link_id)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
|
||||||
|
if (local->ops->assign_vif_chanctx) {
|
||||||
|
WARN_ON_ONCE(!ctx->driver_present);
|
||||||
|
ret = local->ops->assign_vif_chanctx(&local->hw,
|
||||||
|
&sdata->vif,
|
||||||
|
link_conf,
|
||||||
|
&ctx->conf);
|
||||||
|
}
|
||||||
|
trace_drv_return_int(local, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_unassign_vif_chanctx(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_bss_conf *link_conf,
|
||||||
|
struct ieee80211_chanctx *ctx)
|
||||||
|
{
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
drv_verify_link_exists(sdata, link_conf);
|
||||||
|
if (!check_sdata_in_driver(sdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(link_conf->link_id)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
|
||||||
|
if (local->ops->unassign_vif_chanctx) {
|
||||||
|
WARN_ON_ONCE(!ctx->driver_present);
|
||||||
|
local->ops->unassign_vif_chanctx(&local->hw,
|
||||||
|
&sdata->vif,
|
||||||
|
link_conf,
|
||||||
|
&ctx->conf);
|
||||||
|
}
|
||||||
|
trace_drv_return_void(local);
|
||||||
|
}
|
||||||
|
|
||||||
int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
||||||
struct ieee80211_vif_chanctx_switch *vifs,
|
struct ieee80211_vif_chanctx_switch *vifs,
|
||||||
int n_vifs, enum ieee80211_chanctx_switch_mode mode)
|
int n_vifs, enum ieee80211_chanctx_switch_mode mode)
|
||||||
@ -346,3 +404,117 @@ int drv_ampdu_action(struct ieee80211_local *local,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drv_link_info_changed(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_bss_conf *info,
|
||||||
|
int link_id, u64 changed)
|
||||||
|
{
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
|
||||||
|
BSS_CHANGED_BEACON_ENABLED) &&
|
||||||
|
sdata->vif.type != NL80211_IFTYPE_AP &&
|
||||||
|
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||||
|
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
||||||
|
sdata->vif.type != NL80211_IFTYPE_OCB))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
|
||||||
|
sdata->vif.type == NL80211_IFTYPE_NAN ||
|
||||||
|
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||||
|
!sdata->vif.bss_conf.mu_mimo_owner &&
|
||||||
|
!(changed & BSS_CHANGED_TXPOWER))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!check_sdata_in_driver(sdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(link_id)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
trace_drv_link_info_changed(local, sdata, info, changed);
|
||||||
|
if (local->ops->link_info_changed)
|
||||||
|
local->ops->link_info_changed(&local->hw, &sdata->vif,
|
||||||
|
info, changed);
|
||||||
|
else if (local->ops->bss_info_changed)
|
||||||
|
local->ops->bss_info_changed(&local->hw, &sdata->vif,
|
||||||
|
info, changed);
|
||||||
|
trace_drv_return_void(local);
|
||||||
|
}
|
||||||
|
|
||||||
|
int drv_set_key(struct ieee80211_local *local,
|
||||||
|
enum set_key_cmd cmd,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
struct ieee80211_key_conf *key)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
sdata = get_bss_sdata(sdata);
|
||||||
|
if (!check_sdata_in_driver(sdata))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(key->link_id))))
|
||||||
|
return -ENOLINK;
|
||||||
|
|
||||||
|
trace_drv_set_key(local, cmd, sdata, sta, key);
|
||||||
|
ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
|
||||||
|
trace_drv_return_int(local, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drv_change_vif_links(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
u16 old_links, u16 new_links,
|
||||||
|
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
|
||||||
|
{
|
||||||
|
int ret = -EOPNOTSUPP;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
if (!check_sdata_in_driver(sdata))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (old_links == new_links)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
trace_drv_change_vif_links(local, sdata, old_links, new_links);
|
||||||
|
if (local->ops->change_vif_links)
|
||||||
|
ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
|
||||||
|
old_links, new_links, old);
|
||||||
|
trace_drv_return_int(local, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drv_change_sta_links(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
u16 old_links, u16 new_links)
|
||||||
|
{
|
||||||
|
int ret = -EOPNOTSUPP;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
if (!check_sdata_in_driver(sdata))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
old_links &= sdata->vif.active_links;
|
||||||
|
new_links &= sdata->vif.active_links;
|
||||||
|
|
||||||
|
if (old_links == new_links)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
|
||||||
|
if (local->ops->change_sta_links)
|
||||||
|
ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
|
||||||
|
old_links, new_links);
|
||||||
|
trace_drv_return_int(local, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -165,40 +165,10 @@ static inline void drv_vif_cfg_changed(struct ieee80211_local *local,
|
|||||||
trace_drv_return_void(local);
|
trace_drv_return_void(local);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void drv_link_info_changed(struct ieee80211_local *local,
|
void drv_link_info_changed(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_bss_conf *info,
|
struct ieee80211_bss_conf *info,
|
||||||
int link_id, u64 changed)
|
int link_id, u64 changed);
|
||||||
{
|
|
||||||
might_sleep();
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
|
|
||||||
BSS_CHANGED_BEACON_ENABLED) &&
|
|
||||||
sdata->vif.type != NL80211_IFTYPE_AP &&
|
|
||||||
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
|
||||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
|
||||||
sdata->vif.type != NL80211_IFTYPE_OCB))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
|
|
||||||
sdata->vif.type == NL80211_IFTYPE_NAN ||
|
|
||||||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
|
||||||
!sdata->vif.bss_conf.mu_mimo_owner &&
|
|
||||||
!(changed & BSS_CHANGED_TXPOWER))))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!check_sdata_in_driver(sdata))
|
|
||||||
return;
|
|
||||||
|
|
||||||
trace_drv_link_info_changed(local, sdata, info, changed);
|
|
||||||
if (local->ops->link_info_changed)
|
|
||||||
local->ops->link_info_changed(&local->hw, &sdata->vif,
|
|
||||||
info, changed);
|
|
||||||
else if (local->ops->bss_info_changed)
|
|
||||||
local->ops->bss_info_changed(&local->hw, &sdata->vif,
|
|
||||||
info, changed);
|
|
||||||
trace_drv_return_void(local);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
|
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
|
||||||
struct netdev_hw_addr_list *mc_list)
|
struct netdev_hw_addr_list *mc_list)
|
||||||
@ -256,25 +226,11 @@ static inline int drv_set_tim(struct ieee80211_local *local,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int drv_set_key(struct ieee80211_local *local,
|
int drv_set_key(struct ieee80211_local *local,
|
||||||
enum set_key_cmd cmd,
|
enum set_key_cmd cmd,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_sta *sta,
|
struct ieee80211_sta *sta,
|
||||||
struct ieee80211_key_conf *key)
|
struct ieee80211_key_conf *key);
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
might_sleep();
|
|
||||||
|
|
||||||
sdata = get_bss_sdata(sdata);
|
|
||||||
if (!check_sdata_in_driver(sdata))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
trace_drv_set_key(local, cmd, sdata, sta, key);
|
|
||||||
ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
|
|
||||||
trace_drv_return_int(local, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void drv_update_tkip_key(struct ieee80211_local *local,
|
static inline void drv_update_tkip_key(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
@ -945,52 +901,14 @@ static inline void drv_verify_link_exists(struct ieee80211_sub_if_data *sdata,
|
|||||||
sdata_assert_lock(sdata);
|
sdata_assert_lock(sdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
|
int drv_assign_vif_chanctx(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_bss_conf *link_conf,
|
struct ieee80211_bss_conf *link_conf,
|
||||||
struct ieee80211_chanctx *ctx)
|
struct ieee80211_chanctx *ctx);
|
||||||
{
|
void drv_unassign_vif_chanctx(struct ieee80211_local *local,
|
||||||
int ret = 0;
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_bss_conf *link_conf,
|
||||||
drv_verify_link_exists(sdata, link_conf);
|
struct ieee80211_chanctx *ctx);
|
||||||
if (!check_sdata_in_driver(sdata))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
|
|
||||||
if (local->ops->assign_vif_chanctx) {
|
|
||||||
WARN_ON_ONCE(!ctx->driver_present);
|
|
||||||
ret = local->ops->assign_vif_chanctx(&local->hw,
|
|
||||||
&sdata->vif,
|
|
||||||
link_conf,
|
|
||||||
&ctx->conf);
|
|
||||||
}
|
|
||||||
trace_drv_return_int(local, ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
|
|
||||||
struct ieee80211_sub_if_data *sdata,
|
|
||||||
struct ieee80211_bss_conf *link_conf,
|
|
||||||
struct ieee80211_chanctx *ctx)
|
|
||||||
{
|
|
||||||
might_sleep();
|
|
||||||
|
|
||||||
drv_verify_link_exists(sdata, link_conf);
|
|
||||||
if (!check_sdata_in_driver(sdata))
|
|
||||||
return;
|
|
||||||
|
|
||||||
trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
|
|
||||||
if (local->ops->unassign_vif_chanctx) {
|
|
||||||
WARN_ON_ONCE(!ctx->driver_present);
|
|
||||||
local->ops->unassign_vif_chanctx(&local->hw,
|
|
||||||
&sdata->vif,
|
|
||||||
link_conf,
|
|
||||||
&ctx->conf);
|
|
||||||
}
|
|
||||||
trace_drv_return_void(local);
|
|
||||||
}
|
|
||||||
|
|
||||||
int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
||||||
struct ieee80211_vif_chanctx_switch *vifs,
|
struct ieee80211_vif_chanctx_switch *vifs,
|
||||||
int n_vifs, enum ieee80211_chanctx_switch_mode mode);
|
int n_vifs, enum ieee80211_chanctx_switch_mode mode);
|
||||||
@ -1552,46 +1470,13 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int drv_change_vif_links(struct ieee80211_local *local,
|
int drv_change_vif_links(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
u16 old_links, u16 new_links,
|
u16 old_links, u16 new_links,
|
||||||
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
|
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]);
|
||||||
{
|
int drv_change_sta_links(struct ieee80211_local *local,
|
||||||
int ret = -EOPNOTSUPP;
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
might_sleep();
|
u16 old_links, u16 new_links);
|
||||||
|
|
||||||
if (!check_sdata_in_driver(sdata))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
trace_drv_change_vif_links(local, sdata, old_links, new_links);
|
|
||||||
if (local->ops->change_vif_links)
|
|
||||||
ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
|
|
||||||
old_links, new_links, old);
|
|
||||||
trace_drv_return_int(local, ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int drv_change_sta_links(struct ieee80211_local *local,
|
|
||||||
struct ieee80211_sub_if_data *sdata,
|
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
u16 old_links, u16 new_links)
|
|
||||||
{
|
|
||||||
int ret = -EOPNOTSUPP;
|
|
||||||
|
|
||||||
might_sleep();
|
|
||||||
|
|
||||||
if (!check_sdata_in_driver(sdata))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
|
|
||||||
if (local->ops->change_sta_links)
|
|
||||||
ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
|
|
||||||
old_links, new_links);
|
|
||||||
trace_drv_return_int(local, ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __MAC80211_DRIVER_OPS */
|
#endif /* __MAC80211_DRIVER_OPS */
|
||||||
|
@ -177,6 +177,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key->conf.link_id >= 0 && sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(key->conf.link_id)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
ret = drv_set_key(key->local, SET_KEY, sdata,
|
ret = drv_set_key(key->local, SET_KEY, sdata,
|
||||||
sta ? &sta->sta : NULL, &key->conf);
|
sta ? &sta->sta : NULL, &key->conf);
|
||||||
|
|
||||||
@ -246,6 +250,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
|||||||
sta = key->sta;
|
sta = key->sta;
|
||||||
sdata = key->sdata;
|
sdata = key->sdata;
|
||||||
|
|
||||||
|
if (key->conf.link_id >= 0 && sdata->vif.active_links &&
|
||||||
|
!(sdata->vif.active_links & BIT(key->conf.link_id)))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
|
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
|
||||||
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||||
|
@ -73,28 +73,37 @@ struct link_container {
|
|||||||
struct ieee80211_bss_conf conf;
|
struct ieee80211_bss_conf conf;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
|
static void ieee80211_tear_down_links(struct ieee80211_sub_if_data *sdata,
|
||||||
struct link_container **links)
|
struct link_container **links, u16 mask)
|
||||||
{
|
{
|
||||||
|
struct ieee80211_link_data *link;
|
||||||
LIST_HEAD(keys);
|
LIST_HEAD(keys);
|
||||||
unsigned int link_id;
|
unsigned int link_id;
|
||||||
|
|
||||||
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
|
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
|
||||||
if (!links[link_id])
|
if (!(mask & BIT(link_id)))
|
||||||
continue;
|
continue;
|
||||||
ieee80211_remove_link_keys(&links[link_id]->data, &keys);
|
link = &links[link_id]->data;
|
||||||
|
if (link_id == 0 && !link)
|
||||||
|
link = &sdata->deflink;
|
||||||
|
if (WARN_ON(!link))
|
||||||
|
continue;
|
||||||
|
ieee80211_remove_link_keys(link, &keys);
|
||||||
|
ieee80211_link_stop(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
ieee80211_free_key_list(sdata->local, &keys);
|
ieee80211_free_key_list(sdata->local, &keys);
|
||||||
|
}
|
||||||
|
|
||||||
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
|
static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
|
||||||
if (!links[link_id])
|
struct link_container **links)
|
||||||
continue;
|
{
|
||||||
ieee80211_link_stop(&links[link_id]->data);
|
unsigned int link_id;
|
||||||
|
|
||||||
|
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
|
||||||
kfree(links[link_id]);
|
kfree(links[link_id]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
|
static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
|
||||||
@ -123,11 +132,38 @@ static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
|
||||||
|
u16 links)
|
||||||
|
{
|
||||||
|
sdata->vif.valid_links = links;
|
||||||
|
|
||||||
|
if (!links) {
|
||||||
|
sdata->vif.active_links = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sdata->vif.type) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
/* in an AP all links are always active */
|
||||||
|
sdata->vif.active_links = links;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_STATION:
|
||||||
|
if (sdata->vif.active_links)
|
||||||
|
break;
|
||||||
|
WARN_ON(hweight16(links) > 1);
|
||||||
|
sdata->vif.active_links = links;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
||||||
struct link_container **to_free,
|
struct link_container **to_free,
|
||||||
u16 new_links)
|
u16 new_links)
|
||||||
{
|
{
|
||||||
u16 old_links = sdata->vif.valid_links;
|
u16 old_links = sdata->vif.valid_links;
|
||||||
|
u16 old_active = sdata->vif.active_links;
|
||||||
unsigned long add = new_links & ~old_links;
|
unsigned long add = new_links & ~old_links;
|
||||||
unsigned long rem = old_links & ~new_links;
|
unsigned long rem = old_links & ~new_links;
|
||||||
unsigned int link_id;
|
unsigned int link_id;
|
||||||
@ -195,13 +231,17 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
|||||||
ieee80211_link_init(sdata, -1, &sdata->deflink,
|
ieee80211_link_init(sdata, -1, &sdata->deflink,
|
||||||
&sdata->vif.bss_conf);
|
&sdata->vif.bss_conf);
|
||||||
|
|
||||||
sdata->vif.valid_links = new_links;
|
|
||||||
|
|
||||||
ret = ieee80211_check_dup_link_addrs(sdata);
|
ret = ieee80211_check_dup_link_addrs(sdata);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
/* for keys we will not be able to undo this */
|
||||||
|
ieee80211_tear_down_links(sdata, to_free, rem);
|
||||||
|
|
||||||
|
ieee80211_set_vif_links_bitmaps(sdata, new_links);
|
||||||
|
|
||||||
/* tell the driver */
|
/* tell the driver */
|
||||||
ret = drv_change_vif_links(sdata->local, sdata,
|
ret = drv_change_vif_links(sdata->local, sdata,
|
||||||
old_links, new_links,
|
old_links & old_active,
|
||||||
|
new_links & sdata->vif.active_links,
|
||||||
old);
|
old);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +249,7 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
|||||||
/* restore config */
|
/* restore config */
|
||||||
memcpy(sdata->link, old_data, sizeof(old_data));
|
memcpy(sdata->link, old_data, sizeof(old_data));
|
||||||
memcpy(sdata->vif.link_conf, old, sizeof(old));
|
memcpy(sdata->vif.link_conf, old, sizeof(old));
|
||||||
sdata->vif.valid_links = old_links;
|
ieee80211_set_vif_links_bitmaps(sdata, old_links);
|
||||||
/* and free (only) the newly allocated links */
|
/* and free (only) the newly allocated links */
|
||||||
memset(to_free, 0, sizeof(links));
|
memset(to_free, 0, sizeof(links));
|
||||||
goto free;
|
goto free;
|
||||||
|
@ -4056,11 +4056,11 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sband = ieee80211_get_link_sband(link);
|
if (WARN_ON(!link->conf->chandef.chan)) {
|
||||||
if (!sband) {
|
|
||||||
ret = false;
|
ret = false;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
sband = local->hw.wiphy->bands[link->conf->chandef.chan->band];
|
||||||
|
|
||||||
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
|
||||||
(!elems->he_cap || !elems->he_operation)) {
|
(!elems->he_cap || !elems->he_operation)) {
|
||||||
@ -4884,8 +4884,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||||||
err = ieee80211_prep_channel(sdata, link,
|
err = ieee80211_prep_channel(sdata, link,
|
||||||
assoc_data->link[link_id].bss,
|
assoc_data->link[link_id].bss,
|
||||||
&link->u.mgd.conn_flags);
|
&link->u.mgd.conn_flags);
|
||||||
if (err)
|
if (err) {
|
||||||
|
link_info(link, "prep_channel failed\n");
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ieee80211_mgd_setup_link_sta(link, sta, link_sta,
|
err = ieee80211_mgd_setup_link_sta(link, sta, link_sta,
|
||||||
@ -6889,23 +6891,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||||||
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
|
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
|
||||||
size += req->links[i].elems_len;
|
size += req->links[i].elems_len;
|
||||||
|
|
||||||
if (req->ap_mld_addr) {
|
|
||||||
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
|
|
||||||
if (!req->links[i].bss)
|
|
||||||
continue;
|
|
||||||
if (i == assoc_link_id)
|
|
||||||
continue;
|
|
||||||
/*
|
|
||||||
* For now, support only a single link in MLO, we
|
|
||||||
* don't have the necessary parsing of the multi-
|
|
||||||
* link element in the association response, etc.
|
|
||||||
*/
|
|
||||||
sdata_info(sdata,
|
|
||||||
"refusing MLO association with >1 links\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: no support for 4-addr MLO yet */
|
/* FIXME: no support for 4-addr MLO yet */
|
||||||
if (sdata->u.mgd.use_4addr && req->link_id >= 0)
|
if (sdata->u.mgd.use_4addr && req->link_id >= 0)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -2900,7 +2900,7 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
|
|||||||
*/
|
*/
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!chanctx_conf))
|
if (!chanctx_conf)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
|
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user