aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/d3.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c364
1 files changed, 336 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index c64d864799cd..d4578cefe445 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -22,7 +22,7 @@
22 * USA 22 * USA
23 * 23 *
24 * The full GNU General Public License is included in this distribution 24 * The full GNU General Public License is included in this distribution
25 * in the file called LICENSE.GPL. 25 * in the file called COPYING.
26 * 26 *
27 * Contact Information: 27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com> 28 * Intel Linux Wireless <ilw@linux.intel.com>
@@ -61,8 +61,11 @@
61 * 61 *
62 *****************************************************************************/ 62 *****************************************************************************/
63 63
64#include <linux/etherdevice.h>
65#include <linux/ip.h>
64#include <net/cfg80211.h> 66#include <net/cfg80211.h>
65#include <net/ipv6.h> 67#include <net/ipv6.h>
68#include <net/tcp.h>
66#include "iwl-modparams.h" 69#include "iwl-modparams.h"
67#include "fw-api.h" 70#include "fw-api.h"
68#include "mvm.h" 71#include "mvm.h"
@@ -192,6 +195,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
192 sizeof(wkc), &wkc); 195 sizeof(wkc), &wkc);
193 data->error = ret != 0; 196 data->error = ret != 0;
194 197
198 mvm->ptk_ivlen = key->iv_len;
199 mvm->ptk_icvlen = key->icv_len;
200 mvm->gtk_ivlen = key->iv_len;
201 mvm->gtk_icvlen = key->icv_len;
202
195 /* don't upload key again */ 203 /* don't upload key again */
196 goto out_unlock; 204 goto out_unlock;
197 } 205 }
@@ -304,9 +312,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
304 */ 312 */
305 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 313 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
306 key->hw_key_idx = 0; 314 key->hw_key_idx = 0;
315 mvm->ptk_ivlen = key->iv_len;
316 mvm->ptk_icvlen = key->icv_len;
307 } else { 317 } else {
308 data->gtk_key_idx++; 318 data->gtk_key_idx++;
309 key->hw_key_idx = data->gtk_key_idx; 319 key->hw_key_idx = data->gtk_key_idx;
320 mvm->gtk_ivlen = key->iv_len;
321 mvm->gtk_icvlen = key->icv_len;
310 } 322 }
311 323
312 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); 324 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
@@ -392,6 +404,233 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
392 sizeof(cmd), &cmd); 404 sizeof(cmd), &cmd);
393} 405}
394 406
407enum iwl_mvm_tcp_packet_type {
408 MVM_TCP_TX_SYN,
409 MVM_TCP_RX_SYNACK,
410 MVM_TCP_TX_DATA,
411 MVM_TCP_RX_ACK,
412 MVM_TCP_RX_WAKE,
413 MVM_TCP_TX_FIN,
414};
415
416static __le16 pseudo_hdr_check(int len, __be32 saddr, __be32 daddr)
417{
418 __sum16 check = tcp_v4_check(len, saddr, daddr, 0);
419 return cpu_to_le16(be16_to_cpu((__force __be16)check));
420}
421
422static void iwl_mvm_build_tcp_packet(struct iwl_mvm *mvm,
423 struct ieee80211_vif *vif,
424 struct cfg80211_wowlan_tcp *tcp,
425 void *_pkt, u8 *mask,
426 __le16 *pseudo_hdr_csum,
427 enum iwl_mvm_tcp_packet_type ptype)
428{
429 struct {
430 struct ethhdr eth;
431 struct iphdr ip;
432 struct tcphdr tcp;
433 u8 data[];
434 } __packed *pkt = _pkt;
435 u16 ip_tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
436 int i;
437
438 pkt->eth.h_proto = cpu_to_be16(ETH_P_IP),
439 pkt->ip.version = 4;
440 pkt->ip.ihl = 5;
441 pkt->ip.protocol = IPPROTO_TCP;
442
443 switch (ptype) {
444 case MVM_TCP_TX_SYN:
445 case MVM_TCP_TX_DATA:
446 case MVM_TCP_TX_FIN:
447 memcpy(pkt->eth.h_dest, tcp->dst_mac, ETH_ALEN);
448 memcpy(pkt->eth.h_source, vif->addr, ETH_ALEN);
449 pkt->ip.ttl = 128;
450 pkt->ip.saddr = tcp->src;
451 pkt->ip.daddr = tcp->dst;
452 pkt->tcp.source = cpu_to_be16(tcp->src_port);
453 pkt->tcp.dest = cpu_to_be16(tcp->dst_port);
454 /* overwritten for TX SYN later */
455 pkt->tcp.doff = sizeof(struct tcphdr) / 4;
456 pkt->tcp.window = cpu_to_be16(65000);
457 break;
458 case MVM_TCP_RX_SYNACK:
459 case MVM_TCP_RX_ACK:
460 case MVM_TCP_RX_WAKE:
461 memcpy(pkt->eth.h_dest, vif->addr, ETH_ALEN);
462 memcpy(pkt->eth.h_source, tcp->dst_mac, ETH_ALEN);
463 pkt->ip.saddr = tcp->dst;
464 pkt->ip.daddr = tcp->src;
465 pkt->tcp.source = cpu_to_be16(tcp->dst_port);
466 pkt->tcp.dest = cpu_to_be16(tcp->src_port);
467 break;
468 default:
469 WARN_ON(1);
470 return;
471 }
472
473 switch (ptype) {
474 case MVM_TCP_TX_SYN:
475 /* firmware assumes 8 option bytes - 8 NOPs for now */
476 memset(pkt->data, 0x01, 8);
477 ip_tot_len += 8;
478 pkt->tcp.doff = (sizeof(struct tcphdr) + 8) / 4;
479 pkt->tcp.syn = 1;
480 break;
481 case MVM_TCP_TX_DATA:
482 ip_tot_len += tcp->payload_len;
483 memcpy(pkt->data, tcp->payload, tcp->payload_len);
484 pkt->tcp.psh = 1;
485 pkt->tcp.ack = 1;
486 break;
487 case MVM_TCP_TX_FIN:
488 pkt->tcp.fin = 1;
489 pkt->tcp.ack = 1;
490 break;
491 case MVM_TCP_RX_SYNACK:
492 pkt->tcp.syn = 1;
493 pkt->tcp.ack = 1;
494 break;
495 case MVM_TCP_RX_ACK:
496 pkt->tcp.ack = 1;
497 break;
498 case MVM_TCP_RX_WAKE:
499 ip_tot_len += tcp->wake_len;
500 pkt->tcp.psh = 1;
501 pkt->tcp.ack = 1;
502 memcpy(pkt->data, tcp->wake_data, tcp->wake_len);
503 break;
504 }
505
506 switch (ptype) {
507 case MVM_TCP_TX_SYN:
508 case MVM_TCP_TX_DATA:
509 case MVM_TCP_TX_FIN:
510 pkt->ip.tot_len = cpu_to_be16(ip_tot_len);
511 pkt->ip.check = ip_fast_csum(&pkt->ip, pkt->ip.ihl);
512 break;
513 case MVM_TCP_RX_WAKE:
514 for (i = 0; i < DIV_ROUND_UP(tcp->wake_len, 8); i++) {
515 u8 tmp = tcp->wake_mask[i];
516 mask[i + 6] |= tmp << 6;
517 if (i + 1 < DIV_ROUND_UP(tcp->wake_len, 8))
518 mask[i + 7] = tmp >> 2;
519 }
520 /* fall through for ethernet/IP/TCP headers mask */
521 case MVM_TCP_RX_SYNACK:
522 case MVM_TCP_RX_ACK:
523 mask[0] = 0xff; /* match ethernet */
524 /*
525 * match ethernet, ip.version, ip.ihl
526 * the ip.ihl half byte is really masked out by firmware
527 */
528 mask[1] = 0x7f;
529 mask[2] = 0x80; /* match ip.protocol */
530 mask[3] = 0xfc; /* match ip.saddr, ip.daddr */
531 mask[4] = 0x3f; /* match ip.daddr, tcp.source, tcp.dest */
532 mask[5] = 0x80; /* match tcp flags */
533 /* leave rest (0 or set for MVM_TCP_RX_WAKE) */
534 break;
535 };
536
537 *pseudo_hdr_csum = pseudo_hdr_check(ip_tot_len - sizeof(struct iphdr),
538 pkt->ip.saddr, pkt->ip.daddr);
539}
540
541static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
542 struct ieee80211_vif *vif,
543 struct cfg80211_wowlan_tcp *tcp)
544{
545 struct iwl_wowlan_remote_wake_config *cfg;
546 struct iwl_host_cmd cmd = {
547 .id = REMOTE_WAKE_CONFIG_CMD,
548 .len = { sizeof(*cfg), },
549 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
550 .flags = CMD_SYNC,
551 };
552 int ret;
553
554 if (!tcp)
555 return 0;
556
557 cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
558 if (!cfg)
559 return -ENOMEM;
560 cmd.data[0] = cfg;
561
562 cfg->max_syn_retries = 10;
563 cfg->max_data_retries = 10;
564 cfg->tcp_syn_ack_timeout = 1; /* seconds */
565 cfg->tcp_ack_timeout = 1; /* seconds */
566
567 /* SYN (TX) */
568 iwl_mvm_build_tcp_packet(
569 mvm, vif, tcp, cfg->syn_tx.data, NULL,
570 &cfg->syn_tx.info.tcp_pseudo_header_checksum,
571 MVM_TCP_TX_SYN);
572 cfg->syn_tx.info.tcp_payload_length = 0;
573
574 /* SYN/ACK (RX) */
575 iwl_mvm_build_tcp_packet(
576 mvm, vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask,
577 &cfg->synack_rx.info.tcp_pseudo_header_checksum,
578 MVM_TCP_RX_SYNACK);
579 cfg->synack_rx.info.tcp_payload_length = 0;
580
581 /* KEEPALIVE/ACK (TX) */
582 iwl_mvm_build_tcp_packet(
583 mvm, vif, tcp, cfg->keepalive_tx.data, NULL,
584 &cfg->keepalive_tx.info.tcp_pseudo_header_checksum,
585 MVM_TCP_TX_DATA);
586 cfg->keepalive_tx.info.tcp_payload_length =
587 cpu_to_le16(tcp->payload_len);
588 cfg->sequence_number_offset = tcp->payload_seq.offset;
589 /* length must be 0..4, the field is little endian */
590 cfg->sequence_number_length = tcp->payload_seq.len;
591 cfg->initial_sequence_number = cpu_to_le32(tcp->payload_seq.start);
592 cfg->keepalive_interval = cpu_to_le16(tcp->data_interval);
593 if (tcp->payload_tok.len) {
594 cfg->token_offset = tcp->payload_tok.offset;
595 cfg->token_length = tcp->payload_tok.len;
596 cfg->num_tokens =
597 cpu_to_le16(tcp->tokens_size % tcp->payload_tok.len);
598 memcpy(cfg->tokens, tcp->payload_tok.token_stream,
599 tcp->tokens_size);
600 } else {
601 /* set tokens to max value to almost never run out */
602 cfg->num_tokens = cpu_to_le16(65535);
603 }
604
605 /* ACK (RX) */
606 iwl_mvm_build_tcp_packet(
607 mvm, vif, tcp, cfg->keepalive_ack_rx.data,
608 cfg->keepalive_ack_rx.rx_mask,
609 &cfg->keepalive_ack_rx.info.tcp_pseudo_header_checksum,
610 MVM_TCP_RX_ACK);
611 cfg->keepalive_ack_rx.info.tcp_payload_length = 0;
612
613 /* WAKEUP (RX) */
614 iwl_mvm_build_tcp_packet(
615 mvm, vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask,
616 &cfg->wake_rx.info.tcp_pseudo_header_checksum,
617 MVM_TCP_RX_WAKE);
618 cfg->wake_rx.info.tcp_payload_length =
619 cpu_to_le16(tcp->wake_len);
620
621 /* FIN */
622 iwl_mvm_build_tcp_packet(
623 mvm, vif, tcp, cfg->fin_tx.data, NULL,
624 &cfg->fin_tx.info.tcp_pseudo_header_checksum,
625 MVM_TCP_TX_FIN);
626 cfg->fin_tx.info.tcp_payload_length = 0;
627
628 ret = iwl_mvm_send_cmd(mvm, &cmd);
629 kfree(cfg);
630
631 return ret;
632}
633
395struct iwl_d3_iter_data { 634struct iwl_d3_iter_data {
396 struct iwl_mvm *mvm; 635 struct iwl_mvm *mvm;
397 struct ieee80211_vif *vif; 636 struct ieee80211_vif *vif;
@@ -630,6 +869,22 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
630 d3_cfg_cmd.wakeup_flags |= 869 d3_cfg_cmd.wakeup_flags |=
631 cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); 870 cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
632 871
872 if (wowlan->tcp) {
873 /*
874 * The firmware currently doesn't really look at these, only
875 * the IWL_WOWLAN_WAKEUP_LINK_CHANGE bit. We have to set that
876 * reason bit since losing the connection to the AP implies
877 * losing the TCP connection.
878 * Set the flags anyway as long as they exist, in case this
879 * will be changed in the firmware.
880 */
881 wowlan_config_cmd.wakeup_filter |=
882 cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
883 IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
884 IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
885 IWL_WOWLAN_WAKEUP_LINK_CHANGE);
886 }
887
633 iwl_mvm_cancel_scan(mvm); 888 iwl_mvm_cancel_scan(mvm);
634 889
635 iwl_trans_stop_device(mvm->trans); 890 iwl_trans_stop_device(mvm->trans);
@@ -649,6 +904,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
649 /* We reprogram keys and shouldn't allocate new key indices */ 904 /* We reprogram keys and shouldn't allocate new key indices */
650 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); 905 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
651 906
907 mvm->ptk_ivlen = 0;
908 mvm->ptk_icvlen = 0;
909 mvm->ptk_ivlen = 0;
910 mvm->ptk_icvlen = 0;
911
652 /* 912 /*
653 * The D3 firmware still hardcodes the AP station ID for the 913 * 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 914 * BSS we're associated with as 0. As a result, we have to move
@@ -740,6 +1000,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
740 if (ret) 1000 if (ret)
741 goto out; 1001 goto out;
742 1002
1003 ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
1004 if (ret)
1005 goto out;
1006
743 /* must be last -- this switches firmware state */ 1007 /* must be last -- this switches firmware state */
744 ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, 1008 ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
745 sizeof(d3_cfg_cmd), &d3_cfg_cmd); 1009 sizeof(d3_cfg_cmd), &d3_cfg_cmd);
@@ -783,7 +1047,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
783 struct iwl_wowlan_status *status; 1047 struct iwl_wowlan_status *status;
784 u32 reasons; 1048 u32 reasons;
785 int ret, len; 1049 int ret, len;
786 bool pkt8023 = false;
787 struct sk_buff *pkt = NULL; 1050 struct sk_buff *pkt = NULL;
788 1051
789 iwl_trans_read_mem_bytes(mvm->trans, base, 1052 iwl_trans_read_mem_bytes(mvm->trans, base,
@@ -824,7 +1087,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
824 status = (void *)cmd.resp_pkt->data; 1087 status = (void *)cmd.resp_pkt->data;
825 1088
826 if (len - sizeof(struct iwl_cmd_header) != 1089 if (len - sizeof(struct iwl_cmd_header) !=
827 sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { 1090 sizeof(*status) +
1091 ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
828 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); 1092 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
829 goto out; 1093 goto out;
830 } 1094 }
@@ -836,61 +1100,105 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
836 goto report; 1100 goto report;
837 } 1101 }
838 1102
839 if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { 1103 if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)
840 wakeup.magic_pkt = true; 1104 wakeup.magic_pkt = true;
841 pkt8023 = true;
842 }
843 1105
844 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { 1106 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
845 wakeup.pattern_idx = 1107 wakeup.pattern_idx =
846 le16_to_cpu(status->pattern_number); 1108 le16_to_cpu(status->pattern_number);
847 pkt8023 = true;
848 }
849 1109
850 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | 1110 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
851 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) 1111 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
852 wakeup.disconnect = true; 1112 wakeup.disconnect = true;
853 1113
854 if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { 1114 if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)
855 wakeup.gtk_rekey_failure = true; 1115 wakeup.gtk_rekey_failure = true;
856 pkt8023 = true;
857 }
858 1116
859 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { 1117 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
860 wakeup.rfkill_release = true; 1118 wakeup.rfkill_release = true;
861 pkt8023 = true;
862 }
863 1119
864 if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { 1120 if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)
865 wakeup.eap_identity_req = true; 1121 wakeup.eap_identity_req = true;
866 pkt8023 = true;
867 }
868 1122
869 if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { 1123 if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)
870 wakeup.four_way_handshake = true; 1124 wakeup.four_way_handshake = true;
871 pkt8023 = true; 1125
872 } 1126 if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS)
1127 wakeup.tcp_connlost = true;
1128
1129 if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE)
1130 wakeup.tcp_nomoretokens = true;
1131
1132 if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET)
1133 wakeup.tcp_match = true;
873 1134
874 if (status->wake_packet_bufsize) { 1135 if (status->wake_packet_bufsize) {
875 u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); 1136 int pktsize = le32_to_cpu(status->wake_packet_bufsize);
876 u32 pktlen = le32_to_cpu(status->wake_packet_length); 1137 int pktlen = le32_to_cpu(status->wake_packet_length);
1138 const u8 *pktdata = status->wake_packet;
1139 struct ieee80211_hdr *hdr = (void *)pktdata;
1140 int truncated = pktlen - pktsize;
1141
1142 /* this would be a firmware bug */
1143 if (WARN_ON_ONCE(truncated < 0))
1144 truncated = 0;
1145
1146 if (ieee80211_is_data(hdr->frame_control)) {
1147 int hdrlen = ieee80211_hdrlen(hdr->frame_control);
1148 int ivlen = 0, icvlen = 4; /* also FCS */
877 1149
878 if (pkt8023) {
879 pkt = alloc_skb(pktsize, GFP_KERNEL); 1150 pkt = alloc_skb(pktsize, GFP_KERNEL);
880 if (!pkt) 1151 if (!pkt)
881 goto report; 1152 goto report;
882 memcpy(skb_put(pkt, pktsize), status->wake_packet, 1153
883 pktsize); 1154 memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen);
1155 pktdata += hdrlen;
1156 pktsize -= hdrlen;
1157
1158 if (ieee80211_has_protected(hdr->frame_control)) {
1159 if (is_multicast_ether_addr(hdr->addr1)) {
1160 ivlen = mvm->gtk_ivlen;
1161 icvlen += mvm->gtk_icvlen;
1162 } else {
1163 ivlen = mvm->ptk_ivlen;
1164 icvlen += mvm->ptk_icvlen;
1165 }
1166 }
1167
1168 /* if truncated, FCS/ICV is (partially) gone */
1169 if (truncated >= icvlen) {
1170 icvlen = 0;
1171 truncated -= icvlen;
1172 } else {
1173 icvlen -= truncated;
1174 truncated = 0;
1175 }
1176
1177 pktsize -= ivlen + icvlen;
1178 pktdata += ivlen;
1179
1180 memcpy(skb_put(pkt, pktsize), pktdata, pktsize);
1181
884 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) 1182 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
885 goto report; 1183 goto report;
886 wakeup.packet = pkt->data; 1184 wakeup.packet = pkt->data;
887 wakeup.packet_present_len = pkt->len; 1185 wakeup.packet_present_len = pkt->len;
888 wakeup.packet_len = pkt->len - (pktlen - pktsize); 1186 wakeup.packet_len = pkt->len - truncated;
889 wakeup.packet_80211 = false; 1187 wakeup.packet_80211 = false;
890 } else { 1188 } else {
1189 int fcslen = 4;
1190
1191 if (truncated >= 4) {
1192 truncated -= 4;
1193 fcslen = 0;
1194 } else {
1195 fcslen -= truncated;
1196 truncated = 0;
1197 }
1198 pktsize -= fcslen;
891 wakeup.packet = status->wake_packet; 1199 wakeup.packet = status->wake_packet;
892 wakeup.packet_present_len = pktsize; 1200 wakeup.packet_present_len = pktsize;
893 wakeup.packet_len = pktlen; 1201 wakeup.packet_len = pktlen - truncated;
894 wakeup.packet_80211 = true; 1202 wakeup.packet_80211 = true;
895 } 1203 }
896 } 1204 }