aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-08-06 12:58:56 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-11 03:57:53 -0400
commit6d9d32b89ab0f9cbd182f807cc484e66e15c6972 (patch)
tree21d730a7fda7761f2190ffc8ada16a342cb94661
parent04a4e1fdd248d7a19d53e6e90f757e99093e3d29 (diff)
iwlwifi: mvm: keep connection to AP after WoWLAN
Until now, after WoWLAN, we weren't able to keep the connection to the AP because the firmware didn't give us the right information. Since the firmware API has been changed to include all the information we need, change the driver to work with the new API (if it is available) and program all the relevant information in mac80211 to keep the connection. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c383
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h25
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h9
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h12
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c8
7 files changed, 420 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 7fd886f5a5e0..6bdae0e9dd78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -84,6 +84,8 @@
84 * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API 84 * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
85 * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element 85 * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
86 * from the probe request template. 86 * from the probe request template.
87 * @IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping
88 * connection when going back to D0
87 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) 89 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version)
88 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) 90 * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
89 * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. 91 * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
@@ -105,6 +107,7 @@ enum iwl_ucode_tlv_flag {
105 IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), 107 IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10),
106 IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), 108 IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11),
107 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), 109 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12),
110 IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API = BIT(14),
108 IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), 111 IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15),
109 IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), 112 IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16),
110 IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), 113 IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index ab5c1f0e0622..6f45966817bb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -863,6 +863,13 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
863static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm, 863static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
864 struct ieee80211_vif *vif) 864 struct ieee80211_vif *vif)
865{ 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 };
866 struct iwl_host_cmd cmd = { 873 struct iwl_host_cmd cmd = {
867 .id = NON_QOS_TX_COUNTER_CMD, 874 .id = NON_QOS_TX_COUNTER_CMD,
868 .flags = CMD_SYNC | CMD_WANT_SKB, 875 .flags = CMD_SYNC | CMD_WANT_SKB,
@@ -870,21 +877,57 @@ static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
870 int err; 877 int err;
871 u32 size; 878 u32 size;
872 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
873 err = iwl_mvm_send_cmd(mvm, &cmd); 885 err = iwl_mvm_send_cmd(mvm, &cmd);
874 if (err) 886 if (err)
875 return err; 887 return err;
876 888
877 size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; 889 size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
878 size -= sizeof(cmd.resp_pkt->hdr); 890 size -= sizeof(cmd.resp_pkt->hdr);
879 if (size != sizeof(__le32)) 891 if (size < sizeof(__le16)) {
880 err = -EINVAL; 892 err = -EINVAL;
881 else 893 } else {
882 err = le32_to_cpup((__le32 *)cmd.resp_pkt->data); 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 }
883 900
884 iwl_free_resp(&cmd); 901 iwl_free_resp(&cmd);
885 return err; 902 return err;
886} 903}
887 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
888static int __iwl_mvm_suspend(struct ieee80211_hw *hw, 931static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
889 struct cfg80211_wowlan *wowlan, 932 struct cfg80211_wowlan *wowlan,
890 bool test) 933 bool test)
@@ -1203,16 +1246,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
1203 return __iwl_mvm_suspend(hw, wowlan, false); 1246 return __iwl_mvm_suspend(hw, wowlan, false);
1204} 1247}
1205 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
1206static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, 1259static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1207 struct ieee80211_vif *vif, 1260 struct ieee80211_vif *vif,
1208 struct iwl_wowlan_status *status) 1261 struct iwl_wowlan_status_data *status)
1209{ 1262{
1210 struct sk_buff *pkt = NULL; 1263 struct sk_buff *pkt = NULL;
1211 struct cfg80211_wowlan_wakeup wakeup = { 1264 struct cfg80211_wowlan_wakeup wakeup = {
1212 .pattern_idx = -1, 1265 .pattern_idx = -1,
1213 }; 1266 };
1214 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; 1267 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
1215 u32 reasons = le32_to_cpu(status->wakeup_reasons); 1268 u32 reasons = status->wakeup_reasons;
1216 1269
1217 if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { 1270 if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
1218 wakeup_report = NULL; 1271 wakeup_report = NULL;
@@ -1224,7 +1277,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1224 1277
1225 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) 1278 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
1226 wakeup.pattern_idx = 1279 wakeup.pattern_idx =
1227 le16_to_cpu(status->pattern_number); 1280 status->pattern_number;
1228 1281
1229 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | 1282 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
1230 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) 1283 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
@@ -1252,8 +1305,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1252 wakeup.tcp_match = true; 1305 wakeup.tcp_match = true;
1253 1306
1254 if (status->wake_packet_bufsize) { 1307 if (status->wake_packet_bufsize) {
1255 int pktsize = le32_to_cpu(status->wake_packet_bufsize); 1308 int pktsize = status->wake_packet_bufsize;
1256 int pktlen = le32_to_cpu(status->wake_packet_length); 1309 int pktlen = status->wake_packet_length;
1257 const u8 *pktdata = status->wake_packet; 1310 const u8 *pktdata = status->wake_packet;
1258 struct ieee80211_hdr *hdr = (void *)pktdata; 1311 struct ieee80211_hdr *hdr = (void *)pktdata;
1259 int truncated = pktlen - pktsize; 1312 int truncated = pktlen - pktsize;
@@ -1333,8 +1386,229 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
1333 kfree_skb(pkt); 1386 kfree_skb(pkt);
1334} 1387}
1335 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
1336/* releases the MVM mutex */ 1610/* releases the MVM mutex */
1337static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, 1611static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1338 struct ieee80211_vif *vif) 1612 struct ieee80211_vif *vif)
1339{ 1613{
1340 u32 base = mvm->error_event_table; 1614 u32 base = mvm->error_event_table;
@@ -1347,8 +1621,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1347 .id = WOWLAN_GET_STATUSES, 1621 .id = WOWLAN_GET_STATUSES,
1348 .flags = CMD_SYNC | CMD_WANT_SKB, 1622 .flags = CMD_SYNC | CMD_WANT_SKB,
1349 }; 1623 };
1350 struct iwl_wowlan_status *status; 1624 struct iwl_wowlan_status_data status;
1351 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;
1352 1630
1353 iwl_trans_read_mem_bytes(mvm->trans, base, 1631 iwl_trans_read_mem_bytes(mvm->trans, base,
1354 &err_info, sizeof(err_info)); 1632 &err_info, sizeof(err_info));
@@ -1381,32 +1659,83 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
1381 if (!cmd.resp_pkt) 1659 if (!cmd.resp_pkt)
1382 goto out_unlock; 1660 goto out_unlock;
1383 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
1384 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;
1385 if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { 1668 if (len - sizeof(struct iwl_cmd_header) < status_size) {
1386 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); 1669 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
1387 goto out_free_resp; 1670 goto out_free_resp;
1388 } 1671 }
1389 1672
1390 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 }
1391 1702
1392 if (len - sizeof(struct iwl_cmd_header) != 1703 if (len - sizeof(struct iwl_cmd_header) !=
1393 sizeof(*status) + 1704 status_size + ALIGN(status.wake_packet_bufsize, 4)) {
1394 ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
1395 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); 1705 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
1396 goto out_free_resp; 1706 goto out_free_resp;
1397 } 1707 }
1398 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
1399 /* 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 */
1400 mutex_unlock(&mvm->mutex); 1725 mutex_unlock(&mvm->mutex);
1401 1726
1402 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
1403 iwl_free_resp(&cmd); 1731 iwl_free_resp(&cmd);
1404 return; 1732 return keep;
1405 1733
1406 out_free_resp: 1734 out_free_resp:
1407 iwl_free_resp(&cmd); 1735 iwl_free_resp(&cmd);
1408 out_unlock: 1736 out_unlock:
1409 mutex_unlock(&mvm->mutex); 1737 mutex_unlock(&mvm->mutex);
1738 return false;
1410} 1739}
1411 1740
1412static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) 1741static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
@@ -1429,6 +1758,17 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
1429#endif 1758#endif
1430} 1759}
1431 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
1432static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) 1772static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1433{ 1773{
1434 struct iwl_d3_iter_data resume_iter_data = { 1774 struct iwl_d3_iter_data resume_iter_data = {
@@ -1437,6 +1777,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1437 struct ieee80211_vif *vif = NULL; 1777 struct ieee80211_vif *vif = NULL;
1438 int ret; 1778 int ret;
1439 enum iwl_d3_status d3_status; 1779 enum iwl_d3_status d3_status;
1780 bool keep = false;
1440 1781
1441 mutex_lock(&mvm->mutex); 1782 mutex_lock(&mvm->mutex);
1442 1783
@@ -1462,7 +1803,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1462 /* query SRAM first in case we want event logging */ 1803 /* query SRAM first in case we want event logging */
1463 iwl_mvm_read_d3_sram(mvm); 1804 iwl_mvm_read_d3_sram(mvm);
1464 1805
1465 iwl_mvm_query_wakeup_reasons(mvm, vif); 1806 keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
1466 /* has unlocked the mutex, so skip that */ 1807 /* has unlocked the mutex, so skip that */
1467 goto out; 1808 goto out;
1468 1809
@@ -1470,8 +1811,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
1470 mutex_unlock(&mvm->mutex); 1811 mutex_unlock(&mvm->mutex);
1471 1812
1472 out: 1813 out:
1473 if (!test && vif) 1814 if (!test)
1474 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);
1475 1818
1476 /* return 1 to reconfigure the device */ 1819 /* return 1 to reconfigure the device */
1477 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); 1820 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
index 1f7d65aaa87a..4e7dd8cf87dc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -335,7 +335,7 @@ enum iwl_wowlan_wakeup_reason {
335 IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), 335 IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12),
336}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ 336}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
337 337
338struct iwl_wowlan_status { 338struct iwl_wowlan_status_v4 {
339 __le64 replay_ctr; 339 __le64 replay_ctr;
340 __le16 pattern_number; 340 __le16 pattern_number;
341 __le16 non_qos_seq_ctr; 341 __le16 non_qos_seq_ctr;
@@ -350,6 +350,29 @@ struct iwl_wowlan_status {
350 u8 wake_packet[]; /* can be truncated from _length to _bufsize */ 350 u8 wake_packet[]; /* can be truncated from _length to _bufsize */
351} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ 351} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
352 352
353struct iwl_wowlan_gtk_status {
354 u8 key_index;
355 u8 reserved[3];
356 u8 decrypt_key[16];
357 u8 tkip_mic_key[8];
358 struct iwl_wowlan_rsc_tsc_params_cmd rsc;
359} __packed;
360
361struct iwl_wowlan_status_v6 {
362 struct iwl_wowlan_gtk_status gtk;
363 __le64 replay_ctr;
364 __le16 pattern_number;
365 __le16 non_qos_seq_ctr;
366 __le16 qos_seq_ctr[8];
367 __le32 wakeup_reasons;
368 __le32 num_of_gtk_rekeys;
369 __le32 transmitted_ndps;
370 __le32 received_beacons;
371 __le32 wake_packet_length;
372 __le32 wake_packet_bufsize;
373 u8 wake_packet[]; /* can be truncated from _length to _bufsize */
374} __packed; /* WOWLAN_STATUSES_API_S_VER_6 */
375
353#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 376#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64
354#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 377#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128
355#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 378#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
index 98b1feb43d38..44a4959f69c0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
@@ -372,4 +372,13 @@ static inline u32 iwl_mvm_reciprocal(u32 v)
372 return 0xFFFFFFFF / v; 372 return 0xFFFFFFFF / v;
373} 373}
374 374
375#define IWL_NONQOS_SEQ_GET 0x1
376#define IWL_NONQOS_SEQ_SET 0x2
377struct iwl_nonqos_seq_query_cmd {
378 __le32 get_set_flag;
379 __le32 mac_id_n_color;
380 __le16 value;
381 __le16 reserved;
382} __packed; /* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */
383
375#endif /* __fw_api_mac_h__ */ 384#endif /* __fw_api_mac_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 196c4ebb186f..4d1c82271d55 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -1042,6 +1042,9 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1042 if (ret) 1042 if (ret)
1043 return ret; 1043 return ret;
1044 1044
1045 /* will only do anything at resume from D3 time */
1046 iwl_mvm_set_last_nonqos_seq(mvm, vif);
1047
1045 mvmvif->uploaded = true; 1048 mvmvif->uploaded = true;
1046 return 0; 1049 return 0;
1047} 1050}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 3e29d3c91617..16fb92e3877a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -313,6 +313,9 @@ struct iwl_mvm_vif {
313 313
314 int tx_key_idx; 314 int tx_key_idx;
315 315
316 bool seqno_valid;
317 u16 seqno;
318
316#if IS_ENABLED(CONFIG_IPV6) 319#if IS_ENABLED(CONFIG_IPV6)
317 /* IPv6 addresses for WoWLAN */ 320 /* IPv6 addresses for WoWLAN */
318 struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; 321 struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX];
@@ -796,6 +799,15 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
796void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, 799void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
797 struct ieee80211_vif *vif, int idx); 800 struct ieee80211_vif *vif, int idx);
798extern const struct file_operations iwl_dbgfs_d3_test_ops; 801extern const struct file_operations iwl_dbgfs_d3_test_ops;
802#ifdef CONFIG_PM_SLEEP
803void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
804 struct ieee80211_vif *vif);
805#else
806static inline void
807iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
808{
809}
810#endif
799 811
800/* BT Coex */ 812/* BT Coex */
801int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); 813int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index b320350e0226..fd826c9076f8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -337,8 +337,12 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
337 if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) 337 if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
338 mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); 338 mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
339 339
340 /* for HW restart - need to reset the seq_number etc... */ 340 /* for HW restart - reset everything but the sequence number */
341 memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); 341 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
342 u16 seq = mvm_sta->tid_data[i].seq_number;
343 memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i]));
344 mvm_sta->tid_data[i].seq_number = seq;
345 }
342 346
343 ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); 347 ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
344 if (ret) 348 if (ret)