···6161 *6262 *****************************************************************************/63636464+#include <linux/etherdevice.h>6465#include <net/cfg80211.h>6566#include <net/ipv6.h>6667#include "iwl-modparams.h"···193192 sizeof(wkc), &wkc);194193 data->error = ret != 0;195194195195+ mvm->ptk_ivlen = key->iv_len;196196+ mvm->ptk_icvlen = key->icv_len;197197+ mvm->gtk_ivlen = key->iv_len;198198+ mvm->gtk_icvlen = key->icv_len;199199+196200 /* don't upload key again */197201 goto out_unlock;198202 }···310304 */311305 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {312306 key->hw_key_idx = 0;307307+ mvm->ptk_ivlen = key->iv_len;308308+ mvm->ptk_icvlen = key->icv_len;313309 } else {314310 data->gtk_key_idx++;315311 key->hw_key_idx = data->gtk_key_idx;312312+ mvm->gtk_ivlen = key->iv_len;313313+ mvm->gtk_icvlen = key->icv_len;316314 }317315318316 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);···659649 /* We reprogram keys and shouldn't allocate new key indices */660650 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));661651652652+ mvm->ptk_ivlen = 0;653653+ mvm->ptk_icvlen = 0;654654+ mvm->ptk_ivlen = 0;655655+ mvm->ptk_icvlen = 0;656656+662657 /*663658 * The D3 firmware still hardcodes the AP station ID for the664659 * BSS we're associated with as 0. As a result, we have to move···798783 struct iwl_wowlan_status *status;799784 u32 reasons;800785 int ret, len;801801- bool pkt8023 = false;802786 struct sk_buff *pkt = NULL;803787804788 iwl_trans_read_mem_bytes(mvm->trans, base,···838824 status = (void *)cmd.resp_pkt->data;839825840826 if (len - sizeof(struct iwl_cmd_header) !=841841- sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) {827827+ sizeof(*status) +828828+ ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {842829 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");843830 goto out;844831 }···851836 goto report;852837 }853838854854- if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) {839839+ if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)855840 wakeup.magic_pkt = true;856856- pkt8023 = true;857857- }858841859859- if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) {842842+ if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)860843 wakeup.pattern_idx =861844 le16_to_cpu(status->pattern_number);862862- pkt8023 = true;863863- }864845865846 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |866847 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))867848 wakeup.disconnect = true;868849869869- if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) {850850+ if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)870851 wakeup.gtk_rekey_failure = true;871871- pkt8023 = true;872872- }873852874874- if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) {853853+ if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)875854 wakeup.rfkill_release = true;876876- pkt8023 = true;877877- }878855879879- if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) {856856+ if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)880857 wakeup.eap_identity_req = true;881881- pkt8023 = true;882882- }883858884884- if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) {859859+ if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)885860 wakeup.four_way_handshake = true;886886- pkt8023 = true;887887- }888861889862 if (status->wake_packet_bufsize) {890890- u32 pktsize = le32_to_cpu(status->wake_packet_bufsize);891891- u32 pktlen = le32_to_cpu(status->wake_packet_length);863863+ int pktsize = le32_to_cpu(status->wake_packet_bufsize);864864+ int pktlen = le32_to_cpu(status->wake_packet_length);865865+ const u8 *pktdata = status->wake_packet;866866+ struct ieee80211_hdr *hdr = (void *)pktdata;867867+ int truncated = pktlen - pktsize;892868893893- if (pkt8023) {869869+ /* this would be a firmware bug */870870+ if (WARN_ON_ONCE(truncated < 0))871871+ truncated = 0;872872+873873+ if (ieee80211_is_data(hdr->frame_control)) {874874+ int hdrlen = ieee80211_hdrlen(hdr->frame_control);875875+ int ivlen = 0, icvlen = 4; /* also FCS */876876+894877 pkt = alloc_skb(pktsize, GFP_KERNEL);895878 if (!pkt)896879 goto report;897897- memcpy(skb_put(pkt, pktsize), status->wake_packet,898898- pktsize);880880+881881+ memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen);882882+ pktdata += hdrlen;883883+ pktsize -= hdrlen;884884+885885+ if (ieee80211_has_protected(hdr->frame_control)) {886886+ if (is_multicast_ether_addr(hdr->addr1)) {887887+ ivlen = mvm->gtk_ivlen;888888+ icvlen += mvm->gtk_icvlen;889889+ } else {890890+ ivlen = mvm->ptk_ivlen;891891+ icvlen += mvm->ptk_icvlen;892892+ }893893+ }894894+895895+ /* if truncated, FCS/ICV is (partially) gone */896896+ if (truncated >= icvlen) {897897+ icvlen = 0;898898+ truncated -= icvlen;899899+ } else {900900+ icvlen -= truncated;901901+ truncated = 0;902902+ }903903+904904+ pktsize -= ivlen + icvlen;905905+ pktdata += ivlen;906906+907907+ memcpy(skb_put(pkt, pktsize), pktdata, pktsize);908908+899909 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))900910 goto report;901911 wakeup.packet = pkt->data;902912 wakeup.packet_present_len = pkt->len;903903- wakeup.packet_len = pkt->len - (pktlen - pktsize);913913+ wakeup.packet_len = pkt->len - truncated;904914 wakeup.packet_80211 = false;905915 } else {916916+ int fcslen = 4;917917+918918+ if (truncated >= 4) {919919+ truncated -= 4;920920+ fcslen = 0;921921+ } else {922922+ fcslen -= truncated;923923+ truncated = 0;924924+ }925925+ pktsize -= fcslen;906926 wakeup.packet = status->wake_packet;907927 wakeup.packet_present_len = pktsize;908908- wakeup.packet_len = pktlen;928928+ wakeup.packet_len = pktlen - truncated;909929 wakeup.packet_80211 = true;910930 }911931 }
+14-5
drivers/net/wireless/iwlwifi/mvm/mac80211.c
···557557 return ret;558558}559559560560-static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,561561- struct ieee80211_vif *vif)560560+static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,561561+ struct ieee80211_vif *vif)562562{563563- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);564564- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);565563 u32 tfd_msk = 0, ac;566564567565 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)···592594 */593595 flush_work(&mvm->sta_drained_wk);594596 }597597+}598598+599599+static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,600600+ struct ieee80211_vif *vif)601601+{602602+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);603603+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);604604+605605+ iwl_mvm_prepare_mac_removal(mvm, vif);595606596607 mutex_lock(&mvm->mutex);597608598609 /*599610 * For AP/GO interface, the tear down of the resources allocated to the600600- * interface should be handled as part of the bss_info_changed flow.611611+ * interface is be handled as part of the stop_ap flow.601612 */602613 if (vif->type == NL80211_IFTYPE_AP) {603614 iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);···769762{770763 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);771764 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);765765+766766+ iwl_mvm_prepare_mac_removal(mvm, vif);772767773768 mutex_lock(&mvm->mutex);774769
+4
drivers/net/wireless/iwlwifi/mvm/mvm.h
···327327 struct led_classdev led;328328329329 struct ieee80211_vif *p2p_device_vif;330330+331331+#ifdef CONFIG_PM_SLEEP332332+ int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;333333+#endif330334};331335332336/* Extract MVM priv from op_mode and _hw */
+9
drivers/net/wireless/iwlwifi/pcie/internal.h
···182182#define TFD_TX_CMD_SLOTS 256183183#define TFD_CMD_SLOTS 32184184185185+/*186186+ * The FH will write back to the first TB only, so we need187187+ * to copy some data into the buffer regardless of whether188188+ * it should be mapped or not. This indicates how much to189189+ * copy, even for HCMDs it must be big enough to fit the190190+ * DRAM scratch from the TX cmd, at least 16 bytes.191191+ */192192+#define IWL_HCMD_MIN_COPY_SIZE 16193193+185194struct iwl_pcie_txq_entry {186195 struct iwl_device_cmd *cmd;187196 struct iwl_device_cmd *copy_cmd;
+58-17
drivers/net/wireless/iwlwifi/pcie/tx.c
···11521152 void *dup_buf = NULL;11531153 dma_addr_t phys_addr;11541154 int idx;11551155- u16 copy_size, cmd_size;11551155+ u16 copy_size, cmd_size, dma_size;11561156 bool had_nocopy = false;11571157 int i;11581158 u32 cmd_pos;11591159+ const u8 *cmddata[IWL_MAX_CMD_TFDS];11601160+ u16 cmdlen[IWL_MAX_CMD_TFDS];1159116111601162 copy_size = sizeof(out_cmd->hdr);11611163 cmd_size = sizeof(out_cmd->hdr);···11661164 BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);1167116511681166 for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {11671167+ cmddata[i] = cmd->data[i];11681168+ cmdlen[i] = cmd->len[i];11691169+11691170 if (!cmd->len[i])11701171 continue;11721172+11731173+ /* need at least IWL_HCMD_MIN_COPY_SIZE copied */11741174+ if (copy_size < IWL_HCMD_MIN_COPY_SIZE) {11751175+ int copy = IWL_HCMD_MIN_COPY_SIZE - copy_size;11761176+11771177+ if (copy > cmdlen[i])11781178+ copy = cmdlen[i];11791179+ cmdlen[i] -= copy;11801180+ cmddata[i] += copy;11811181+ copy_size += copy;11821182+ }11831183+11711184 if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {11721185 had_nocopy = true;11731186 if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) {···12021185 goto free_dup_buf;12031186 }1204118712051205- dup_buf = kmemdup(cmd->data[i], cmd->len[i],11881188+ dup_buf = kmemdup(cmddata[i], cmdlen[i],12061189 GFP_ATOMIC);12071190 if (!dup_buf)12081191 return -ENOMEM;···12121195 idx = -EINVAL;12131196 goto free_dup_buf;12141197 }12151215- copy_size += cmd->len[i];11981198+ copy_size += cmdlen[i];12161199 }12171200 cmd_size += cmd->len[i];12181201 }···1259124212601243 /* and copy the data that needs to be copied */12611244 cmd_pos = offsetof(struct iwl_device_cmd, payload);12451245+ copy_size = sizeof(out_cmd->hdr);12621246 for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {12631263- if (!cmd->len[i])12471247+ int copy = 0;12481248+12491249+ if (!cmd->len)12641250 continue;12651265- if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |12661266- IWL_HCMD_DFL_DUP))12671267- break;12681268- memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);12691269- cmd_pos += cmd->len[i];12511251+12521252+ /* need at least IWL_HCMD_MIN_COPY_SIZE copied */12531253+ if (copy_size < IWL_HCMD_MIN_COPY_SIZE) {12541254+ copy = IWL_HCMD_MIN_COPY_SIZE - copy_size;12551255+12561256+ if (copy > cmd->len[i])12571257+ copy = cmd->len[i];12581258+ }12591259+12601260+ /* copy everything if not nocopy/dup */12611261+ if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |12621262+ IWL_HCMD_DFL_DUP)))12631263+ copy = cmd->len[i];12641264+12651265+ if (copy) {12661266+ memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy);12671267+ cmd_pos += copy;12681268+ copy_size += copy;12691269+ }12701270 }1271127112721272 WARN_ON_ONCE(txq->entries[idx].copy_cmd);···13091275 out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),13101276 cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);1311127713121312- phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,12781278+ /*12791279+ * If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must12801280+ * still map at least that many bytes for the hardware to write back to.12811281+ * We have enough space, so that's not a problem.12821282+ */12831283+ dma_size = max_t(u16, copy_size, IWL_HCMD_MIN_COPY_SIZE);12841284+12851285+ phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, dma_size,13131286 DMA_BIDIRECTIONAL);13141287 if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {13151288 idx = -ENOMEM;···13241283 }1325128413261285 dma_unmap_addr_set(out_meta, mapping, phys_addr);13271327- dma_unmap_len_set(out_meta, len, copy_size);12861286+ dma_unmap_len_set(out_meta, len, dma_size);1328128713291288 iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1);1330128912901290+ /* map the remaining (adjusted) nocopy/dup fragments */13311291 for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {13321332- const void *data = cmd->data[i];12921292+ const void *data = cmddata[i];1333129313341334- if (!cmd->len[i])12941294+ if (!cmdlen[i])13351295 continue;13361296 if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |13371297 IWL_HCMD_DFL_DUP)))···13401298 if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)13411299 data = dup_buf;13421300 phys_addr = dma_map_single(trans->dev, (void *)data,13431343- cmd->len[i], DMA_BIDIRECTIONAL);13011301+ cmdlen[i], DMA_BIDIRECTIONAL);13441302 if (dma_mapping_error(trans->dev, phys_addr)) {13451303 iwl_pcie_tfd_unmap(trans, out_meta,13461304 &txq->tfds[q->write_ptr],···13491307 goto out;13501308 }1351130913521352- iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0);13101310+ iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0);13531311 }1354131213551313 out_meta->flags = cmd->flags;···1359131713601318 txq->need_update = 1;1361131913621362- trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size,13631363- &out_cmd->hdr, copy_size);13201320+ trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);1364132113651322 /* start timer if queue currently empty */13661323 if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
+5-1
drivers/net/wireless/libertas/if_sdio.c
···825825826826 sdio_release_host(func);827827828828+ /* Set fw_ready before queuing any commands so that829829+ * lbs_thread won't block from sending them to firmware.830830+ */831831+ priv->fw_ready = 1;832832+828833 /*829834 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions830835 */···844839 netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");845840 }846841847847- priv->fw_ready = 1;848842 wake_up(&card->pwron_waitq);849843850844 if (!card->started) {