aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c104
1 files changed, 77 insertions, 27 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index c64d864799c..994c8c263dc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -61,6 +61,7 @@
61 * 61 *
62 *****************************************************************************/ 62 *****************************************************************************/
63 63
64#include <linux/etherdevice.h>
64#include <net/cfg80211.h> 65#include <net/cfg80211.h>
65#include <net/ipv6.h> 66#include <net/ipv6.h>
66#include "iwl-modparams.h" 67#include "iwl-modparams.h"
@@ -192,6 +193,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
192 sizeof(wkc), &wkc); 193 sizeof(wkc), &wkc);
193 data->error = ret != 0; 194 data->error = ret != 0;
194 195
196 mvm->ptk_ivlen = key->iv_len;
197 mvm->ptk_icvlen = key->icv_len;
198 mvm->gtk_ivlen = key->iv_len;
199 mvm->gtk_icvlen = key->icv_len;
200
195 /* don't upload key again */ 201 /* don't upload key again */
196 goto out_unlock; 202 goto out_unlock;
197 } 203 }
@@ -304,9 +310,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
304 */ 310 */
305 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 311 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
306 key->hw_key_idx = 0; 312 key->hw_key_idx = 0;
313 mvm->ptk_ivlen = key->iv_len;
314 mvm->ptk_icvlen = key->icv_len;
307 } else { 315 } else {
308 data->gtk_key_idx++; 316 data->gtk_key_idx++;
309 key->hw_key_idx = data->gtk_key_idx; 317 key->hw_key_idx = data->gtk_key_idx;
318 mvm->gtk_ivlen = key->iv_len;
319 mvm->gtk_icvlen = key->icv_len;
310 } 320 }
311 321
312 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); 322 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
@@ -649,6 +659,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
649 /* We reprogram keys and shouldn't allocate new key indices */ 659 /* We reprogram keys and shouldn't allocate new key indices */
650 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); 660 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
651 661
662 mvm->ptk_ivlen = 0;
663 mvm->ptk_icvlen = 0;
664 mvm->ptk_ivlen = 0;
665 mvm->ptk_icvlen = 0;
666
652 /* 667 /*
653 * The D3 firmware still hardcodes the AP station ID for the 668 * The D3 firmware still hardcodes the AP station ID for the
654 * BSS we're associated with as 0. As a result, we have to move 669 * BSS we're associated with as 0. As a result, we have to move
@@ -783,7 +798,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
783 struct iwl_wowlan_status *status; 798 struct iwl_wowlan_status *status;
784 u32 reasons; 799 u32 reasons;
785 int ret, len; 800 int ret, len;
786 bool pkt8023 = false;
787 struct sk_buff *pkt = NULL; 801 struct sk_buff *pkt = NULL;
788 802
789 iwl_trans_read_mem_bytes(mvm->trans, base, 803 iwl_trans_read_mem_bytes(mvm->trans, base,
@@ -824,7 +838,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
824 status = (void *)cmd.resp_pkt->data; 838 status = (void *)cmd.resp_pkt->data;
825 839
826 if (len - sizeof(struct iwl_cmd_header) != 840 if (len - sizeof(struct iwl_cmd_header) !=
827 sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { 841 sizeof(*status) +
842 ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
828 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); 843 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
829 goto out; 844 goto out;
830 } 845 }
@@ -836,61 +851,96 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
836 goto report; 851 goto report;
837 } 852 }
838 853
839 if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { 854 if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)
840 wakeup.magic_pkt = true; 855 wakeup.magic_pkt = true;
841 pkt8023 = true;
842 }
843 856
844 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { 857 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
845 wakeup.pattern_idx = 858 wakeup.pattern_idx =
846 le16_to_cpu(status->pattern_number); 859 le16_to_cpu(status->pattern_number);
847 pkt8023 = true;
848 }
849 860
850 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | 861 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
851 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) 862 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
852 wakeup.disconnect = true; 863 wakeup.disconnect = true;
853 864
854 if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { 865 if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)
855 wakeup.gtk_rekey_failure = true; 866 wakeup.gtk_rekey_failure = true;
856 pkt8023 = true;
857 }
858 867
859 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { 868 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
860 wakeup.rfkill_release = true; 869 wakeup.rfkill_release = true;
861 pkt8023 = true;
862 }
863 870
864 if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { 871 if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)
865 wakeup.eap_identity_req = true; 872 wakeup.eap_identity_req = true;
866 pkt8023 = true;
867 }
868 873
869 if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { 874 if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)
870 wakeup.four_way_handshake = true; 875 wakeup.four_way_handshake = true;
871 pkt8023 = true;
872 }
873 876
874 if (status->wake_packet_bufsize) { 877 if (status->wake_packet_bufsize) {
875 u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); 878 int pktsize = le32_to_cpu(status->wake_packet_bufsize);
876 u32 pktlen = le32_to_cpu(status->wake_packet_length); 879 int pktlen = le32_to_cpu(status->wake_packet_length);
880 const u8 *pktdata = status->wake_packet;
881 struct ieee80211_hdr *hdr = (void *)pktdata;
882 int truncated = pktlen - pktsize;
883
884 /* this would be a firmware bug */
885 if (WARN_ON_ONCE(truncated < 0))
886 truncated = 0;
887
888 if (ieee80211_is_data(hdr->frame_control)) {
889 int hdrlen = ieee80211_hdrlen(hdr->frame_control);
890 int ivlen = 0, icvlen = 4; /* also FCS */
877 891
878 if (pkt8023) {
879 pkt = alloc_skb(pktsize, GFP_KERNEL); 892 pkt = alloc_skb(pktsize, GFP_KERNEL);
880 if (!pkt) 893 if (!pkt)
881 goto report; 894 goto report;
882 memcpy(skb_put(pkt, pktsize), status->wake_packet, 895
883 pktsize); 896 memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen);
897 pktdata += hdrlen;
898 pktsize -= hdrlen;
899
900 if (ieee80211_has_protected(hdr->frame_control)) {
901 if (is_multicast_ether_addr(hdr->addr1)) {
902 ivlen = mvm->gtk_ivlen;
903 icvlen += mvm->gtk_icvlen;
904 } else {
905 ivlen = mvm->ptk_ivlen;
906 icvlen += mvm->ptk_icvlen;
907 }
908 }
909
910 /* if truncated, FCS/ICV is (partially) gone */
911 if (truncated >= icvlen) {
912 icvlen = 0;
913 truncated -= icvlen;
914 } else {
915 icvlen -= truncated;
916 truncated = 0;
917 }
918
919 pktsize -= ivlen + icvlen;
920 pktdata += ivlen;
921
922 memcpy(skb_put(pkt, pktsize), pktdata, pktsize);
923
884 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) 924 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
885 goto report; 925 goto report;
886 wakeup.packet = pkt->data; 926 wakeup.packet = pkt->data;
887 wakeup.packet_present_len = pkt->len; 927 wakeup.packet_present_len = pkt->len;
888 wakeup.packet_len = pkt->len - (pktlen - pktsize); 928 wakeup.packet_len = pkt->len - truncated;
889 wakeup.packet_80211 = false; 929 wakeup.packet_80211 = false;
890 } else { 930 } else {
931 int fcslen = 4;
932
933 if (truncated >= 4) {
934 truncated -= 4;
935 fcslen = 0;
936 } else {
937 fcslen -= truncated;
938 truncated = 0;
939 }
940 pktsize -= fcslen;
891 wakeup.packet = status->wake_packet; 941 wakeup.packet = status->wake_packet;
892 wakeup.packet_present_len = pktsize; 942 wakeup.packet_present_len = pktsize;
893 wakeup.packet_len = pktlen; 943 wakeup.packet_len = pktlen - truncated;
894 wakeup.packet_80211 = true; 944 wakeup.packet_80211 = true;
895 } 945 }
896 } 946 }