diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 3643b6ba6385f64c90355e532b7b06e1db2de034..c4562e1f8d18ac47e659744718e773dcacaf7ef8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -618,7 +618,7 @@ struct iwl_wowlan_status_v6 { * @wake_packet_bufsize: wakeup packet buffer size * @wake_packet: wakeup packet */ -struct iwl_wowlan_status { +struct iwl_wowlan_status_v7 { struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; @@ -634,6 +634,43 @@ struct iwl_wowlan_status { u8 wake_packet[]; /* can be truncated from _length to _bufsize */ } __packed; /* WOWLAN_STATUSES_API_S_VER_7 */ +/** + * struct iwl_wowlan_status - WoWLAN status + * @gtk: GTK data + * @igtk: IGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched pattern + * @non_qos_seq_ctr: non-QoS sequence counter to use next + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @wake_packet_length: wakeup packet length + * @wake_packet_bufsize: wakeup packet buffer size + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @reserved: unused + * @wake_packet: wakeup packet + */ +struct iwl_wowlan_status { + struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 non_qos_seq_ctr; + __le16 qos_seq_ctr[8]; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + __le32 wake_packet_length; + __le32 wake_packet_bufsize; + u8 tid_tear_down; + u8 reserved[3]; + u8 wake_packet[]; /* can be truncated from _length to _bufsize */ +} __packed; /* WOWLAN_STATUSES_API_S_VER_9 */ + static inline u8 iwlmvm_wowlan_gtk_idx(struct iwl_wowlan_gtk_status *gtk) { return gtk->key_flags & IWL_WOWLAN_GTK_IDX_MASK; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 122ca7624073debf05e6bf8bd08becfa3a7091b7..2227757148599ede6676f5e7e2c4d1de40ba93ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1517,12 +1517,14 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) { - struct iwl_wowlan_status *v7, *status; + struct iwl_wowlan_status_v7 *v7; + struct iwl_wowlan_status *status; struct iwl_host_cmd cmd = { .id = WOWLAN_GET_STATUSES, .flags = CMD_WANT_SKB, }; - int ret, len, status_size; + int ret, len, status_size, data_size; + u8 notif_ver; lockdep_assert_held(&mvm->mutex); @@ -1532,13 +1534,12 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) return ERR_PTR(ret); } + len = iwl_rx_packet_payload_len(cmd.resp_pkt); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data; - int data_size; status_size = sizeof(*v6); - len = iwl_rx_packet_payload_len(cmd.resp_pkt); if (len < status_size) { IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); @@ -1593,23 +1594,33 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) } v7 = (void *)cmd.resp_pkt->data; - status_size = sizeof(*v7); - len = iwl_rx_packet_payload_len(cmd.resp_pkt); + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + WOWLAN_GET_STATUSES, 0); + + status_size = sizeof(*status); + + if (notif_ver == IWL_FW_CMD_VER_UNKNOWN || notif_ver < 9) + status_size = sizeof(*v7); if (len < status_size) { IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); status = ERR_PTR(-EIO); goto out_free_resp; } + data_size = ALIGN(le32_to_cpu(v7->wake_packet_bufsize), 4); - if (len != (status_size + - ALIGN(le32_to_cpu(v7->wake_packet_bufsize), 4))) { + if (len != (status_size + data_size)) { IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); status = ERR_PTR(-EIO); goto out_free_resp; } - status = kmemdup(v7, len, GFP_KERNEL); + status = kzalloc(sizeof(*status) + data_size, GFP_KERNEL); + if (!status) + goto out_free_resp; + + memcpy(status, v7, status_size); + memcpy(status->wake_packet, (u8 *)v7 + status_size, data_size); out_free_resp: iwl_free_resp(&cmd);