Commit 78a7ea37 authored by Mukesh Sisodiya's avatar Mukesh Sisodiya Committed by Johannes Berg

wifi: mac80211: handle TDLS negotiation with MLO

Userspace can now select the link to use for TDLS management
frames (indicating e.g. which BSSID should be used), use the
link_id received from cfg80211 to build the frames.
Signed-off-by: default avatarMukesh Sisodiya <mukesh.sisodiya@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230616094948.ce1fc230b505.Ie773c5679805001f5a52680d68d9ce0232c57648@changeid
[Benjamin fixed some locking]
Co-developed-by: default avatarBenjamin Berg <benjamin.berg@intel.com>
Signed-off-by: default avatarBenjamin Berg <benjamin.berg@intel.com>
[fix sta mutex locking too]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c6112046
...@@ -39,9 +39,10 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) ...@@ -39,9 +39,10 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk)
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
} }
static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, static void ieee80211_tdls_add_ext_capab(struct ieee80211_link_data *link,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
bool chan_switch = local->hw.wiphy->features & bool chan_switch = local->hw.wiphy->features &
...@@ -50,7 +51,7 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, ...@@ -50,7 +51,7 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata,
!ifmgd->tdls_wider_bw_prohibited; !ifmgd->tdls_wider_bw_prohibited;
bool buffer_sta = ieee80211_hw_check(&local->hw, bool buffer_sta = ieee80211_hw_check(&local->hw,
SUPPORTS_TDLS_BUFFER_STA); SUPPORTS_TDLS_BUFFER_STA);
struct ieee80211_supported_band *sband = ieee80211_get_sband(sdata); struct ieee80211_supported_band *sband = ieee80211_get_link_sband(link);
bool vht = sband && sband->vht_cap.vht_supported; bool vht = sband && sband->vht_cap.vht_supported;
u8 *pos = skb_put(skb, 10); u8 *pos = skb_put(skb, 10);
...@@ -152,13 +153,13 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, ...@@ -152,13 +153,13 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata,
*pos = 2 * subband_cnt; *pos = 2 * subband_cnt;
} }
static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata, static void ieee80211_tdls_add_oper_classes(struct ieee80211_link_data *link,
struct sk_buff *skb) struct sk_buff *skb)
{ {
u8 *pos; u8 *pos;
u8 op_class; u8 op_class;
if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef, if (!ieee80211_chandef_to_operating_class(&link->conf->chandef,
&op_class)) &op_class))
return; return;
...@@ -180,7 +181,7 @@ static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) ...@@ -180,7 +181,7 @@ static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb)
*pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST;
} }
static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_link_data *link,
u16 status_code) u16 status_code)
{ {
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
...@@ -189,7 +190,8 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, ...@@ -189,7 +190,8 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata,
if (status_code != 0) if (status_code != 0)
return 0; return 0;
sband = ieee80211_get_sband(sdata); sband = ieee80211_get_link_sband(link);
if (sband && sband->band == NL80211_BAND_2GHZ) { if (sband && sband->band == NL80211_BAND_2GHZ) {
return WLAN_CAPABILITY_SHORT_SLOT_TIME | return WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE; WLAN_CAPABILITY_SHORT_PREAMBLE;
...@@ -198,10 +200,11 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, ...@@ -198,10 +200,11 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata,
return 0; return 0;
} }
static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, static void ieee80211_tdls_add_link_ie(struct ieee80211_link_data *link,
struct sk_buff *skb, const u8 *peer, struct sk_buff *skb, const u8 *peer,
bool initiator) bool initiator)
{ {
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_tdls_lnkie *lnkid; struct ieee80211_tdls_lnkie *lnkid;
const u8 *init_addr, *rsp_addr; const u8 *init_addr, *rsp_addr;
...@@ -218,7 +221,7 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, ...@@ -218,7 +221,7 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
lnkid->ie_type = WLAN_EID_LINK_ID; lnkid->ie_type = WLAN_EID_LINK_ID;
lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
memcpy(lnkid->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN); memcpy(lnkid->bssid, link->u.mgd.bssid, ETH_ALEN);
memcpy(lnkid->init_sta, init_addr, ETH_ALEN); memcpy(lnkid->init_sta, init_addr, ETH_ALEN);
memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
} }
...@@ -359,11 +362,12 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, ...@@ -359,11 +362,12 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata,
} }
static void static void
ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link,
struct sk_buff *skb, const u8 *peer, struct sk_buff *skb, const u8 *peer,
u8 action_code, bool initiator, u8 action_code, bool initiator,
const u8 *extra_ies, size_t extra_ies_len) const u8 *extra_ies, size_t extra_ies_len)
{ {
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_ht_cap ht_cap;
...@@ -372,8 +376,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ...@@ -372,8 +376,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
size_t offset = 0, noffset; size_t offset = 0, noffset;
u8 *pos; u8 *pos;
sband = ieee80211_get_sband(sdata); sband = ieee80211_get_link_sband(link);
if (!sband) if (WARN_ON_ONCE(!sband))
return; return;
ieee80211_add_srates_ie(sdata, skb, false, sband->band); ieee80211_add_srates_ie(sdata, skb, false, sband->band);
...@@ -397,7 +401,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ...@@ -397,7 +401,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
offset = noffset; offset = noffset;
} }
ieee80211_tdls_add_ext_capab(sdata, skb); ieee80211_tdls_add_ext_capab(link, skb);
/* add the QoS element if we support it */ /* add the QoS element if we support it */
if (local->hw.queues >= IEEE80211_NUM_ACS && if (local->hw.queues >= IEEE80211_NUM_ACS &&
...@@ -426,20 +430,16 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ...@@ -426,20 +430,16 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
offset = noffset; offset = noffset;
} }
mutex_lock(&local->sta_mtx);
/* we should have the peer STA if we're already responding */ /* we should have the peer STA if we're already responding */
if (action_code == WLAN_TDLS_SETUP_RESPONSE) { if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
sta = sta_info_get(sdata, peer); sta = sta_info_get(sdata, peer);
if (WARN_ON_ONCE(!sta)) { if (WARN_ON_ONCE(!sta))
mutex_unlock(&local->sta_mtx);
return; return;
}
sta->tdls_chandef = sdata->vif.bss_conf.chandef; sta->tdls_chandef = link->conf->chandef;
} }
ieee80211_tdls_add_oper_classes(sdata, skb); ieee80211_tdls_add_oper_classes(link, skb);
/* /*
* with TDLS we can switch channels, and HT-caps are not necessarily * with TDLS we can switch channels, and HT-caps are not necessarily
...@@ -472,7 +472,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ...@@ -472,7 +472,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
(ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
ieee80211_tdls_add_bss_coex_ie(skb); ieee80211_tdls_add_bss_coex_ie(skb);
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); ieee80211_tdls_add_link_ie(link, skb, peer, initiator);
/* add any custom IEs that go before VHT capabilities */ /* add any custom IEs that go before VHT capabilities */
if (extra_ies_len) { if (extra_ies_len) {
...@@ -529,8 +529,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ...@@ -529,8 +529,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
ieee80211_tdls_chandef_vht_upgrade(sdata, sta); ieee80211_tdls_chandef_vht_upgrade(sdata, sta);
} }
mutex_unlock(&local->sta_mtx);
/* add any remaining IEs */ /* add any remaining IEs */
if (extra_ies_len) { if (extra_ies_len) {
noffset = extra_ies_len; noffset = extra_ies_len;
...@@ -540,31 +538,29 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ...@@ -540,31 +538,29 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
} }
static void static void
ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_link_data *link,
struct sk_buff *skb, const u8 *peer, struct sk_buff *skb, const u8 *peer,
bool initiator, const u8 *extra_ies, bool initiator, const u8 *extra_ies,
size_t extra_ies_len) size_t extra_ies_len)
{ {
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
size_t offset = 0, noffset; size_t offset = 0, noffset;
struct sta_info *sta, *ap_sta; struct sta_info *sta, *ap_sta;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
u8 *pos; u8 *pos;
sband = ieee80211_get_sband(sdata); sband = ieee80211_get_link_sband(link);
if (!sband) if (WARN_ON_ONCE(!sband))
return; return;
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, peer); sta = sta_info_get(sdata, peer);
ap_sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); ap_sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
if (WARN_ON_ONCE(!sta || !ap_sta)) {
mutex_unlock(&local->sta_mtx); if (WARN_ON_ONCE(!sta || !ap_sta))
return; return;
}
sta->tdls_chandef = sdata->vif.bss_conf.chandef; sta->tdls_chandef = link->conf->chandef;
/* add any custom IEs that go before the QoS IE */ /* add any custom IEs that go before the QoS IE */
if (extra_ies_len) { if (extra_ies_len) {
...@@ -610,11 +606,11 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, ...@@ -610,11 +606,11 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
ieee80211_ie_build_ht_oper(pos, &sta->sta.deflink.ht_cap, ieee80211_ie_build_ht_oper(pos, &sta->sta.deflink.ht_cap,
&sdata->vif.bss_conf.chandef, prot, &link->conf->chandef, prot,
true); true);
} }
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); ieee80211_tdls_add_link_ie(link, skb, peer, initiator);
/* only include VHT-operation if not on the 2.4GHz band */ /* only include VHT-operation if not on the 2.4GHz band */
if (sband->band != NL80211_BAND_2GHZ && if (sband->band != NL80211_BAND_2GHZ &&
...@@ -631,8 +627,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, ...@@ -631,8 +627,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
&sta->tdls_chandef); &sta->tdls_chandef);
} }
mutex_unlock(&local->sta_mtx);
/* add any remaining IEs */ /* add any remaining IEs */
if (extra_ies_len) { if (extra_ies_len) {
noffset = extra_ies_len; noffset = extra_ies_len;
...@@ -641,7 +635,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, ...@@ -641,7 +635,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
} }
static void static void
ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_link_data *link,
struct sk_buff *skb, const u8 *peer, struct sk_buff *skb, const u8 *peer,
bool initiator, const u8 *extra_ies, bool initiator, const u8 *extra_ies,
size_t extra_ies_len, u8 oper_class, size_t extra_ies_len, u8 oper_class,
...@@ -670,7 +664,7 @@ ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, ...@@ -670,7 +664,7 @@ ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata,
offset = noffset; offset = noffset;
} }
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); ieee80211_tdls_add_link_ie(link, skb, peer, initiator);
/* add any remaining IEs */ /* add any remaining IEs */
if (extra_ies_len) { if (extra_ies_len) {
...@@ -680,20 +674,20 @@ ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, ...@@ -680,20 +674,20 @@ ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata,
} }
static void static void
ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_link_data *link,
struct sk_buff *skb, const u8 *peer, struct sk_buff *skb, const u8 *peer,
u16 status_code, bool initiator, u16 status_code, bool initiator,
const u8 *extra_ies, const u8 *extra_ies,
size_t extra_ies_len) size_t extra_ies_len)
{ {
if (status_code == 0) if (status_code == 0)
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); ieee80211_tdls_add_link_ie(link, skb, peer, initiator);
if (extra_ies_len) if (extra_ies_len)
skb_put_data(skb, extra_ies, extra_ies_len); skb_put_data(skb, extra_ies, extra_ies_len);
} }
static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, static void ieee80211_tdls_add_ies(struct ieee80211_link_data *link,
struct sk_buff *skb, const u8 *peer, struct sk_buff *skb, const u8 *peer,
u8 action_code, u16 status_code, u8 action_code, u16 status_code,
bool initiator, const u8 *extra_ies, bool initiator, const u8 *extra_ies,
...@@ -705,7 +699,8 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, ...@@ -705,7 +699,8 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
case WLAN_TDLS_SETUP_RESPONSE: case WLAN_TDLS_SETUP_RESPONSE:
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
if (status_code == 0) if (status_code == 0)
ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, ieee80211_tdls_add_setup_start_ies(link,
skb, peer,
action_code, action_code,
initiator, initiator,
extra_ies, extra_ies,
...@@ -713,7 +708,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, ...@@ -713,7 +708,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
break; break;
case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_SETUP_CONFIRM:
if (status_code == 0) if (status_code == 0)
ieee80211_tdls_add_setup_cfm_ies(sdata, skb, peer, ieee80211_tdls_add_setup_cfm_ies(link, skb, peer,
initiator, extra_ies, initiator, extra_ies,
extra_ies_len); extra_ies_len);
break; break;
...@@ -722,16 +717,17 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, ...@@ -722,16 +717,17 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
if (extra_ies_len) if (extra_ies_len)
skb_put_data(skb, extra_ies, extra_ies_len); skb_put_data(skb, extra_ies, extra_ies_len);
if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN)
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); ieee80211_tdls_add_link_ie(link, skb,
peer, initiator);
break; break;
case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: case WLAN_TDLS_CHANNEL_SWITCH_REQUEST:
ieee80211_tdls_add_chan_switch_req_ies(sdata, skb, peer, ieee80211_tdls_add_chan_switch_req_ies(link, skb, peer,
initiator, extra_ies, initiator, extra_ies,
extra_ies_len, extra_ies_len,
oper_class, chandef); oper_class, chandef);
break; break;
case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE:
ieee80211_tdls_add_chan_switch_resp_ies(sdata, skb, peer, ieee80211_tdls_add_chan_switch_resp_ies(link, skb, peer,
status_code, status_code,
initiator, extra_ies, initiator, extra_ies,
extra_ies_len); extra_ies_len);
...@@ -742,6 +738,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, ...@@ -742,6 +738,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
static int static int
ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_link_data *link,
const u8 *peer, u8 action_code, u8 dialog_token, const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, struct sk_buff *skb) u16 status_code, struct sk_buff *skb)
{ {
...@@ -766,7 +763,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, ...@@ -766,7 +763,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
skb_put(skb, sizeof(tf->u.setup_req)); skb_put(skb, sizeof(tf->u.setup_req));
tf->u.setup_req.dialog_token = dialog_token; tf->u.setup_req.dialog_token = dialog_token;
tf->u.setup_req.capability = tf->u.setup_req.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, cpu_to_le16(ieee80211_get_tdls_sta_capab(link,
status_code)); status_code));
break; break;
case WLAN_TDLS_SETUP_RESPONSE: case WLAN_TDLS_SETUP_RESPONSE:
...@@ -777,7 +774,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, ...@@ -777,7 +774,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
tf->u.setup_resp.status_code = cpu_to_le16(status_code); tf->u.setup_resp.status_code = cpu_to_le16(status_code);
tf->u.setup_resp.dialog_token = dialog_token; tf->u.setup_resp.dialog_token = dialog_token;
tf->u.setup_resp.capability = tf->u.setup_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, cpu_to_le16(ieee80211_get_tdls_sta_capab(link,
status_code)); status_code));
break; break;
case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_SETUP_CONFIRM:
...@@ -824,7 +821,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, ...@@ -824,7 +821,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
static int static int
ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token, const u8 *peer, struct ieee80211_link_data *link,
u8 action_code, u8 dialog_token,
u16 status_code, struct sk_buff *skb) u16 status_code, struct sk_buff *skb)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
...@@ -833,8 +831,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, ...@@ -833,8 +831,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
mgmt = skb_put_zero(skb, 24); mgmt = skb_put_zero(skb, 24);
memcpy(mgmt->da, peer, ETH_ALEN); memcpy(mgmt->da, peer, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN); memcpy(mgmt->bssid, link->u.mgd.bssid, ETH_ALEN);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION); IEEE80211_STYPE_ACTION);
...@@ -847,7 +844,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, ...@@ -847,7 +844,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
mgmt->u.action.u.tdls_discover_resp.dialog_token = mgmt->u.action.u.tdls_discover_resp.dialog_token =
dialog_token; dialog_token;
mgmt->u.action.u.tdls_discover_resp.capability = mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, cpu_to_le16(ieee80211_get_tdls_sta_capab(link,
status_code)); status_code));
break; break;
default: default:
...@@ -859,15 +856,23 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, ...@@ -859,15 +856,23 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
static struct sk_buff * static struct sk_buff *
ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
const u8 *peer, u8 action_code, const u8 *peer, int link_id,
u8 dialog_token, u16 status_code, u8 action_code, u8 dialog_token,
bool initiator, const u8 *extra_ies, u16 status_code, bool initiator,
size_t extra_ies_len, u8 oper_class, const u8 *extra_ies, size_t extra_ies_len,
u8 oper_class,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
struct ieee80211_link_data *link;
link_id = link_id >= 0 ? link_id : 0;
rcu_read_lock();
link = rcu_dereference(sdata->link[link_id]);
if (WARN_ON(!link))
goto unlock;
skb = netdev_alloc_skb(sdata->dev, skb = netdev_alloc_skb(sdata->dev,
local->hw.extra_tx_headroom + local->hw.extra_tx_headroom +
...@@ -887,7 +892,7 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, ...@@ -887,7 +892,7 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
extra_ies_len + extra_ies_len +
sizeof(struct ieee80211_tdls_lnkie)); sizeof(struct ieee80211_tdls_lnkie));
if (!skb) if (!skb)
return NULL; goto unlock;
skb_reserve(skb, local->hw.extra_tx_headroom); skb_reserve(skb, local->hw.extra_tx_headroom);
...@@ -900,13 +905,13 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, ...@@ -900,13 +905,13 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: case WLAN_TDLS_CHANNEL_SWITCH_REQUEST:
case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE:
ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy, ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy,
sdata->dev, peer, sdata->dev, link, peer,
action_code, dialog_token, action_code, dialog_token,
status_code, skb); status_code, skb);
break; break;
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev, ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev,
peer, action_code, peer, link, action_code,
dialog_token, status_code, dialog_token, status_code,
skb); skb);
break; break;
...@@ -918,19 +923,23 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, ...@@ -918,19 +923,23 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
if (ret < 0) if (ret < 0)
goto fail; goto fail;
ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, ieee80211_tdls_add_ies(link, skb, peer, action_code, status_code,
initiator, extra_ies, extra_ies_len, oper_class, initiator, extra_ies, extra_ies_len, oper_class,
chandef); chandef);
rcu_read_unlock();
return skb; return skb;
fail: fail:
dev_kfree_skb(skb); dev_kfree_skb(skb);
unlock:
rcu_read_unlock();
return NULL; return NULL;
} }
static int static int
ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token, const u8 *peer, int link_id,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability, u16 status_code, u32 peer_capability,
bool initiator, const u8 *extra_ies, bool initiator, const u8 *extra_ies,
size_t extra_ies_len, u8 oper_class, size_t extra_ies_len, u8 oper_class,
...@@ -988,7 +997,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, ...@@ -988,7 +997,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
if (ret < 0) if (ret < 0)
goto fail; goto fail;
skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, action_code, skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer,
link_id, action_code,
dialog_token, status_code, dialog_token, status_code,
initiator, extra_ies, initiator, extra_ies,
extra_ies_len, oper_class, extra_ies_len, oper_class,
...@@ -999,7 +1009,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, ...@@ -999,7 +1009,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
} }
if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
ieee80211_tx_skb(sdata, skb); ieee80211_tx_skb_tid(sdata, skb, 7, link_id);
return 0; return 0;
} }
...@@ -1066,7 +1076,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, ...@@ -1066,7 +1076,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
static int static int
ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token, const u8 *peer, int link_id,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability, bool initiator, u16 status_code, u32 peer_capability, bool initiator,
const u8 *extra_ies, size_t extra_ies_len) const u8 *extra_ies, size_t extra_ies_len)
{ {
...@@ -1115,7 +1126,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, ...@@ -1115,7 +1126,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
/* we cannot take the mutex while preparing the setup packet */ /* we cannot take the mutex while preparing the setup packet */
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
link_id, action_code,
dialog_token, status_code, dialog_token, status_code,
peer_capability, initiator, peer_capability, initiator,
extra_ies, extra_ies_len, 0, extra_ies, extra_ies_len, 0,
...@@ -1139,7 +1151,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, ...@@ -1139,7 +1151,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
static int static int
ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 action_code, u8 dialog_token, const u8 *peer, int link_id,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability, u16 status_code, u32 peer_capability,
bool initiator, const u8 *extra_ies, bool initiator, const u8 *extra_ies,
size_t extra_ies_len) size_t extra_ies_len)
...@@ -1159,7 +1172,8 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, ...@@ -1159,7 +1172,8 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
ieee80211_flush_queues(local, sdata, false); ieee80211_flush_queues(local, sdata, false);
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
link_id, action_code,
dialog_token, status_code, dialog_token, status_code,
peer_capability, initiator, peer_capability, initiator,
extra_ies, extra_ies_len, 0, extra_ies, extra_ies_len, 0,
...@@ -1204,13 +1218,14 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, ...@@ -1204,13 +1218,14 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
switch (action_code) { switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST: case WLAN_TDLS_SETUP_REQUEST:
case WLAN_TDLS_SETUP_RESPONSE: case WLAN_TDLS_SETUP_RESPONSE:
ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code, ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer,
link_id, action_code,
dialog_token, status_code, dialog_token, status_code,
peer_capability, initiator, peer_capability, initiator,
extra_ies, extra_ies_len); extra_ies, extra_ies_len);
break; break;
case WLAN_TDLS_TEARDOWN: case WLAN_TDLS_TEARDOWN:
ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, link_id,
action_code, dialog_token, action_code, dialog_token,
status_code, status_code,
peer_capability, initiator, peer_capability, initiator,
...@@ -1228,7 +1243,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, ...@@ -1228,7 +1243,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
/* no special handling */ /* no special handling */
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
action_code, link_id, action_code,
dialog_token, dialog_token,
status_code, status_code,
peer_capability, peer_capability,
...@@ -1240,8 +1255,8 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, ...@@ -1240,8 +1255,8 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
break; break;
} }
tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", tdls_dbg(sdata, "TDLS mgmt action %d peer %pM link_id %d status %d\n",
action_code, peer, ret); action_code, peer, link_id, ret);
return ret; return ret;
} }
...@@ -1497,6 +1512,7 @@ ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, ...@@ -1497,6 +1512,7 @@ ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class,
int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing); int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing);
u8 *pos = extra_ies; u8 *pos = extra_ies;
struct sk_buff *skb; struct sk_buff *skb;
int link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0;
/* /*
* if chandef points to a wide channel add a Secondary-Channel * if chandef points to a wide channel add a Secondary-Channel
...@@ -1524,6 +1540,7 @@ ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, ...@@ -1524,6 +1540,7 @@ ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class,
iee80211_tdls_add_ch_switch_timing(pos, 0, 0); iee80211_tdls_add_ch_switch_timing(pos, 0, 0);
skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr,
link_id,
WLAN_TDLS_CHANNEL_SWITCH_REQUEST, WLAN_TDLS_CHANNEL_SWITCH_REQUEST,
0, 0, !sta->sta.tdls_initiator, 0, 0, !sta->sta.tdls_initiator,
extra_ies, extra_ies_len, extra_ies, extra_ies_len,
...@@ -1644,11 +1661,13 @@ ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta, ...@@ -1644,11 +1661,13 @@ ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta,
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
struct sk_buff *skb; struct sk_buff *skb;
u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)]; u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)];
int link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0;
/* initial timing are always zero in the template */ /* initial timing are always zero in the template */
iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0); iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0);
skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr,
link_id,
WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, WLAN_TDLS_CHANNEL_SWITCH_RESPONSE,
0, 0, !sta->sta.tdls_initiator, 0, 0, !sta->sta.tdls_initiator,
extra_ies, sizeof(extra_ies), 0, NULL); extra_ies, sizeof(extra_ies), 0, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment