diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/d3.c | 258 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 51 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 26 |
3 files changed, 334 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 376a5776db90..d4578cefe445 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -62,8 +62,10 @@ | |||
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | 63 | ||
64 | #include <linux/etherdevice.h> | 64 | #include <linux/etherdevice.h> |
65 | #include <linux/ip.h> | ||
65 | #include <net/cfg80211.h> | 66 | #include <net/cfg80211.h> |
66 | #include <net/ipv6.h> | 67 | #include <net/ipv6.h> |
68 | #include <net/tcp.h> | ||
67 | #include "iwl-modparams.h" | 69 | #include "iwl-modparams.h" |
68 | #include "fw-api.h" | 70 | #include "fw-api.h" |
69 | #include "mvm.h" | 71 | #include "mvm.h" |
@@ -402,6 +404,233 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
402 | sizeof(cmd), &cmd); | 404 | sizeof(cmd), &cmd); |
403 | } | 405 | } |
404 | 406 | ||
407 | enum 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 | |||
416 | static __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 | |||
422 | static 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 | |||
541 | static 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 | |||
405 | struct iwl_d3_iter_data { | 634 | struct iwl_d3_iter_data { |
406 | struct iwl_mvm *mvm; | 635 | struct iwl_mvm *mvm; |
407 | struct ieee80211_vif *vif; | 636 | struct ieee80211_vif *vif; |
@@ -640,6 +869,22 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
640 | d3_cfg_cmd.wakeup_flags |= | 869 | d3_cfg_cmd.wakeup_flags |= |
641 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | 870 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); |
642 | 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 | |||
643 | iwl_mvm_cancel_scan(mvm); | 888 | iwl_mvm_cancel_scan(mvm); |
644 | 889 | ||
645 | iwl_trans_stop_device(mvm->trans); | 890 | iwl_trans_stop_device(mvm->trans); |
@@ -755,6 +1000,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
755 | if (ret) | 1000 | if (ret) |
756 | goto out; | 1001 | goto out; |
757 | 1002 | ||
1003 | ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp); | ||
1004 | if (ret) | ||
1005 | goto out; | ||
1006 | |||
758 | /* must be last -- this switches firmware state */ | 1007 | /* must be last -- this switches firmware state */ |
759 | 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, |
760 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); | 1009 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); |
@@ -874,6 +1123,15 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
874 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) | 1123 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) |
875 | wakeup.four_way_handshake = true; | 1124 | wakeup.four_way_handshake = true; |
876 | 1125 | ||
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; | ||
1134 | |||
877 | if (status->wake_packet_bufsize) { | 1135 | if (status->wake_packet_bufsize) { |
878 | int pktsize = le32_to_cpu(status->wake_packet_bufsize); | 1136 | int pktsize = le32_to_cpu(status->wake_packet_bufsize); |
879 | int pktlen = le32_to_cpu(status->wake_packet_length); | 1137 | int pktlen = le32_to_cpu(status->wake_packet_length); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index a442ee11a062..51e015d1dfb2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -258,7 +258,7 @@ enum iwl_wowlan_wakeup_reason { | |||
258 | IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), | 258 | IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), |
259 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), | 259 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), |
260 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), | 260 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), |
261 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11), | 261 | /* BIT(11) reserved */ |
262 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), | 262 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), |
263 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ | 263 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ |
264 | 264 | ||
@@ -277,6 +277,55 @@ struct iwl_wowlan_status { | |||
277 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ | 277 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ |
278 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ | 278 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ |
279 | 279 | ||
280 | #define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 | ||
281 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 | ||
282 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 | ||
283 | |||
284 | struct iwl_tcp_packet_info { | ||
285 | __le16 tcp_pseudo_header_checksum; | ||
286 | __le16 tcp_payload_length; | ||
287 | } __packed; /* TCP_PACKET_INFO_API_S_VER_2 */ | ||
288 | |||
289 | struct iwl_tcp_packet { | ||
290 | struct iwl_tcp_packet_info info; | ||
291 | u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; | ||
292 | u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN]; | ||
293 | } __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ | ||
294 | |||
295 | struct iwl_remote_wake_packet { | ||
296 | struct iwl_tcp_packet_info info; | ||
297 | u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; | ||
298 | u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN]; | ||
299 | } __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ | ||
300 | |||
301 | struct iwl_wowlan_remote_wake_config { | ||
302 | __le32 connection_max_time; /* unused */ | ||
303 | /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */ | ||
304 | u8 max_syn_retries; | ||
305 | u8 max_data_retries; | ||
306 | u8 tcp_syn_ack_timeout; | ||
307 | u8 tcp_ack_timeout; | ||
308 | |||
309 | struct iwl_tcp_packet syn_tx; | ||
310 | struct iwl_tcp_packet synack_rx; | ||
311 | struct iwl_tcp_packet keepalive_ack_rx; | ||
312 | struct iwl_tcp_packet fin_tx; | ||
313 | |||
314 | struct iwl_remote_wake_packet keepalive_tx; | ||
315 | struct iwl_remote_wake_packet wake_rx; | ||
316 | |||
317 | /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */ | ||
318 | u8 sequence_number_offset; | ||
319 | u8 sequence_number_length; | ||
320 | u8 token_offset; | ||
321 | u8 token_length; | ||
322 | /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */ | ||
323 | __le32 initial_sequence_number; | ||
324 | __le16 keepalive_interval; | ||
325 | __le16 num_tokens; | ||
326 | u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS]; | ||
327 | } __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */ | ||
328 | |||
280 | /* TODO: NetDetect API */ | 329 | /* TODO: NetDetect API */ |
281 | 330 | ||
282 | #endif /* __fw_api_d3_h__ */ | 331 | #endif /* __fw_api_d3_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 924cabf88b26..ed2d8754c82b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -65,7 +65,9 @@ | |||
65 | #include <linux/skbuff.h> | 65 | #include <linux/skbuff.h> |
66 | #include <linux/netdevice.h> | 66 | #include <linux/netdevice.h> |
67 | #include <linux/etherdevice.h> | 67 | #include <linux/etherdevice.h> |
68 | #include <linux/ip.h> | ||
68 | #include <net/mac80211.h> | 69 | #include <net/mac80211.h> |
70 | #include <net/tcp.h> | ||
69 | 71 | ||
70 | #include "iwl-op-mode.h" | 72 | #include "iwl-op-mode.h" |
71 | #include "iwl-io.h" | 73 | #include "iwl-io.h" |
@@ -102,6 +104,29 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { | |||
102 | }, | 104 | }, |
103 | }; | 105 | }; |
104 | 106 | ||
107 | #ifdef CONFIG_PM_SLEEP | ||
108 | static const struct nl80211_wowlan_tcp_data_token_feature | ||
109 | iwl_mvm_wowlan_tcp_token_feature = { | ||
110 | .min_len = 0, | ||
111 | .max_len = 255, | ||
112 | .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS, | ||
113 | }; | ||
114 | |||
115 | static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { | ||
116 | .tok = &iwl_mvm_wowlan_tcp_token_feature, | ||
117 | .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN - | ||
118 | sizeof(struct ethhdr) - | ||
119 | sizeof(struct iphdr) - | ||
120 | sizeof(struct tcphdr), | ||
121 | .data_interval_max = 65535, /* __le16 in API */ | ||
122 | .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN - | ||
123 | sizeof(struct ethhdr) - | ||
124 | sizeof(struct iphdr) - | ||
125 | sizeof(struct tcphdr), | ||
126 | .seq = true, | ||
127 | }; | ||
128 | #endif | ||
129 | |||
105 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 130 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
106 | { | 131 | { |
107 | struct ieee80211_hw *hw = mvm->hw; | 132 | struct ieee80211_hw *hw = mvm->hw; |
@@ -210,6 +235,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
210 | hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; | 235 | hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; |
211 | hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; | 236 | hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; |
212 | hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; | 237 | hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; |
238 | hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; | ||
213 | } | 239 | } |
214 | #endif | 240 | #endif |
215 | 241 | ||