summaryrefslogtreecommitdiffstats
path: root/net/mac80211/tdls.c
diff options
context:
space:
mode:
authorMohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>2017-04-27 12:45:38 +0530
committerJohannes Berg <johannes.berg@intel.com>2017-04-28 12:28:44 +0200
commit21a8e9dd52b64f0170bad208293ef8c30c3c1403 (patch)
treeaf61429b6f3d3f06f3c1a47690aa31dbcff23ee3 /net/mac80211/tdls.c
parent5fe49a9d11644f4aa9034c7eedbcfc6e52373e10 (diff)
downloadlinux-stable-21a8e9dd52b64f0170bad208293ef8c30c3c1403.tar.gz
linux-stable-21a8e9dd52b64f0170bad208293ef8c30c3c1403.tar.bz2
linux-stable-21a8e9dd52b64f0170bad208293ef8c30c3c1403.zip
mac80211: Fix possible sband related NULL pointer de-reference
Existing API 'ieee80211_get_sdata_band' returns default 2 GHz band even if the channel context configuration is NULL. This crashes for chipsets which support 5 Ghz alone when it tries to access members of 'sband'. Channel context configuration can be NULL in multivif case and when channel switch is in progress (or) when it fails. Fix this by replacing the API 'ieee80211_get_sdata_band' with 'ieee80211_get_sband' which returns a NULL pointer for sband when the channel configuration is NULL. An example scenario is as below: In multivif mode (AP + STA) with drivers like ath10k, when we do a channel switch in the AP vif (which has a number of clients connected) and a STA vif which is connected to some other AP, when the channel switch in AP vif fails, while the STA vifs tries to connect to the other AP, there is a window where the channel context is NULL/invalid and this results in a crash while the clients connected to the AP vif tries to reconnect and this race is very similar to the one investigated by Michal in https://patchwork.kernel.org/patch/3788161/ and this does happens with hardware that supports 5Ghz alone after long hours of testing with continuous channel switch on the AP vif ieee80211 phy0: channel context reservation cannot be finalized because some interfaces aren't switching wlan0: failed to finalize CSA, disconnecting wlan0-1: deauthenticating from 8c:fd:f0:01:54:9c by local choice (Reason: 3=DEAUTH_LEAVING) WARNING: CPU: 1 PID: 19032 at net/mac80211/ieee80211_i.h:1013 sta_info_alloc+0x374/0x3fc [mac80211] [<bf77272c>] (sta_info_alloc [mac80211]) [<bf78776c>] (ieee80211_add_station [mac80211])) [<bf73cc50>] (nl80211_new_station [cfg80211]) Unable to handle kernel NULL pointer dereference at virtual address 00000014 pgd = d5f4c000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM PC is at sta_info_alloc+0x380/0x3fc [mac80211] LR is at sta_info_alloc+0x37c/0x3fc [mac80211] [<bf772738>] (sta_info_alloc [mac80211]) [<bf78776c>] (ieee80211_add_station [mac80211]) [<bf73cc50>] (nl80211_new_station [cfg80211])) Cc: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/tdls.c')
-rw-r--r--net/mac80211/tdls.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index afca7d103684..f20dcf1b1830 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -47,8 +47,7 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata,
NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
!ifmgd->tdls_wider_bw_prohibited;
- enum nl80211_band band = ieee80211_get_sdata_band(sdata);
- struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
+ struct ieee80211_supported_band *sband = ieee80211_get_sband(sdata);
bool vht = sband && sband->vht_cap.vht_supported;
u8 *pos = (void *)skb_put(skb, 10);
@@ -180,11 +179,14 @@ static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb)
static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata,
u16 status_code)
{
+ struct ieee80211_supported_band *sband;
+
/* The capability will be 0 when sending a failure code */
if (status_code != 0)
return 0;
- if (ieee80211_get_sdata_band(sdata) == NL80211_BAND_2GHZ) {
+ sband = ieee80211_get_sband(sdata);
+ if (sband && sband->band == NL80211_BAND_2GHZ) {
return WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE;
}
@@ -358,17 +360,20 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
u8 action_code, bool initiator,
const u8 *extra_ies, size_t extra_ies_len)
{
- enum nl80211_band band = ieee80211_get_sdata_band(sdata);
- struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
struct sta_info *sta = NULL;
size_t offset = 0, noffset;
u8 *pos;
- ieee80211_add_srates_ie(sdata, skb, false, band);
- ieee80211_add_ext_srates_ie(sdata, skb, false, band);
+ sband = ieee80211_get_sband(sdata);
+ if (!sband)
+ return;
+
+ ieee80211_add_srates_ie(sdata, skb, false, sband->band);
+ ieee80211_add_ext_srates_ie(sdata, skb, false, sband->band);
ieee80211_tdls_add_supp_channels(sdata, skb);
/* add any custom IEs that go before Extended Capabilities */
@@ -439,7 +444,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
* the same on all bands. The specification limits the setup to a
* single HT-cap, so use the current band for now.
*/
- sband = local->hw.wiphy->bands[band];
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
if ((action_code == WLAN_TDLS_SETUP_REQUEST ||
@@ -545,9 +549,13 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
size_t offset = 0, noffset;
struct sta_info *sta, *ap_sta;
- enum nl80211_band band = ieee80211_get_sdata_band(sdata);
+ struct ieee80211_supported_band *sband;
u8 *pos;
+ sband = ieee80211_get_sband(sdata);
+ if (!sband)
+ return;
+
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, peer);
@@ -612,7 +620,8 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
/* only include VHT-operation if not on the 2.4GHz band */
- if (band != NL80211_BAND_2GHZ && sta->sta.vht_cap.vht_supported) {
+ if (sband->band != NL80211_BAND_2GHZ &&
+ sta->sta.vht_cap.vht_supported) {
/*
* if both peers support WIDER_BW, we can expand the chandef to
* a wider compatible one, up to 80MHz