From 65b1aae0d9d5962faccc06bdb8e91a2a0b09451c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 6 Jan 2020 14:42:12 -0800 Subject: [PATCH 01/14] mwifiex: fix unbalanced locking in mwifiex_process_country_ie() We called rcu_read_lock(), so we need to call rcu_read_unlock() before we return. Fixes: 3d94a4a8373b ("mwifiex: fix possible heap overflow in mwifiex_process_country_ie()") Cc: stable@vger.kernel.org Cc: huangwen Cc: Ganapathi Bhat Signed-off-by: Brian Norris Acked-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 6dd835f1efc2..fbfa0b15d0c8 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -232,6 +232,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, if (country_ie_len > (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) { + rcu_read_unlock(); mwifiex_dbg(priv->adapter, ERROR, "11D: country_ie_len overflow!, deauth AP\n"); return -EINVAL; From 3a9b153c5591548612c3955c9600a98150c81875 Mon Sep 17 00:00:00 2001 From: Qing Xu Date: Thu, 2 Jan 2020 10:39:26 +0800 Subject: [PATCH 02/14] mwifiex: Fix possible buffer overflows in mwifiex_ret_wmm_get_status() mwifiex_ret_wmm_get_status() calls memcpy() without checking the destination size.Since the source is given from remote AP which contains illegal wmm elements , this may trigger a heap buffer overflow. Fix it by putting the length check before calling memcpy(). Signed-off-by: Qing Xu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/wmm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 41f0231376c0..132f9e8ed68c 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -970,6 +970,10 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, "WMM Parameter Set Count: %d\n", wmm_param_ie->qos_info_bitmap & mask); + if (wmm_param_ie->vend_hdr.len + 2 > + sizeof(struct ieee_types_wmm_parameter)) + break; + memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. wmm_ie, wmm_param_ie, wmm_param_ie->vend_hdr.len + 2); From b70261a288ea4d2f4ac7cd04be08a9f0f2de4f4d Mon Sep 17 00:00:00 2001 From: Qing Xu Date: Thu, 2 Jan 2020 10:39:27 +0800 Subject: [PATCH 03/14] mwifiex: Fix possible buffer overflows in mwifiex_cmd_append_vsie_tlv() mwifiex_cmd_append_vsie_tlv() calls memcpy() without checking the destination size may trigger a buffer overflower, which a local user could use to cause denial of service or the execution of arbitrary code. Fix it by putting the length check before calling memcpy(). Signed-off-by: Qing Xu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/scan.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 98f942b797f7..a7968a84aaf8 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2884,6 +2884,13 @@ mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, vs_param_set->header.len = cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) & 0x00FF) + 2); + if (le16_to_cpu(vs_param_set->header.len) > + MWIFIEX_MAX_VSIE_LEN) { + mwifiex_dbg(priv->adapter, ERROR, + "Invalid param length!\n"); + break; + } + memcpy(vs_param_set->ie, priv->vs_ie[id].ie, le16_to_cpu(vs_param_set->header.len)); *buffer += le16_to_cpu(vs_param_set->header.len) + From c7bf1fb7ddca331780b9a733ae308737b39f1ad4 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 14 Jan 2020 11:39:02 +0100 Subject: [PATCH 04/14] libertas: don't exit from lbs_ibss_join_existing() with RCU read lock held Commit e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") introduced a bounds check on the number of supplied rates to lbs_ibss_join_existing(). Unfortunately, it introduced a return path from within a RCU read side critical section without a corresponding rcu_read_unlock(). Fix this. Fixes: e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") Signed-off-by: Nicolai Stange Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cfg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index c9401c121a14..68985d766349 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1785,6 +1785,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, rates_max = rates_eid[1]; if (rates_max > MAX_RATES) { lbs_deb_join("invalid rates"); + rcu_read_unlock(); goto out; } rates = cmd.bss.rates; From 1754c4f60aaf1e17d886afefee97e94d7f27b4cb Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 14 Jan 2020 11:39:03 +0100 Subject: [PATCH 05/14] libertas: make lbs_ibss_join_existing() return error code on rates overflow Commit e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") introduced a bounds check on the number of supplied rates to lbs_ibss_join_existing() and made it to return on overflow. However, the aforementioned commit doesn't set the return value accordingly and thus, lbs_ibss_join_existing() would return with zero even though it failed. Make lbs_ibss_join_existing return -EINVAL in case the bounds check on the number of supplied rates fails. Fixes: e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") Signed-off-by: Nicolai Stange Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cfg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 68985d766349..4e3de684928b 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1786,6 +1786,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, if (rates_max > MAX_RATES) { lbs_deb_join("invalid rates"); rcu_read_unlock(); + ret = -EINVAL; goto out; } rates = cmd.bss.rates; From baa6cf8450b72dcab11f37c47efce7c5b9b8ad0f Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Fri, 31 Jan 2020 15:45:24 +0200 Subject: [PATCH 06/14] iwlwifi: mvm: Fix thermal zone registration Use a unique name when registering a thermal zone. Otherwise, with multiple NICS, we hit the following warning during the unregistration. WARNING: CPU: 2 PID: 3525 at fs/sysfs/group.c:255 RIP: 0010:sysfs_remove_group+0x80/0x90 Call Trace: dpm_sysfs_remove+0x57/0x60 device_del+0x5a/0x350 ? sscanf+0x4e/0x70 device_unregister+0x1a/0x60 hwmon_device_unregister+0x4a/0xa0 thermal_remove_hwmon_sysfs+0x175/0x1d0 thermal_zone_device_unregister+0x188/0x1e0 iwl_mvm_thermal_exit+0xe7/0x100 [iwlmvm] iwl_op_mode_mvm_stop+0x27/0x180 [iwlmvm] _iwl_op_mode_stop.isra.3+0x2b/0x50 [iwlwifi] iwl_opmode_deregister+0x90/0xa0 [iwlwifi] __exit_compat+0x10/0x2c7 [iwlmvm] __x64_sys_delete_module+0x13f/0x270 do_syscall_64+0x5a/0x110 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Signed-off-by: Andrei Otcheretianski Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index b5a16f00bada..fcad25ffd811 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -734,7 +734,8 @@ static struct thermal_zone_device_ops tzone_ops = { static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) { int i; - char name[] = "iwlwifi"; + char name[16]; + static atomic_t counter = ATOMIC_INIT(0); if (!iwl_mvm_is_tt_in_fw(mvm)) { mvm->tz_device.tzone = NULL; @@ -744,6 +745,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); + sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF); mvm->tz_device.tzone = thermal_zone_device_register(name, IWL_MAX_DTS_TRIPS, IWL_WRITABLE_TRIPS_MSK, From 197288d5ba8a5289f22d3aeb4fca3824bfd9b4af Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 31 Jan 2020 15:45:25 +0200 Subject: [PATCH 07/14] iwlwifi: don't throw error when trying to remove IGTK The IGTK keys are only removed by mac80211 after it has already removed the AP station. This causes the driver to throw an error because mac80211 is trying to remove the IGTK when the station doesn't exist anymore. The firmware is aware that the station has been removed and can deal with it the next time we try to add an IGTK for a station, so we shouldn't try to remove the key if the station ID is IWL_MVM_INVALID_STA. Do this by removing the check for mvm_sta before calling iwl_mvm_send_sta_igtk() and check return from that function gracefully if the station ID is invalid. Cc: stable@vger.kernel.org # 4.12+ Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 7b35f416404c..64ef3f3ba23b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3320,6 +3320,10 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, igtk_cmd.sta_id = cpu_to_le32(sta_id); if (remove_key) { + /* This is a valid situation for IGTK */ + if (sta_id == IWL_MVM_INVALID_STA) + return 0; + igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); } else { struct ieee80211_key_seq seq; @@ -3574,9 +3578,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", keyconf->keyidx, sta_id); - if (mvm_sta && (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)) + if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) { From 6bd5fa332a8c24c8b9079a70c44240b61858fab8 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Fri, 31 Jan 2020 15:45:26 +0200 Subject: [PATCH 08/14] iwlwifi: mvm: update the DTS measurement type Till now, the driver asked the fw for a DTS measurement in automatic mode. This triggered a flow in which the fw actively measured the temperature. This is not needed anymore, as the fw performs measurements by itself, without the driver triggering them, and the current cadence in which the fw performs such measurements is sufficient. In addition, in some time-sensitive scenarios, in which the driver asks the fw for an active measurement twice in a short time (<100ms), the fw asserts with code 0x20100801. Change the DTS measurement to _WITHOUT_MEASURE instead, so the fw will respond with the last measurement it has performed. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index fcad25ffd811..418e59b7c671 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -8,7 +8,7 @@ * Copyright(c) 2013 - 2014, 2019 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright(c) 2019 Intel Corporation + * Copyright(c) 2019 - 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014, 2019 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright(c) 2019 Intel Corporation + * Copyright(c) 2019 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -234,7 +234,7 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), }; struct iwl_ext_dts_measurement_cmd extcmd = { - .control_mode = cpu_to_le32(DTS_AUTOMATIC), + .control_mode = cpu_to_le32(DTS_DIRECT_WITHOUT_MEASURE), }; u32 cmdid; From cc4255eff523f25187bb95561642941de0e57497 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Fri, 31 Jan 2020 15:45:27 +0200 Subject: [PATCH 09/14] iwlwifi: mvm: avoid use after free for pmsr request When a FTM request is aborted, the driver sends the abort command to the fw and waits for a response. When the response arrives, the driver calls cfg80211_pmsr_complete() for that request. However, cfg80211 frees the requested data immediately after sending the abort command, so this may lead to use after free. Fix it by clearing the request data in the driver when the abort command arrives and ignoring the fw notification that will come afterwards. Signed-off-by: Avraham Stern Fixes: fc36ffda3267 ("iwlwifi: mvm: support FTM initiator") Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index f783d6d53b6f..6e1ea921c299 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -8,6 +8,7 @@ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * Copyright (C) 2018 Intel Corporation * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * Copyright (C) 2018 Intel Corporation * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -528,6 +530,8 @@ void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req) if (req != mvm->ftm_initiator.req) return; + iwl_mvm_ftm_reset(mvm); + if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD, LOCATION_GROUP, 0), 0, sizeof(cmd), &cmd)) @@ -641,7 +645,6 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) lockdep_assert_held(&mvm->mutex); if (!mvm->ftm_initiator.req) { - IWL_ERR(mvm, "Got FTM response but have no request?\n"); return; } From 12d47f0ea5e0aa63f19ba618da55a7c67850ca10 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Fri, 31 Jan 2020 15:45:28 +0200 Subject: [PATCH 10/14] iwlwifi: mvm: Check the sta is not NULL in iwl_mvm_cfg_he_sta() Fix a kernel panic by checking that the sta is not NULL. This could happen during a reconfig flow, as mac80211 moves the sta between all the states without really checking if the previous state was successfully set. So, if for some reason we failed to add back the station, subsequent calls to sta_state() callback will be done when the station is NULL. This would result in a following panic: BUG: unable to handle kernel NULL pointer dereference at 0000000000000040 IP: iwl_mvm_cfg_he_sta+0xfc/0x690 [iwlmvm] [..] Call Trace: iwl_mvm_mac_sta_state+0x629/0x6f0 [iwlmvm] drv_sta_state+0xf4/0x950 [mac80211] ieee80211_reconfig+0xa12/0x2180 [mac80211] ieee80211_restart_work+0xbb/0xe0 [mac80211] process_one_work+0x1e2/0x610 worker_thread+0x4d/0x3e0 [..] Signed-off-by: Andrei Otcheretianski Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 6717f25c46b1..8ecd1f6875de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -2037,7 +2035,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_ctxt_cmd.sta_id]); - if (IS_ERR(sta)) { + if (IS_ERR_OR_NULL(sta)) { rcu_read_unlock(); WARN(1, "Can't find STA to configure HE\n"); return; From b5b878e36c1836c0195575132cc7c199e5a34a7b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 31 Jan 2020 15:45:29 +0200 Subject: [PATCH 11/14] iwlwifi: mvm: fix TDLS discovery with the new firmware API I changed the API for asking for a session protection but I omitted the TDLS flows. Fix that now. Note that for the TDLS flow, we need to block until the session protection actually starts, so add this option to iwl_mvm_schedule_session_protection. This patch fixes a firmware assert in the TDLS flow since the old TIME_EVENT_CMD is not supported anymore by newer firwmare versions. Signed-off-by: Emmanuel Grumbach Fixes: fe959c7b2049 ("iwlwifi: mvm: use the new session protection command") Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 10 ++- .../wireless/intel/iwlwifi/mvm/time-event.c | 71 ++++++++++++++++--- .../wireless/intel/iwlwifi/mvm/time-event.h | 4 +- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8ecd1f6875de..02df603b6400 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3291,7 +3291,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) iwl_mvm_schedule_session_protection(mvm, vif, 900, - min_duration); + min_duration, false); else iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 1851719e9f4b..d781777b6b96 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -205,9 +205,15 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; - mutex_lock(&mvm->mutex); /* Protect the session to hear the TDLS setup response on the channel */ - iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); + mutex_lock(&mvm->mutex); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_schedule_session_protection(mvm, vif, duration, + duration, true); + else + iwl_mvm_protect_session(mvm, vif, duration, + duration, 100, true); mutex_unlock(&mvm->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 51b138673ddb..c0b420fe5e48 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1056,13 +1056,42 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } +static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) +{ + struct iwl_mvm *mvm = + container_of(notif_wait, struct iwl_mvm, notif_wait); + struct iwl_mvm_session_prot_notif *resp; + int resp_len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON(pkt->hdr.cmd != SESSION_PROTECTION_NOTIF || + pkt->hdr.group_id != MAC_CONF_GROUP)) + return true; + + if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { + IWL_ERR(mvm, "Invalid SESSION_PROTECTION_NOTIF response\n"); + return true; + } + + resp = (void *)pkt->data; + + if (!resp->status) + IWL_ERR(mvm, + "TIME_EVENT_NOTIFICATION received but not executed\n"); + + return true; +} + void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 duration, u32 min_duration) + u32 duration, u32 min_duration, + bool wait_for_notif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - + const u16 notif[] = { iwl_cmd_id(SESSION_PROTECTION_NOTIF, + MAC_CONF_GROUP, 0) }; + struct iwl_notification_wait wait_notif; struct iwl_mvm_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, @@ -1071,7 +1100,6 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), }; - int ret; lockdep_assert_held(&mvm->mutex); @@ -1092,14 +1120,35 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", le32_to_cpu(cmd.duration_tu)); - ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, - MAC_CONF_GROUP, 0), - 0, sizeof(cmd), &cmd); - if (ret) { + if (!wait_for_notif) { + if (iwl_mvm_send_cmd_pdu(mvm, + iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd)) { + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD\n"); + spin_lock_bh(&mvm->time_event_lock); + iwl_mvm_te_clear_data(mvm, te_data); + spin_unlock_bh(&mvm->time_event_lock); + } + + return; + } + + iwl_init_notification_wait(&mvm->notif_wait, &wait_notif, + notif, ARRAY_SIZE(notif), + iwl_mvm_session_prot_notif, NULL); + + if (iwl_mvm_send_cmd_pdu(mvm, + iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd)) { IWL_ERR(mvm, - "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); - spin_lock_bh(&mvm->time_event_lock); - iwl_mvm_te_clear_data(mvm, te_data); - spin_unlock_bh(&mvm->time_event_lock); + "Couldn't send the SESSION_PROTECTION_CMD\n"); + iwl_remove_notification(&mvm->notif_wait, &wait_notif); + } else if (iwl_wait_notification(&mvm->notif_wait, &wait_notif, + TU_TO_JIFFIES(100))) { + IWL_ERR(mvm, + "Failed to protect session until session protection\n"); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index df6832b79666..3186d7e40567 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -250,10 +250,12 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) * @mvm: the mvm component * @vif: the virtual interface for which the protection issued * @duration: the duration of the protection + * @wait_for_notif: if true, will block until the start of the protection */ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 duration, u32 min_duration); + u32 duration, u32 min_duration, + bool wait_for_notif); /** * iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF From 577ddbee1f43a355cc733829da96c8ffb3b99cc5 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 31 Jan 2020 15:45:30 +0200 Subject: [PATCH 12/14] iwlwifi: d3: read all FW CPUs error info Continue the wakeup flow only if no FW CPUs have an error If we don't check for error in all FW CPUs the driver can think based on one CPU that the FW is operational and try to access and send commands. Also, handle the error_id endianness correctly as le32 Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 54 ++++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 8878409d2f07..22a32eb10f01 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1897,27 +1897,55 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, ieee80211_resume_disconnect(vif); } -static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +static bool iwl_mvm_rt_status(struct iwl_trans *trans, u32 base, u32 *err_id) { - u32 base = mvm->trans->dbg.lmac_error_event_table[0]; struct error_table_start { /* cf. struct iwl_error_event_table */ u32 valid; - u32 error_id; + __le32 err_id; } err_info; - iwl_trans_read_mem_bytes(mvm->trans, base, - &err_info, sizeof(err_info)); + if (!base) + return false; - if (err_info.valid && - err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { - struct cfg80211_wowlan_wakeup wakeup = { - .rfkill_release = true, - }; - ieee80211_report_wowlan_wakeup(vif, &wakeup, GFP_KERNEL); + iwl_trans_read_mem_bytes(trans, base, + &err_info, sizeof(err_info)); + if (err_info.valid && err_id) + *err_id = le32_to_cpu(err_info.err_id); + + return !!err_info.valid; +} + +static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + u32 err_id; + + /* check for lmac1 error */ + if (iwl_mvm_rt_status(mvm->trans, + mvm->trans->dbg.lmac_error_event_table[0], + &err_id)) { + if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN) { + struct cfg80211_wowlan_wakeup wakeup = { + .rfkill_release = true, + }; + ieee80211_report_wowlan_wakeup(vif, &wakeup, + GFP_KERNEL); + } + return true; } - return err_info.valid; + + /* check if we have lmac2 set and check for error */ + if (iwl_mvm_rt_status(mvm->trans, + mvm->trans->dbg.lmac_error_event_table[1], NULL)) + return true; + + /* check for umac error */ + if (iwl_mvm_rt_status(mvm->trans, + mvm->trans->dbg.umac_error_event_table, NULL)) + return true; + + return false; } static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) From ebe8e6116ac49d182b060f843904caf5eacf5b87 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Mon, 3 Feb 2020 14:01:57 +0800 Subject: [PATCH 13/14] rtw88: Fix return value of rtw_wow_check_fw_status Clang warns that ret is used uninitialzed. And we found that actually the return type should be "int" instead of "bool". Fixes: 44bc17f7f5b3 ("rtw88: support wowlan feature for 8822c") Link: https://github.com/ClangBuiltLinux/linux/issues/850 Reported-by: Nathan Chancellor Signed-off-by: Chin-Yen Lee Signed-off-by: Yan-Hsuan Chuang Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor # build Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/wow.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/wow.c b/drivers/net/wireless/realtek/rtw88/wow.c index af5c27e1bb07..4820dca958dd 100644 --- a/drivers/net/wireless/realtek/rtw88/wow.c +++ b/drivers/net/wireless/realtek/rtw88/wow.c @@ -281,27 +281,26 @@ static void rtw_wow_rx_dma_start(struct rtw_dev *rtwdev) rtw_write32_clr(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE); } -static bool rtw_wow_check_fw_status(struct rtw_dev *rtwdev, bool wow_enable) +static int rtw_wow_check_fw_status(struct rtw_dev *rtwdev, bool wow_enable) { - bool ret; - /* wait 100ms for wow firmware to finish work */ msleep(100); if (wow_enable) { - if (!rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON)) - ret = 0; + if (rtw_read8(rtwdev, REG_WOWLAN_WAKE_REASON)) + goto wow_fail; } else { - if (rtw_read32_mask(rtwdev, REG_FE1IMR, BIT_FS_RXDONE) == 0 && - rtw_read32_mask(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE) == 0) - ret = 0; + if (rtw_read32_mask(rtwdev, REG_FE1IMR, BIT_FS_RXDONE) || + rtw_read32_mask(rtwdev, REG_RXPKT_NUM, BIT_RW_RELEASE)) + goto wow_fail; } - if (ret) - rtw_err(rtwdev, "failed to check wow status %s\n", - wow_enable ? "enabled" : "disabled"); + return 0; - return ret; +wow_fail: + rtw_err(rtwdev, "failed to check wow status %s\n", + wow_enable ? "enabled" : "disabled"); + return -EBUSY; } static void rtw_wow_fw_security_type_iter(struct ieee80211_hw *hw, From d08f3010f4a32eec3c8aa771f03a1b342a1472fa Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 7 Feb 2020 11:29:51 +0100 Subject: [PATCH 14/14] mt76: mt7615: fix max_nss in mt7615_eeprom_parse_hw_cap Fix u8 cast reading max_nss from MT_TOP_STRAP_STA register in mt7615_eeprom_parse_hw_cap routine Fixes: acf5457fd99db ("mt76: mt7615: read {tx,rx} mask from eeprom") Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index eccad4987ac8..17e277bf39e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -92,8 +92,9 @@ static int mt7615_check_eeprom(struct mt76_dev *dev) static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) { - u8 val, *eeprom = dev->mt76.eeprom.data; + u8 *eeprom = dev->mt76.eeprom.data; u8 tx_mask, rx_mask, max_nss; + u32 val; val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL, eeprom[MT_EE_WIFI_CONF]);