aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/d3.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-13 03:40:34 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-13 03:40:34 -0500
commit42a2d923cc349583ebf6fdd52a7d35e1c2f7e6bd (patch)
tree2b2b0c03b5389c1301800119333967efafd994ca /drivers/net/wireless/iwlwifi/mvm/d3.c
parent5cbb3d216e2041700231bcfc383ee5f8b7fc8b74 (diff)
parent75ecab1df14d90e86cebef9ec5c76befde46e65f (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: 1) The addition of nftables. No longer will we need protocol aware firewall filtering modules, it can all live in userspace. At the core of nftables is a, for lack of a better term, virtual machine that executes byte codes to inspect packet or metadata (arriving interface index, etc.) and make verdict decisions. Besides support for loading packet contents and comparing them, the interpreter supports lookups in various datastructures as fundamental operations. For example sets are supports, and therefore one could create a set of whitelist IP address entries which have ACCEPT verdicts attached to them, and use the appropriate byte codes to do such lookups. Since the interpreted code is composed in userspace, userspace can do things like optimize things before giving it to the kernel. Another major improvement is the capability of atomically updating portions of the ruleset. In the existing netfilter implementation, one has to update the entire rule set in order to make a change and this is very expensive. Userspace tools exist to create nftables rules using existing netfilter rule sets, but both kernel implementations will need to co-exist for quite some time as we transition from the old to the new stuff. Kudos to Patrick McHardy, Pablo Neira Ayuso, and others who have worked so hard on this. 2) Daniel Borkmann and Hannes Frederic Sowa made several improvements to our pseudo-random number generator, mostly used for things like UDP port randomization and netfitler, amongst other things. In particular the taus88 generater is updated to taus113, and test cases are added. 3) Support 64-bit rates in HTB and TBF schedulers, from Eric Dumazet and Yang Yingliang. 4) Add support for new 577xx tigon3 chips to tg3 driver, from Nithin Sujir. 5) Fix two fatal flaws in TCP dynamic right sizing, from Eric Dumazet, Neal Cardwell, and Yuchung Cheng. 6) Allow IP_TOS and IP_TTL to be specified in sendmsg() ancillary control message data, much like other socket option attributes. From Francesco Fusco. 7) Allow applications to specify a cap on the rate computed automatically by the kernel for pacing flows, via a new SO_MAX_PACING_RATE socket option. From Eric Dumazet. 8) Make the initial autotuned send buffer sizing in TCP more closely reflect actual needs, from Eric Dumazet. 9) Currently early socket demux only happens for TCP sockets, but we can do it for connected UDP sockets too. Implementation from Shawn Bohrer. 10) Refactor inet socket demux with the goal of improving hash demux performance for listening sockets. With the main goals being able to use RCU lookups on even request sockets, and eliminating the listening lock contention. From Eric Dumazet. 11) The bonding layer has many demuxes in it's fast path, and an RCU conversion was started back in 3.11, several changes here extend the RCU usage to even more locations. From Ding Tianhong and Wang Yufen, based upon suggestions by Nikolay Aleksandrov and Veaceslav Falico. 12) Allow stackability of segmentation offloads to, in particular, allow segmentation offloading over tunnels. From Eric Dumazet. 13) Significantly improve the handling of secret keys we input into the various hash functions in the inet hashtables, TCP fast open, as well as syncookies. From Hannes Frederic Sowa. The key fundamental operation is "net_get_random_once()" which uses static keys. Hannes even extended this to ipv4/ipv6 fragmentation handling and our generic flow dissector. 14) The generic driver layer takes care now to set the driver data to NULL on device removal, so it's no longer necessary for drivers to explicitly set it to NULL any more. Many drivers have been cleaned up in this way, from Jingoo Han. 15) Add a BPF based packet scheduler classifier, from Daniel Borkmann. 16) Improve CRC32 interfaces and generic SKB checksum iterators so that SCTP's checksumming can more cleanly be handled. Also from Daniel Borkmann. 17) Add a new PMTU discovery mode, IP_PMTUDISC_INTERFACE, which forces using the interface MTU value. This helps avoid PMTU attacks, particularly on DNS servers. From Hannes Frederic Sowa. 18) Use generic XPS for transmit queue steering rather than internal (re-)implementation in virtio-net. From Jason Wang. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1622 commits) random32: add test cases for taus113 implementation random32: upgrade taus88 generator to taus113 from errata paper random32: move rnd_state to linux/random.h random32: add prandom_reseed_late() and call when nonblocking pool becomes initialized random32: add periodic reseeding random32: fix off-by-one in seeding requirement PHY: Add RTL8201CP phy_driver to realtek xtsonic: add missing platform_set_drvdata() in xtsonic_probe() macmace: add missing platform_set_drvdata() in mace_probe() ethernet/arc/arc_emac: add missing platform_set_drvdata() in arc_emac_probe() ipv6: protect for_each_sk_fl_rcu in mem_check with rcu_read_lock_bh vlan: Implement vlan_dev_get_egress_qos_mask as an inline. ixgbe: add warning when max_vfs is out of range. igb: Update link modes display in ethtool netfilter: push reasm skb through instead of original frag skbs ip6_output: fragment outgoing reassembled skb properly MAINTAINERS: mv643xx_eth: take over maintainership from Lennart net_sched: tbf: support of 64bit rates ixgbe: deleting dfwd stations out of order can cause null ptr deref ixgbe: fix build err, num_rx_queues is only available with CONFIG_RPS ...
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c515
1 files changed, 476 insertions, 39 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 417639f77b01..6f45966817bb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -67,6 +67,7 @@
67#include <net/cfg80211.h> 67#include <net/cfg80211.h>
68#include <net/ipv6.h> 68#include <net/ipv6.h>
69#include <net/tcp.h> 69#include <net/tcp.h>
70#include <net/addrconf.h>
70#include "iwl-modparams.h" 71#include "iwl-modparams.h"
71#include "fw-api.h" 72#include "fw-api.h"
72#include "mvm.h" 73#include "mvm.h"
@@ -381,14 +382,74 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
381 union { 382 union {
382 struct iwl_proto_offload_cmd_v1 v1; 383 struct iwl_proto_offload_cmd_v1 v1;
383 struct iwl_proto_offload_cmd_v2 v2; 384 struct iwl_proto_offload_cmd_v2 v2;
385 struct iwl_proto_offload_cmd_v3_small v3s;
386 struct iwl_proto_offload_cmd_v3_large v3l;
384 } cmd = {}; 387 } cmd = {};
388 struct iwl_host_cmd hcmd = {
389 .id = PROT_OFFLOAD_CONFIG_CMD,
390 .flags = CMD_SYNC,
391 .data[0] = &cmd,
392 .dataflags[0] = IWL_HCMD_DFL_DUP,
393 };
385 struct iwl_proto_offload_cmd_common *common; 394 struct iwl_proto_offload_cmd_common *common;
386 u32 enabled = 0, size; 395 u32 enabled = 0, size;
396 u32 capa_flags = mvm->fw->ucode_capa.flags;
387#if IS_ENABLED(CONFIG_IPV6) 397#if IS_ENABLED(CONFIG_IPV6)
388 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 398 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
389 int i; 399 int i;
390 400
391 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { 401 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
402 capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
403 struct iwl_ns_config *nsc;
404 struct iwl_targ_addr *addrs;
405 int n_nsc, n_addrs;
406 int c;
407
408 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
409 nsc = cmd.v3s.ns_config;
410 n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
411 addrs = cmd.v3s.targ_addrs;
412 n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
413 } else {
414 nsc = cmd.v3l.ns_config;
415 n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
416 addrs = cmd.v3l.targ_addrs;
417 n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
418 }
419
420 if (mvmvif->num_target_ipv6_addrs)
421 enabled |= IWL_D3_PROTO_OFFLOAD_NS;
422
423 /*
424 * For each address we have (and that will fit) fill a target
425 * address struct and combine for NS offload structs with the
426 * solicited node addresses.
427 */
428 for (i = 0, c = 0;
429 i < mvmvif->num_target_ipv6_addrs &&
430 i < n_addrs && c < n_nsc; i++) {
431 struct in6_addr solicited_addr;
432 int j;
433
434 addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
435 &solicited_addr);
436 for (j = 0; j < c; j++)
437 if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
438 &solicited_addr) == 0)
439 break;
440 if (j == c)
441 c++;
442 addrs[i].addr = mvmvif->target_ipv6_addrs[i];
443 addrs[i].config_num = cpu_to_le32(j);
444 nsc[j].dest_ipv6_addr = solicited_addr;
445 memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
446 }
447
448 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
449 cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
450 else
451 cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
452 } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
392 if (mvmvif->num_target_ipv6_addrs) { 453 if (mvmvif->num_target_ipv6_addrs) {
393 enabled |= IWL_D3_PROTO_OFFLOAD_NS; 454 enabled |= IWL_D3_PROTO_OFFLOAD_NS;
394 memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); 455 memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
@@ -419,7 +480,13 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
419 } 480 }
420#endif 481#endif
421 482
422 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { 483 if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
484 common = &cmd.v3s.common;
485 size = sizeof(cmd.v3s);
486 } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
487 common = &cmd.v3l.common;
488 size = sizeof(cmd.v3l);
489 } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
423 common = &cmd.v2.common; 490 common = &cmd.v2.common;
424 size = sizeof(cmd.v2); 491 size = sizeof(cmd.v2);
425 } else { 492 } else {
@@ -438,8 +505,8 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
438 505
439 common->enabled = cpu_to_le32(enabled); 506 common->enabled = cpu_to_le32(enabled);
440 507
441 return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, 508 hcmd.len[0] = size;
442 size, &cmd); 509 return iwl_mvm_send_cmd(mvm, &hcmd);
443} 510}
444 511
445enum iwl_mvm_tcp_packet_type { 512enum iwl_mvm_tcp_packet_type {
@@ -793,6 +860,74 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
793 return 0; 860 return 0;
794} 861}
795 862
863static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
864 struct ieee80211_vif *vif)
865{
866 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
867 struct iwl_nonqos_seq_query_cmd query_cmd = {
868 .get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_GET),
869 .mac_id_n_color =
870 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
871 mvmvif->color)),
872 };
873 struct iwl_host_cmd cmd = {
874 .id = NON_QOS_TX_COUNTER_CMD,
875 .flags = CMD_SYNC | CMD_WANT_SKB,
876 };
877 int err;
878 u32 size;
879
880 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) {
881 cmd.data[0] = &query_cmd;
882 cmd.len[0] = sizeof(query_cmd);
883 }
884
885 err = iwl_mvm_send_cmd(mvm, &cmd);
886 if (err)
887 return err;
888
889 size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
890 size -= sizeof(cmd.resp_pkt->hdr);
891 if (size < sizeof(__le16)) {
892 err = -EINVAL;
893 } else {
894 err = le16_to_cpup((__le16 *)cmd.resp_pkt->data);
895 /* new API returns next, not last-used seqno */
896 if (mvm->fw->ucode_capa.flags &
897 IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)
898 err -= 0x10;
899 }
900
901 iwl_free_resp(&cmd);
902 return err;
903}
904
905void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
906{
907 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
908 struct iwl_nonqos_seq_query_cmd query_cmd = {
909 .get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_SET),
910 .mac_id_n_color =
911 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
912 mvmvif->color)),
913 .value = cpu_to_le16(mvmvif->seqno),
914 };
915
916 /* return if called during restart, not resume from D3 */
917 if (!mvmvif->seqno_valid)
918 return;
919
920 mvmvif->seqno_valid = false;
921
922 if (!(mvm->fw->ucode_capa.flags &
923 IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API))
924 return;
925
926 if (iwl_mvm_send_cmd_pdu(mvm, NON_QOS_TX_COUNTER_CMD, CMD_SYNC,
927 sizeof(query_cmd), &query_cmd))
928 IWL_ERR(mvm, "failed to set non-QoS seqno\n");
929}
930
796static int __iwl_mvm_suspend(struct ieee80211_hw *hw, 931static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
797 struct cfg80211_wowlan *wowlan, 932 struct cfg80211_wowlan *wowlan,
798 bool test) 933 bool test)
@@ -829,7 +964,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
829 }; 964 };
830 int ret, i; 965 int ret, i;
831 int len __maybe_unused; 966 int len __maybe_unused;
832 u16 seq;
833 u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; 967 u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
834 968
835 if (!wowlan) { 969 if (!wowlan) {
@@ -872,26 +1006,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
872 1006
873 mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; 1007 mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
874 1008
875 /*
876 * The D3 firmware still hardcodes the AP station ID for the
877 * BSS we're associated with as 0. Store the real STA ID here
878 * and assign 0. When we leave this function, we'll restore
879 * the original value for the resume code.
880 */
881 old_ap_sta_id = mvm_ap_sta->sta_id;
882 mvm_ap_sta->sta_id = 0;
883 mvmvif->ap_sta_id = 0;
884
885 /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ 1009 /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
886 1010
887 wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; 1011 wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
888 1012
889 /* 1013 /* Query the last used seqno and set it */
890 * We know the last used seqno, and the uCode expects to know that 1014 ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
891 * one, it will increment before TX. 1015 if (ret < 0)
892 */ 1016 goto out_noreset;
893 seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ; 1017 wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret);
894 wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq);
895 1018
896 /* 1019 /*
897 * For QoS counters, we store the one to use next, so subtract 0x10 1020 * For QoS counters, we store the one to use next, so subtract 0x10
@@ -899,7 +1022,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
899 * increment after using the value (i.e. store the next value to use). 1022 * increment after using the value (i.e. store the next value to use).
900 */ 1023 */
901 for (i = 0; i < IWL_MAX_TID_COUNT; i++) { 1024 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
902 seq = mvm_ap_sta->tid_data[i].seq_number; 1025 u16 seq = mvm_ap_sta->tid_data[i].seq_number;
903 seq -= 0x10; 1026 seq -= 0x10;
904 wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); 1027 wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
905 } 1028 }
@@ -945,6 +1068,16 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
945 iwl_trans_stop_device(mvm->trans); 1068 iwl_trans_stop_device(mvm->trans);
946 1069
947 /* 1070 /*
1071 * The D3 firmware still hardcodes the AP station ID for the
1072 * BSS we're associated with as 0. Store the real STA ID here
1073 * and assign 0. When we leave this function, we'll restore
1074 * the original value for the resume code.
1075 */
1076 old_ap_sta_id = mvm_ap_sta->sta_id;
1077 mvm_ap_sta->sta_id = 0;
1078 mvmvif->ap_sta_id = 0;
1079
1080 /*
948 * Set the HW restart bit -- this is mostly true as we're 1081 * Set the HW restart bit -- this is mostly true as we're
949 * going to load new firmware and reprogram that, though 1082 * going to load new firmware and reprogram that, though
950 * the reprogramming is going to be manual to avoid adding 1083 * the reprogramming is going to be manual to avoid adding
@@ -1059,6 +1192,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
1059 if (ret) 1192 if (ret)
1060 goto out; 1193 goto out;
1061 1194
1195 ret = iwl_mvm_power_update_device_mode(mvm);
1196 if (ret)
1197 goto out;
1198
1062 ret = iwl_mvm_power_update_mode(mvm, vif); 1199 ret = iwl_mvm_power_update_mode(mvm, vif);
1063 if (ret) 1200 if (ret)
1064 goto out; 1201 goto out;
@@ -1109,16 +1246,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
1109 return __iwl_mvm_suspend(hw, wowlan, false); 1246 return __iwl_mvm_suspend(hw, wowlan, false);
1110} 1247}
1111 1248
1249/* converted data from the different status responses */
1250struct iwl_wowlan_status_data {
1251 u16 pattern_number;
1252 u16 qos_seq_ctr[8];
1253 u32 wakeup_reasons;
1254 u32 wake_packet_length;
1255 u32 wake_packet_bufsize;
1256 const u8 *wake_packet;
1257};
1258
1112static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, 1259static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1113 struct ieee80211_vif *vif, 1260 struct ieee80211_vif *vif,
1114 struct iwl_wowlan_status *status) 1261 struct iwl_wowlan_status_data *status)
1115{ 1262{
1116 struct sk_buff *pkt = NULL; 1263 struct sk_buff *pkt = NULL;
1117 struct cfg80211_wowlan_wakeup wakeup = { 1264 struct cfg80211_wowlan_wakeup wakeup = {
1118 .pattern_idx = -1, 1265 .pattern_idx = -1,
1119 }; 1266 };
1120 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; 1267 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
1121 u32 reasons = le32_to_cpu(status->wakeup_reasons); 1268 u32 reasons = status->wakeup_reasons;
1122 1269
1123 if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { 1270 if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
1124 wakeup_report = NULL; 1271 wakeup_report = NULL;
@@ -1130,7 +1277,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1130 1277
1131 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) 1278 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
1132 wakeup.pattern_idx = 1279 wakeup.pattern_idx =
1133 le16_to_cpu(status->pattern_number); 1280 status->pattern_number;
1134 1281
1135 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | 1282 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
1136 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) 1283 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
@@ -1158,8 +1305,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1158 wakeup.tcp_match = true; 1305 wakeup.tcp_match = true;
1159 1306
1160 if (status->wake_packet_bufsize) { 1307 if (status->wake_packet_bufsize) {
1161 int pktsize = le32_to_cpu(status->wake_packet_bufsize); 1308 int pktsize = status->wake_packet_bufsize;
1162 int pktlen = le32_to_cpu(status->wake_packet_length); 1309 int pktlen = status->wake_packet_length;
1163 const u8 *pktdata = status->wake_packet; 1310 const u8 *pktdata = status->wake_packet;
1164 struct ieee80211_hdr *hdr = (void *)pktdata; 1311 struct ieee80211_hdr *hdr = (void *)pktdata;
1165 int truncated = pktlen - pktsize; 1312 int truncated = pktlen - pktsize;
@@ -1239,8 +1386,229 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1239 kfree_skb(pkt); 1386 kfree_skb(pkt);
1240} 1387}
1241 1388
1389static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc,
1390 struct ieee80211_key_seq *seq)
1391{
1392 u64 pn;
1393
1394 pn = le64_to_cpu(sc->pn);
1395 seq->ccmp.pn[0] = pn >> 40;
1396 seq->ccmp.pn[1] = pn >> 32;
1397 seq->ccmp.pn[2] = pn >> 24;
1398 seq->ccmp.pn[3] = pn >> 16;
1399 seq->ccmp.pn[4] = pn >> 8;
1400 seq->ccmp.pn[5] = pn;
1401}
1402
1403static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,
1404 struct ieee80211_key_seq *seq)
1405{
1406 seq->tkip.iv32 = le32_to_cpu(sc->iv32);
1407 seq->tkip.iv16 = le16_to_cpu(sc->iv16);
1408}
1409
1410static void iwl_mvm_set_aes_rx_seq(struct aes_sc *scs,
1411 struct ieee80211_key_conf *key)
1412{
1413 int tid;
1414
1415 BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
1416
1417 for (tid = 0; tid < IWL_NUM_RSC; tid++) {
1418 struct ieee80211_key_seq seq = {};
1419
1420 iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
1421 ieee80211_set_key_rx_seq(key, tid, &seq);
1422 }
1423}
1424
1425static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
1426 struct ieee80211_key_conf *key)
1427{
1428 int tid;
1429
1430 BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
1431
1432 for (tid = 0; tid < IWL_NUM_RSC; tid++) {
1433 struct ieee80211_key_seq seq = {};
1434
1435 iwl_mvm_tkip_sc_to_seq(&scs[tid], &seq);
1436 ieee80211_set_key_rx_seq(key, tid, &seq);
1437 }
1438}
1439
1440static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
1441 struct iwl_wowlan_status_v6 *status)
1442{
1443 union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc;
1444
1445 switch (key->cipher) {
1446 case WLAN_CIPHER_SUITE_CCMP:
1447 iwl_mvm_set_aes_rx_seq(rsc->aes.multicast_rsc, key);
1448 break;
1449 case WLAN_CIPHER_SUITE_TKIP:
1450 iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key);
1451 break;
1452 default:
1453 WARN_ON(1);
1454 }
1455}
1456
1457struct iwl_mvm_d3_gtk_iter_data {
1458 struct iwl_wowlan_status_v6 *status;
1459 void *last_gtk;
1460 u32 cipher;
1461 bool find_phase, unhandled_cipher;
1462 int num_keys;
1463};
1464
1465static void iwl_mvm_d3_update_gtks(struct ieee80211_hw *hw,
1466 struct ieee80211_vif *vif,
1467 struct ieee80211_sta *sta,
1468 struct ieee80211_key_conf *key,
1469 void *_data)
1470{
1471 struct iwl_mvm_d3_gtk_iter_data *data = _data;
1472
1473 if (data->unhandled_cipher)
1474 return;
1475
1476 switch (key->cipher) {
1477 case WLAN_CIPHER_SUITE_WEP40:
1478 case WLAN_CIPHER_SUITE_WEP104:
1479 /* ignore WEP completely, nothing to do */
1480 return;
1481 case WLAN_CIPHER_SUITE_CCMP:
1482 case WLAN_CIPHER_SUITE_TKIP:
1483 /* we support these */
1484 break;
1485 default:
1486 /* everything else (even CMAC for MFP) - disconnect from AP */
1487 data->unhandled_cipher = true;
1488 return;
1489 }
1490
1491 data->num_keys++;
1492
1493 /*
1494 * pairwise key - update sequence counters only;
1495 * note that this assumes no TDLS sessions are active
1496 */
1497 if (sta) {
1498 struct ieee80211_key_seq seq = {};
1499 union iwl_all_tsc_rsc *sc = &data->status->gtk.rsc.all_tsc_rsc;
1500
1501 if (data->find_phase)
1502 return;
1503
1504 switch (key->cipher) {
1505 case WLAN_CIPHER_SUITE_CCMP:
1506 iwl_mvm_aes_sc_to_seq(&sc->aes.tsc, &seq);
1507 iwl_mvm_set_aes_rx_seq(sc->aes.unicast_rsc, key);
1508 break;
1509 case WLAN_CIPHER_SUITE_TKIP:
1510 iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
1511 iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
1512 break;
1513 }
1514 ieee80211_set_key_tx_seq(key, &seq);
1515
1516 /* that's it for this key */
1517 return;
1518 }
1519
1520 if (data->find_phase) {
1521 data->last_gtk = key;
1522 data->cipher = key->cipher;
1523 return;
1524 }
1525
1526 if (data->status->num_of_gtk_rekeys)
1527 ieee80211_remove_key(key);
1528 else if (data->last_gtk == key)
1529 iwl_mvm_set_key_rx_seq(key, data->status);
1530}
1531
1532static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
1533 struct ieee80211_vif *vif,
1534 struct iwl_wowlan_status_v6 *status)
1535{
1536 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1537 struct iwl_mvm_d3_gtk_iter_data gtkdata = {
1538 .status = status,
1539 };
1540
1541 if (!status || !vif->bss_conf.bssid)
1542 return false;
1543
1544 /* find last GTK that we used initially, if any */
1545 gtkdata.find_phase = true;
1546 ieee80211_iter_keys(mvm->hw, vif,
1547 iwl_mvm_d3_update_gtks, &gtkdata);
1548 /* not trying to keep connections with MFP/unhandled ciphers */
1549 if (gtkdata.unhandled_cipher)
1550 return false;
1551 if (!gtkdata.num_keys)
1552 return true;
1553 if (!gtkdata.last_gtk)
1554 return false;
1555
1556 /*
1557 * invalidate all other GTKs that might still exist and update
1558 * the one that we used
1559 */
1560 gtkdata.find_phase = false;
1561 ieee80211_iter_keys(mvm->hw, vif,
1562 iwl_mvm_d3_update_gtks, &gtkdata);
1563
1564 if (status->num_of_gtk_rekeys) {
1565 struct ieee80211_key_conf *key;
1566 struct {
1567 struct ieee80211_key_conf conf;
1568 u8 key[32];
1569 } conf = {
1570 .conf.cipher = gtkdata.cipher,
1571 .conf.keyidx = status->gtk.key_index,
1572 };
1573
1574 switch (gtkdata.cipher) {
1575 case WLAN_CIPHER_SUITE_CCMP:
1576 conf.conf.keylen = WLAN_KEY_LEN_CCMP;
1577 memcpy(conf.conf.key, status->gtk.decrypt_key,
1578 WLAN_KEY_LEN_CCMP);
1579 break;
1580 case WLAN_CIPHER_SUITE_TKIP:
1581 conf.conf.keylen = WLAN_KEY_LEN_TKIP;
1582 memcpy(conf.conf.key, status->gtk.decrypt_key, 16);
1583 /* leave TX MIC key zeroed, we don't use it anyway */
1584 memcpy(conf.conf.key +
1585 NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
1586 status->gtk.tkip_mic_key, 8);
1587 break;
1588 }
1589
1590 key = ieee80211_gtk_rekey_add(vif, &conf.conf);
1591 if (IS_ERR(key))
1592 return false;
1593 iwl_mvm_set_key_rx_seq(key, status);
1594 }
1595
1596 if (status->num_of_gtk_rekeys) {
1597 __be64 replay_ctr =
1598 cpu_to_be64(le64_to_cpu(status->replay_ctr));
1599 ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
1600 (void *)&replay_ctr, GFP_KERNEL);
1601 }
1602
1603 mvmvif->seqno_valid = true;
1604 /* +0x10 because the set API expects next-to-use, not last-used */
1605 mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10;
1606
1607 return true;
1608}
1609
1242/* releases the MVM mutex */ 1610/* releases the MVM mutex */
1243static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, 1611static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1244 struct ieee80211_vif *vif) 1612 struct ieee80211_vif *vif)
1245{ 1613{
1246 u32 base = mvm->error_event_table; 1614 u32 base = mvm->error_event_table;
@@ -1253,8 +1621,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1253 .id = WOWLAN_GET_STATUSES, 1621 .id = WOWLAN_GET_STATUSES,
1254 .flags = CMD_SYNC | CMD_WANT_SKB, 1622 .flags = CMD_SYNC | CMD_WANT_SKB,
1255 }; 1623 };
1256 struct iwl_wowlan_status *status; 1624 struct iwl_wowlan_status_data status;
1257 int ret, len; 1625 struct iwl_wowlan_status_v6 *status_v6;
1626 int ret, len, status_size, i;
1627 bool keep;
1628 struct ieee80211_sta *ap_sta;
1629 struct iwl_mvm_sta *mvm_ap_sta;
1258 1630
1259 iwl_trans_read_mem_bytes(mvm->trans, base, 1631 iwl_trans_read_mem_bytes(mvm->trans, base,
1260 &err_info, sizeof(err_info)); 1632 &err_info, sizeof(err_info));
@@ -1287,32 +1659,83 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1287 if (!cmd.resp_pkt) 1659 if (!cmd.resp_pkt)
1288 goto out_unlock; 1660 goto out_unlock;
1289 1661
1662 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)
1663 status_size = sizeof(struct iwl_wowlan_status_v6);
1664 else
1665 status_size = sizeof(struct iwl_wowlan_status_v4);
1666
1290 len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; 1667 len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
1291 if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { 1668 if (len - sizeof(struct iwl_cmd_header) < status_size) {
1292 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); 1669 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
1293 goto out_free_resp; 1670 goto out_free_resp;
1294 } 1671 }
1295 1672
1296 status = (void *)cmd.resp_pkt->data; 1673 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) {
1674 status_v6 = (void *)cmd.resp_pkt->data;
1675
1676 status.pattern_number = le16_to_cpu(status_v6->pattern_number);
1677 for (i = 0; i < 8; i++)
1678 status.qos_seq_ctr[i] =
1679 le16_to_cpu(status_v6->qos_seq_ctr[i]);
1680 status.wakeup_reasons = le32_to_cpu(status_v6->wakeup_reasons);
1681 status.wake_packet_length =
1682 le32_to_cpu(status_v6->wake_packet_length);
1683 status.wake_packet_bufsize =
1684 le32_to_cpu(status_v6->wake_packet_bufsize);
1685 status.wake_packet = status_v6->wake_packet;
1686 } else {
1687 struct iwl_wowlan_status_v4 *status_v4;
1688 status_v6 = NULL;
1689 status_v4 = (void *)cmd.resp_pkt->data;
1690
1691 status.pattern_number = le16_to_cpu(status_v4->pattern_number);
1692 for (i = 0; i < 8; i++)
1693 status.qos_seq_ctr[i] =
1694 le16_to_cpu(status_v4->qos_seq_ctr[i]);
1695 status.wakeup_reasons = le32_to_cpu(status_v4->wakeup_reasons);
1696 status.wake_packet_length =
1697 le32_to_cpu(status_v4->wake_packet_length);
1698 status.wake_packet_bufsize =
1699 le32_to_cpu(status_v4->wake_packet_bufsize);
1700 status.wake_packet = status_v4->wake_packet;
1701 }
1297 1702
1298 if (len - sizeof(struct iwl_cmd_header) != 1703 if (len - sizeof(struct iwl_cmd_header) !=
1299 sizeof(*status) + 1704 status_size + ALIGN(status.wake_packet_bufsize, 4)) {
1300 ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
1301 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); 1705 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
1302 goto out_free_resp; 1706 goto out_free_resp;
1303 } 1707 }
1304 1708
1709 /* still at hard-coded place 0 for D3 image */
1710 ap_sta = rcu_dereference_protected(
1711 mvm->fw_id_to_mac_id[0],
1712 lockdep_is_held(&mvm->mutex));
1713 if (IS_ERR_OR_NULL(ap_sta))
1714 goto out_free_resp;
1715
1716 mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
1717 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
1718 u16 seq = status.qos_seq_ctr[i];
1719 /* firmware stores last-used value, we store next value */
1720 seq += 0x10;
1721 mvm_ap_sta->tid_data[i].seq_number = seq;
1722 }
1723
1305 /* now we have all the data we need, unlock to avoid mac80211 issues */ 1724 /* now we have all the data we need, unlock to avoid mac80211 issues */
1306 mutex_unlock(&mvm->mutex); 1725 mutex_unlock(&mvm->mutex);
1307 1726
1308 iwl_mvm_report_wakeup_reasons(mvm, vif, status); 1727 iwl_mvm_report_wakeup_reasons(mvm, vif, &status);
1728
1729 keep = iwl_mvm_setup_connection_keep(mvm, vif, status_v6);
1730
1309 iwl_free_resp(&cmd); 1731 iwl_free_resp(&cmd);
1310 return; 1732 return keep;
1311 1733
1312 out_free_resp: 1734 out_free_resp:
1313 iwl_free_resp(&cmd); 1735 iwl_free_resp(&cmd);
1314 out_unlock: 1736 out_unlock:
1315 mutex_unlock(&mvm->mutex); 1737 mutex_unlock(&mvm->mutex);
1738 return false;
1316} 1739}
1317 1740
1318static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) 1741static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
@@ -1335,6 +1758,17 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
1335#endif 1758#endif
1336} 1759}
1337 1760
1761static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
1762 struct ieee80211_vif *vif)
1763{
1764 /* skip the one we keep connection on */
1765 if (data == vif)
1766 return;
1767
1768 if (vif->type == NL80211_IFTYPE_STATION)
1769 ieee80211_resume_disconnect(vif);
1770}
1771
1338static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) 1772static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1339{ 1773{
1340 struct iwl_d3_iter_data resume_iter_data = { 1774 struct iwl_d3_iter_data resume_iter_data = {
@@ -1343,6 +1777,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1343 struct ieee80211_vif *vif = NULL; 1777 struct ieee80211_vif *vif = NULL;
1344 int ret; 1778 int ret;
1345 enum iwl_d3_status d3_status; 1779 enum iwl_d3_status d3_status;
1780 bool keep = false;
1346 1781
1347 mutex_lock(&mvm->mutex); 1782 mutex_lock(&mvm->mutex);
1348 1783
@@ -1368,7 +1803,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1368 /* query SRAM first in case we want event logging */ 1803 /* query SRAM first in case we want event logging */
1369 iwl_mvm_read_d3_sram(mvm); 1804 iwl_mvm_read_d3_sram(mvm);
1370 1805
1371 iwl_mvm_query_wakeup_reasons(mvm, vif); 1806 keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
1372 /* has unlocked the mutex, so skip that */ 1807 /* has unlocked the mutex, so skip that */
1373 goto out; 1808 goto out;
1374 1809
@@ -1376,8 +1811,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1376 mutex_unlock(&mvm->mutex); 1811 mutex_unlock(&mvm->mutex);
1377 1812
1378 out: 1813 out:
1379 if (!test && vif) 1814 if (!test)
1380 ieee80211_resume_disconnect(vif); 1815 ieee80211_iterate_active_interfaces_rtnl(mvm->hw,
1816 IEEE80211_IFACE_ITER_NORMAL,
1817 iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
1381 1818
1382 /* return 1 to reconfigure the device */ 1819 /* return 1 to reconfigure the device */
1383 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); 1820 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);