/* * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format * @mvm: the mvm object * @hdr: 80211 header * @stats: status in mac80211's format * @rx_pkt_status: status coming from fw * * returns non 0 value if the packet should be dropped */ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *stats, u32 rx_pkt_status, u8 *crypt_len) { if (!ieee80211_has_protected(hdr->frame_control) || (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == RX_MPDU_RES_STATUS_SEC_NO_ENC) return 0; /* packet was encrypted with unknown alg */ if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == RX_MPDU_RES_STATUS_SEC_ENC_ERR) return 0; switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) { case RX_MPDU_RES_STATUS_SEC_CCM_ENC: /* alg is CCM: check MIC only */ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK)) return -1; stats->flag |= RX_FLAG_DECRYPTED; *crypt_len = IEEE80211_CCMP_HDR_LEN; return 0; case RX_MPDU_RES_STATUS_SEC_TKIP_ENC: /* Don't drop the frame and decrypt it in SW */ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) return 0; *crypt_len = IEEE80211_TKIP_IV_LEN; /* fall through if TTAK OK */ case RX_MPDU_RES_STATUS_SEC_WEP_ENC: if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK)) return -1; stats->flag |= RX_FLAG_DECRYPTED; if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) == RX_MPDU_RES_STATUS_SEC_WEP_ENC) *crypt_len = IEEE80211_WEP_IV_LEN; return 0; case RX_MPDU_RES_STATUS_SEC_EXT_ENC: if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK)) return -1; stats->flag |= RX_FLAG_DECRYPTED; return 0; default: IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); } return 0; }
static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *stats, struct iwl_rx_mpdu_desc *desc, int queue, u8 *crypt_len) { u16 status = le16_to_cpu(desc->status); if (!ieee80211_has_protected(hdr->frame_control) || (status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) return 0; /* TODO: handle packets encrypted with unknown alg */ switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) { case IWL_RX_MPDU_STATUS_SEC_CCM: case IWL_RX_MPDU_STATUS_SEC_GCM: BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN); /* alg is CCM: check MIC only */ if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) return -1; stats->flag |= RX_FLAG_DECRYPTED; *crypt_len = IEEE80211_CCMP_HDR_LEN; return 0; case IWL_RX_MPDU_STATUS_SEC_TKIP: /* Don't drop the frame and decrypt it in SW */ if (!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK)) return 0; *crypt_len = IEEE80211_TKIP_IV_LEN; /* fall through if TTAK OK */ case IWL_RX_MPDU_STATUS_SEC_WEP: if (!(status & IWL_RX_MPDU_STATUS_ICV_OK)) return -1; stats->flag |= RX_FLAG_DECRYPTED; if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_WEP) *crypt_len = IEEE80211_WEP_IV_LEN; return 0; case IWL_RX_MPDU_STATUS_SEC_EXT_ENC: if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) return -1; stats->flag |= RX_FLAG_DECRYPTED; return 0; default: IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status); } return 0; }
void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, struct sk_buff *skb, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rxs, bool decrypt_error) { struct ath_hw *ah = common->ah; struct ieee80211_hdr *hdr; int hdrlen, padpos, padsize; u8 keyix; __le16 fc; /* see if any padding is done by the hw and remove it */ hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; padpos = ath9k_cmn_padpos(hdr->frame_control); /* The MAC header is padded to have 32-bit boundary if the * packet payload is non-zero. The general calculation for * padsize would take into account odd header lengths: * padsize = (4 - padpos % 4) % 4; However, since only * even-length headers are used, padding can only be 0 or 2 * bytes and we can optimize this a bit. In addition, we must * not try to remove padding from short control frames that do * not have payload. */ padsize = padpos & 3; if (padsize && skb->len>=padpos+padsize+FCS_LEN) { memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } keyix = rx_stats->rs_keyix; if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { rxs->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; if (test_bit(keyix, common->keymap)) rxs->flag |= RX_FLAG_DECRYPTED; }
static inline void mwl_tx_skb(struct mwl_priv *priv, int desc_num, struct sk_buff *tx_skb) { struct ieee80211_tx_info *tx_info; struct mwl_tx_ctrl *tx_ctrl; struct mwl_tx_hndl *tx_hndl; struct mwl_tx_desc *tx_desc; struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct mwl_vif *mwl_vif; struct ieee80211_key_conf *k_conf; bool ccmp = false; struct mwl_dma_data *dma_data; struct ieee80211_hdr *wh; dma_addr_t dma; if (WARN_ON(!tx_skb)) return; tx_info = IEEE80211_SKB_CB(tx_skb); tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status; sta = (struct ieee80211_sta *)tx_ctrl->sta; vif = (struct ieee80211_vif *)tx_ctrl->vif; mwl_vif = mwl_dev_get_vif(vif); k_conf = (struct ieee80211_key_conf *)tx_ctrl->k_conf; mwl_tx_encapsulate_frame(priv, tx_skb, k_conf, &ccmp); dma_data = (struct mwl_dma_data *)tx_skb->data; wh = &dma_data->wh; if (ieee80211_is_data(wh->frame_control) || (ieee80211_is_mgmt(wh->frame_control) && ieee80211_has_protected(wh->frame_control) && !is_multicast_ether_addr(wh->addr1))) { if (is_multicast_ether_addr(wh->addr1)) { if (ccmp) { mwl_tx_insert_ccmp_hdr(dma_data->data, mwl_vif->keyidx, mwl_vif->iv16, mwl_vif->iv32); INCREASE_IV(mwl_vif->iv16, mwl_vif->iv32); } } else { if (ccmp) { if (vif->type == NL80211_IFTYPE_STATION) { mwl_tx_insert_ccmp_hdr(dma_data->data, mwl_vif->keyidx, mwl_vif->iv16, mwl_vif->iv32); INCREASE_IV(mwl_vif->iv16, mwl_vif->iv32); } else { struct mwl_sta *sta_info; sta_info = mwl_dev_get_sta(sta); mwl_tx_insert_ccmp_hdr(dma_data->data, 0, sta_info->iv16, sta_info->iv32); INCREASE_IV(sta_info->iv16, sta_info->iv32); } } } } tx_hndl = priv->desc_data[desc_num].pnext_tx_hndl; tx_hndl->psk_buff = tx_skb; tx_desc = tx_hndl->pdesc; tx_desc->tx_priority = tx_ctrl->tx_priority; tx_desc->qos_ctrl = cpu_to_le16(tx_ctrl->qos_ctrl); tx_desc->pkt_len = cpu_to_le16(tx_skb->len); tx_desc->packet_info = 0; tx_desc->data_rate = 0; tx_desc->type = tx_ctrl->type; tx_desc->xmit_control = tx_ctrl->xmit_control; tx_desc->sap_pkt_info = 0; dma = pci_map_single(priv->pdev, tx_skb->data, tx_skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(priv->pdev, dma)) { dev_kfree_skb_any(tx_skb); wiphy_err(priv->hw->wiphy, "failed to map pci memory!\n"); return; } tx_desc->pkt_ptr = cpu_to_le32(dma); tx_desc->status = cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED); /* make sure all the memory transactions done by cpu were completed */ wmb(); /*Data Memory Barrier*/ writel(MACREG_H2ARIC_BIT_PPA_READY, priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS); priv->desc_data[desc_num].pnext_tx_hndl = tx_hndl->pnext; priv->fw_desc_cnt[desc_num]++; }
static bool vnt_rx_data(struct vnt_private *priv, struct sk_buff *skb, u16 bytes_received) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_supported_band *sband; struct ieee80211_rx_status rx_status = { 0 }; struct ieee80211_hdr *hdr; __le16 fc; u8 *rsr, *new_rsr, *rssi; __le64 *tsf_time; u16 frame_size; int ii, r; u8 *rx_sts, *rx_rate, *sq; u8 *skb_data; u8 rate_idx = 0; u8 rate[MAX_RATE] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; long rx_dbm; /* [31:16]RcvByteCount ( not include 4-byte Status ) */ frame_size = le16_to_cpu(*((__le16 *)(skb->data + 2))); if (frame_size > 2346 || frame_size < 14) { dev_dbg(&priv->pcid->dev, "------- WRONG Length 1\n"); return false; } skb_data = (u8 *)skb->data; rx_sts = skb_data; rx_rate = skb_data + 1; sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; for (r = RATE_1M; r < MAX_RATE; r++) { if (*rx_rate == rate[r]) break; } priv->rx_rate = r; for (ii = 0; ii < sband->n_bitrates; ii++) { if (sband->bitrates[ii].hw_value == r) { rate_idx = ii; break; } } if (ii == sband->n_bitrates) { dev_dbg(&priv->pcid->dev, "Wrong RxRate %x\n", *rx_rate); return false; } tsf_time = (__le64 *)(skb_data + bytes_received - 12); sq = skb_data + bytes_received - 4; new_rsr = skb_data + bytes_received - 3; rssi = skb_data + bytes_received - 2; rsr = skb_data + bytes_received - 1; if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) return false; RFvRSSITodBm(priv, *rssi, &rx_dbm); priv->byBBPreEDRSSI = (u8)rx_dbm + 1; priv->uCurrRSSI = *rssi; skb_pull(skb, 4); skb_trim(skb, frame_size); rx_status.mactime = le64_to_cpu(*tsf_time); rx_status.band = hw->conf.chandef.chan->band; rx_status.signal = rx_dbm; rx_status.flag = 0; rx_status.freq = hw->conf.chandef.chan->center_freq; if (!(*rsr & RSR_CRCOK)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; rx_status.rate_idx = rate_idx; if (ieee80211_has_protected(fc)) { if (priv->byLocalID > REV_ID_VT3253_A1) rx_status.flag |= RX_FLAG_DECRYPTED; /* Drop packet */ if (!(*new_rsr & NEWRSR_DECRYPTOK)) return false; } memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(priv->hw, skb); return true; }
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct ath10k *ar = htt->ar; struct device *dev = ar->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); struct ath10k_hif_sg_item sg_items[2]; struct htt_data_tx_desc_frag *frags; u8 vdev_id = skb_cb->vdev_id; u8 tid = skb_cb->htt.tid; int prefetch_len; int res; u8 flags0 = 0; u16 msdu_id, flags1 = 0; dma_addr_t paddr; u32 frags_paddr; bool use_frags; res = ath10k_htt_tx_inc_pending(htt); if (res) goto err; spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt); if (res < 0) { spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); /* Since HTT 3.0 there is no separate mgmt tx command. However in case * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx * fragment list host driver specifies directly frame pointer. */ use_frags = htt->target_version_major < 3 || !ieee80211_is_mgmt(hdr->frame_control); skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, &paddr); if (!skb_cb->htt.txbuf) goto err_free_msdu_id; skb_cb->htt.txbuf_paddr = paddr; skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); if (res) goto err_free_txbuf; if (likely(use_frags)) { frags = skb_cb->htt.txbuf->frags; frags[0].paddr = __cpu_to_le32(skb_cb->paddr); frags[0].len = __cpu_to_le32(msdu->len); frags[1].paddr = 0; frags[1].len = 0; flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); frags_paddr = skb_cb->htt.txbuf_paddr; } else { flags0 |= SM(ATH10K_HW_TXRX_MGMT, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); frags_paddr = skb_cb->paddr; } /* Normally all commands go through HTC which manages tx credits for * each endpoint and notifies when tx is completed. * * HTT endpoint is creditless so there's no need to care about HTC * flags. In that case it is trivial to fill the HTC header here. * * MSDU transmission is considered completed upon HTT event. This * implies no relevant resources can be freed until after the event is * received. That's why HTC tx completion handler itself is ignored by * setting NULL to transfer_context for all sg items. * * There is simply no point in pushing HTT TX_FRM through HTC tx path * as it's a waste of resources. By bypassing HTC it is possible to * avoid extra memory allocations, compress data structures and thus * improve performance. */ skb_cb->htt.txbuf->htc_hdr.eid = htt->eid; skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16( sizeof(skb_cb->htt.txbuf->cmd_hdr) + sizeof(skb_cb->htt.txbuf->cmd_tx) + prefetch_len); skb_cb->htt.txbuf->htc_hdr.flags = 0; if (!ieee80211_has_protected(hdr->frame_control)) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; /* Prevent firmware from sending up tx inspection requests. There's * nothing ath10k can do with frames requested for inspection so force * it to simply rely a regular tx completion with discard status. */ flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID); skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq); trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n", flags0, flags1, msdu->len, msdu_id, frags_paddr, (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", msdu->data, msdu->len); trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); trace_ath10k_tx_payload(ar, msdu->data, msdu->len); sg_items[0].transfer_id = 0; sg_items[0].transfer_context = NULL; sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr; sg_items[0].paddr = skb_cb->htt.txbuf_paddr + sizeof(skb_cb->htt.txbuf->frags); sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) + sizeof(skb_cb->htt.txbuf->cmd_hdr) + sizeof(skb_cb->htt.txbuf->cmd_tx); sg_items[1].transfer_id = 0; sg_items[1].transfer_context = NULL; sg_items[1].vaddr = msdu->data; sg_items[1].paddr = skb_cb->paddr; sg_items[1].len = prefetch_len; res = ath10k_hif_tx_sg(htt->ar, htt->ar->htc.endpoint[htt->eid].ul_pipe_id, sg_items, ARRAY_SIZE(sg_items)); if (res) goto err_unmap_msdu; return 0; err_unmap_msdu: dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_txbuf: dma_pool_free(htt->tx_pool, skb_cb->htt.txbuf, skb_cb->htt.txbuf_paddr); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err_tx_dec: ath10k_htt_tx_dec_pending(htt); err: return res; }
static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_tfh_tfd *tfd, int start_len, u8 hdr_len, struct iwl_device_cmd *dev_cmd) { #ifdef CONFIG_INET struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, iv_len, amsdu_pad; u8 *start_hdr; struct iwl_tso_hdr_page *hdr_page; struct page **page_ptr; struct tso_t tso; /* if the packet is protected, then it must be CCMP or GCMP */ iv_len = ieee80211_has_protected(hdr->frame_control) ? IEEE80211_CCMP_HDR_LEN : 0; trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, start_len, 0); ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len; amsdu_pad = 0; /* total amount of header we may need for this A-MSDU */ hdr_room = DIV_ROUND_UP(total_len, mss) * (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; /* Our device supports 9 segments at most, it will fit in 1 page */ hdr_page = get_page_hdr(trans, hdr_room); if (!hdr_page) return -ENOMEM; get_page(hdr_page->page); start_hdr = hdr_page->pos; page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs); *page_ptr = hdr_page->page; memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); hdr_page->pos += iv_len; /* * Pull the ieee80211 header + IV to be able to use TSO core, * we will restore it for the tx_status flow. */ skb_pull(skb, hdr_len + iv_len); /* * Remove the length of all the headers that we don't actually * have in the MPDU by themselves, but that we duplicate into * all the different MSDUs inside the A-MSDU. */ le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); tso_start(skb, &tso); while (total_len) { /* this is the data left for this subframe */ unsigned int data_left = min_t(unsigned int, mss, total_len); struct sk_buff *csum_skb = NULL; unsigned int tb_len; dma_addr_t tb_phys; u8 *subf_hdrs_start = hdr_page->pos; total_len -= data_left; memset(hdr_page->pos, 0, amsdu_pad); hdr_page->pos += amsdu_pad; amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + data_left)) & 0x3; ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); hdr_page->pos += ETH_ALEN; ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); hdr_page->pos += ETH_ALEN; length = snap_ip_tcp_hdrlen + data_left; *((__be16 *)hdr_page->pos) = cpu_to_be16(length); hdr_page->pos += sizeof(length); /* * This will copy the SNAP as well which will be considered * as MAC header. */ tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); hdr_page->pos += snap_ip_tcp_hdrlen; tb_len = hdr_page->pos - start_hdr; tb_phys = dma_map_single(trans->dev, start_hdr, tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { dev_kfree_skb(csum_skb); goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_len); /* add this subframe's headers' length to the tx_cmd */ le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); /* prepare the start_hdr for the next subframe */ start_hdr = hdr_page->pos; /* put the payload */ while (data_left) { tb_len = min_t(unsigned int, tso.size, data_left); tb_phys = dma_map_single(trans->dev, tso.data, tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { dev_kfree_skb(csum_skb); goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data, tb_len); data_left -= tb_len; tso_build_data(skb, &tso, tb_len); } } /* re -add the WiFi header and IV */ skb_push(skb, hdr_len + iv_len); return 0; out_err: #endif return -EINVAL; }
/* Assumes you've already done the endian to CPU conversion */ bool ath9k_cmn_rx_accept(struct ath_common *common, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rxs, struct ath_rx_status *rx_stats, bool *decrypt_error, unsigned int rxfilter) { struct ath_hw *ah = common->ah; bool is_mc, is_valid_tkip, strip_mic, mic_error; __le16 fc; fc = hdr->frame_control; is_mc = !!is_multicast_ether_addr(hdr->addr1); is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && test_bit(rx_stats->rs_keyix, common->tkip_keymap); strip_mic = is_valid_tkip && ieee80211_is_data(fc) && ieee80211_has_protected(fc) && !(rx_stats->rs_status & (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | ATH9K_RXERR_KEYMISS)); /* * Key miss events are only relevant for pairwise keys where the * descriptor does contain a valid key index. This has been observed * mostly with CCMP encryption. */ if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && !ieee80211_has_morefrags(fc) && !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && (rx_stats->rs_status & ATH9K_RXERR_MIC); /* * The rx_stats->rs_status will not be set until the end of the * chained descriptors so it can be ignored if rs_more is set. The * rs_more will be false at the last element of the chained * descriptors. */ if (rx_stats->rs_status != 0) { u8 status_mask; if (rx_stats->rs_status & ATH9K_RXERR_CRC) { rxs->flag |= RX_FLAG_FAILED_FCS_CRC; mic_error = false; } if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { *decrypt_error = true; mic_error = false; } /* * Reject error frames with the exception of * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_KEYMISS; if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL)) status_mask |= ATH9K_RXERR_CRC; if (rx_stats->rs_status & ~status_mask) return false; } /* * For unicast frames the MIC error bit can have false positives, * so all MIC error reports need to be validated in software. * False negatives are not common, so skip software verification * if the hardware considers the MIC valid. */ if (strip_mic) rxs->flag |= RX_FLAG_MMIC_STRIPPED; else if (is_mc && mic_error) rxs->flag |= RX_FLAG_MMIC_ERROR; return true; }
void mwl_rx_recv(unsigned long data) { struct ieee80211_hw *hw = (struct ieee80211_hw *)data; struct mwl_priv *priv; struct mwl_rx_desc *curr_desc; int work_done = 0; struct sk_buff *prx_skb = NULL; int pkt_len; struct ieee80211_rx_status status; struct mwl_vif *mwl_vif = NULL; struct ieee80211_hdr *wh; u32 status_mask; WLDBG_ENTER(DBG_LEVEL_4); BUG_ON(!hw); priv = hw->priv; BUG_ON(!priv); curr_desc = priv->desc_data[0].pnext_rx_desc; if (curr_desc == NULL) { status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); priv->is_rx_schedule = false; WLDBG_EXIT_INFO(DBG_LEVEL_4, "busy or no receiving packets"); return; } while ((curr_desc->rx_control == EAGLE_RXD_CTRL_DMA_OWN) && (work_done < priv->recv_limit)) { prx_skb = curr_desc->psk_buff; if (prx_skb == NULL) goto out; pci_unmap_single(priv->pdev, ENDIAN_SWAP32(curr_desc->pphys_buff_data), priv->desc_data[0].rx_buf_size, PCI_DMA_FROMDEVICE); pkt_len = curr_desc->pkt_len; if (skb_tailroom(prx_skb) < pkt_len) { WLDBG_PRINT("Critical error: not enough tail room =%x pkt_len=%x, curr_desc=%x, curr_desc_data=%x", skb_tailroom(prx_skb), pkt_len, curr_desc, curr_desc->pbuff_data); dev_kfree_skb_any(prx_skb); goto out; } if (curr_desc->channel != hw->conf.chandef.chan->hw_value) { dev_kfree_skb_any(prx_skb); goto out; } mwl_rx_prepare_status(curr_desc, &status); priv->noise = -curr_desc->noise_floor; wh = &((struct mwl_dma_data *)prx_skb->data)->wh; if (ieee80211_has_protected(wh->frame_control)) { /* Check if hw crypto has been enabled for * this bss. If yes, set the status flags * accordingly */ if (ieee80211_has_tods(wh->frame_control)) mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list, wh->addr1); else mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list, wh->addr2); if (mwl_vif != NULL && mwl_vif->is_hw_crypto_enabled) { /* * When MMIC ERROR is encountered * by the firmware, payload is * dropped and only 32 bytes of * mwl8k Firmware header is sent * to the host. * * We need to add four bytes of * key information. In it * MAC80211 expects keyidx set to * 0 for triggering Counter * Measure of MMIC failure. */ if (status.flag & RX_FLAG_MMIC_ERROR) { struct mwl_dma_data *tr; tr = (struct mwl_dma_data *)prx_skb->data; memset((void *)&(tr->data), 0, 4); pkt_len += 4; } if (!ieee80211_is_auth(wh->frame_control)) status.flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED; } } skb_put(prx_skb, pkt_len); mwl_rx_remove_dma_header(prx_skb, curr_desc->qos_ctrl); memcpy(IEEE80211_SKB_RXCB(prx_skb), &status, sizeof(status)); ieee80211_rx(hw, prx_skb); out: mwl_rx_refill(priv, curr_desc); curr_desc->rx_control = EAGLE_RXD_CTRL_DRIVER_OWN; curr_desc->qos_ctrl = 0; curr_desc = curr_desc->pnext; work_done++; } priv->desc_data[0].pnext_rx_desc = curr_desc; status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); priv->is_rx_schedule = false; WLDBG_EXIT(DBG_LEVEL_4); }
int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb, unsigned long bytes_received) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_rx_status rx_status = { 0 }; struct ieee80211_hdr *hdr; __le16 fc; u8 *rsr, *new_rsr, *rssi, *frame; __le64 *tsf_time; u32 frame_size; int ii, r; u8 *rx_sts, *rx_rate, *sq, *sq_3; u32 wbk_status; u8 *skb_data; u16 *pay_load_len; u16 pay_load_with_padding; u8 rate_idx = 0; u8 rate[MAX_RATE] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; long rx_dbm; skb = ptr_rcb->skb; /* [31:16]RcvByteCount ( not include 4-byte Status ) */ wbk_status = *((u32 *)(skb->data)); frame_size = wbk_status >> 16; frame_size += 4; if (bytes_received != frame_size) { dev_dbg(&priv->usb->dev, "------- WRONG Length 1\n"); return false; } if ((bytes_received > 2372) || (bytes_received <= 40)) { /* Frame Size error drop this packet.*/ dev_dbg(&priv->usb->dev, "------ WRONG Length 2\n"); return false; } skb_data = (u8 *)skb->data; rx_sts = skb_data+4; rx_rate = skb_data+5; /* real Frame Size = USBframe_size -4WbkStatus - 4RxStatus */ /* -8TSF - 4RSR - 4SQ3 - ?Padding */ /* if SQ3 the range is 24~27, if no SQ3 the range is 20~23 */ pay_load_len = (u16 *) (skb_data + 6); /*Fix hardware bug => PLCP_Length error */ if (((bytes_received - (*pay_load_len)) > 27) || ((bytes_received - (*pay_load_len)) < 24) || (bytes_received < (*pay_load_len))) { dev_dbg(&priv->usb->dev, "Wrong PLCP Length %x\n", *pay_load_len); return false; } sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; for (r = RATE_1M; r < MAX_RATE; r++) { if (*rx_rate == rate[r]) break; } priv->rx_rate = r; for (ii = 0; ii < sband->n_bitrates; ii++) { if (sband->bitrates[ii].hw_value == r) { rate_idx = ii; break; } } if (ii == sband->n_bitrates) { dev_dbg(&priv->usb->dev, "Wrong RxRate %x\n", *rx_rate); return false; } pay_load_with_padding = ((*pay_load_len / 4) + ((*pay_load_len % 4) ? 1 : 0)) * 4; tsf_time = (__le64 *)(skb_data + 8 + pay_load_with_padding); priv->tsf_time = le64_to_cpu(*tsf_time); if (priv->bb_type == BB_TYPE_11G) { sq_3 = skb_data + 8 + pay_load_with_padding + 12; sq = sq_3; } else { sq = skb_data + 8 + pay_load_with_padding + 8; sq_3 = sq; } new_rsr = skb_data + 8 + pay_load_with_padding + 9; rssi = skb_data + 8 + pay_load_with_padding + 10; rsr = skb_data + 8 + pay_load_with_padding + 11; if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) return false; frame_size = *pay_load_len; vnt_rf_rssi_to_dbm(priv, *rssi, &rx_dbm); priv->bb_pre_ed_rssi = (u8)rx_dbm + 1; priv->current_rssi = priv->bb_pre_ed_rssi; frame = skb_data + 8; skb_pull(skb, 8); skb_trim(skb, frame_size); rx_status.mactime = priv->tsf_time; rx_status.band = hw->conf.chandef.chan->band; rx_status.signal = rx_dbm; rx_status.flag = 0; rx_status.freq = hw->conf.chandef.chan->center_freq; if (!(*rsr & RSR_CRCOK)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; rx_status.rate_idx = rate_idx; if (ieee80211_has_protected(fc)) { if (priv->local_id > REV_ID_VT3253_A1) { rx_status.flag |= RX_FLAG_DECRYPTED; /* Drop packet */ if (!(*new_rsr & NEWRSR_DECRYPTOK)) { dev_kfree_skb(skb); return true; } } } memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(priv->hw, skb); return true; }
static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_hdr *hdr, u16 len, u32 ampdu_status, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { struct sk_buff *skb; int ret = 0; __le16 fc = hdr->frame_control; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, "Dropping packet while interface is not open.\n"); return; } /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; } skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ if (ieee80211_is_mgmt(fc) || ieee80211_has_protected(fc) || ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG || (ieee80211_is_data_qos(fc) && *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)) ret = skb_linearize(skb); else ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? 0 : -ENOMEM; if (ret) { kfree_skb(skb); goto out; } /* * XXX: We cannot touch the page and its virtual memory (hdr) after * here. It might have already been freed by the above skb change. */ iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); out: priv->alloc_rxb_page--; rxb->page = NULL; }
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct device *dev = htt->ar->dev; struct htt_cmd *cmd; struct htt_data_tx_desc_frag *tx_frags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); struct sk_buff *txdesc = NULL; bool use_frags; u8 vdev_id = ATH10K_SKB_CB(msdu)->vdev_id; u8 tid; int prefetch_len, desc_len; int msdu_id = -1; int res; u8 flags0; u16 flags1; res = ath10k_htt_tx_inc_pending(htt); if (res) goto err; spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt); if (res < 0) { spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len; txdesc = ath10k_htc_alloc_skb(desc_len); if (!txdesc) { res = -ENOMEM; goto err_free_msdu_id; } /* Since HTT 3.0 there is no separate mgmt tx command. However in case * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx * fragment list host driver specifies directly frame pointer. */ use_frags = htt->target_version_major < 3 || !ieee80211_is_mgmt(hdr->frame_control); if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { ath10k_warn("htt alignment check failed. dropping packet.\n"); res = -EIO; goto err_free_txdesc; } if (use_frags) { skb_cb->htt.frag_len = sizeof(*tx_frags) * 2; skb_cb->htt.pad_len = (unsigned long)msdu->data - round_down((unsigned long)msdu->data, 4); skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); } else { skb_cb->htt.frag_len = 0; skb_cb->htt.pad_len = 0; } res = ath10k_skb_map(dev, msdu); if (res) goto err_pull_txfrag; if (use_frags) { dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); /* tx fragment list must be terminated with zero-entry */ tx_frags = (struct htt_data_tx_desc_frag *)msdu->data; tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr + skb_cb->htt.frag_len + skb_cb->htt.pad_len); tx_frags[0].len = __cpu_to_le32(msdu->len - skb_cb->htt.frag_len - skb_cb->htt.pad_len); tx_frags[1].paddr = __cpu_to_le32(0); tx_frags[1].len = __cpu_to_le32(0); dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); } ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", msdu->data, msdu->len); skb_put(txdesc, desc_len); cmd = (struct htt_cmd *)txdesc->data; tid = ATH10K_SKB_CB(msdu)->htt.tid; ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid); flags0 = 0; if (!ieee80211_has_protected(hdr->frame_control)) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; if (use_frags) flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); else flags0 |= SM(ATH10K_HW_TXRX_MGMT, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); flags1 = 0; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; cmd->data_tx.flags0 = flags0; cmd->data_tx.flags1 = __cpu_to_le16(flags1); cmd->data_tx.len = __cpu_to_le16(msdu->len - skb_cb->htt.frag_len - skb_cb->htt.pad_len); cmd->data_tx.id = __cpu_to_le16(msdu_id); cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr); cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); memcpy(cmd->data_tx.prefetch, hdr, prefetch_len); res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) goto err_unmap_msdu; return 0; err_unmap_msdu: ath10k_skb_unmap(dev, msdu); err_pull_txfrag: skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err_tx_dec: ath10k_htt_tx_dec_pending(htt); err: return res; }
void pcie_tx_xmit_ndp(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mwl_priv *priv = hw->priv; struct pcie_priv *pcie_priv = priv->hif.priv; struct ieee80211_tx_info *tx_info; struct ieee80211_key_conf *k_conf; struct mwl_vif *mwl_vif; int index; struct ieee80211_sta *sta; struct mwl_sta *sta_info; struct ieee80211_hdr *wh; u8 *da; u16 qos; u8 tid = 0; struct mwl_ampdu_stream *stream = NULL; u16 tx_que_priority; bool mgmtframe = false; struct ieee80211_mgmt *mgmt; bool eapol_frame = false; bool start_ba_session = false; struct pcie_tx_ctrl_ndp *tx_ctrl; tx_info = IEEE80211_SKB_CB(skb); k_conf = tx_info->control.hw_key; mwl_vif = mwl_dev_get_vif(tx_info->control.vif); index = skb_get_queue_mapping(skb); sta = control->sta; sta_info = sta ? mwl_dev_get_sta(sta) : NULL; wh = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(wh->frame_control)) qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); else qos = 0xFFFF; if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { index = IEEE80211_AC_VO; eapol_frame = true; } if (ieee80211_is_mgmt(wh->frame_control)) { mgmtframe = true; mgmt = (struct ieee80211_mgmt *)skb->data; } if (mgmtframe) { u16 capab; if (unlikely(ieee80211_is_action(wh->frame_control) && mgmt->u.action.category == WLAN_CATEGORY_BACK && mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)) { capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; index = utils_tid_to_ac(tid); } if (unlikely(ieee80211_is_assoc_req(wh->frame_control))) utils_add_basic_rates(hw->conf.chandef.chan->band, skb); if (ieee80211_is_probe_req(wh->frame_control) || ieee80211_is_probe_resp(wh->frame_control)) tx_que_priority = PROBE_RESPONSE_TXQNUM; else { if (( (mwl_vif->macid == SYSADPT_NUM_OF_AP) && (!ieee80211_has_protected(wh->frame_control) || (ieee80211_has_protected(wh->frame_control) && ieee80211_is_auth(wh->frame_control))) ) || !sta || ieee80211_is_auth(wh->frame_control) || ieee80211_is_assoc_req(wh->frame_control) || ieee80211_is_assoc_resp(wh->frame_control)) tx_que_priority = MGMT_TXQNUM; else { if (is_multicast_ether_addr(wh->addr1) && (mwl_vif->macid != SYSADPT_NUM_OF_AP)) tx_que_priority = mwl_vif->macid * SYSADPT_MAX_TID; else tx_que_priority = SYSADPT_MAX_TID * (sta_info->stnid + QUEUE_STAOFFSET) + 6; } } if (ieee80211_is_assoc_resp(wh->frame_control) || ieee80211_is_reassoc_resp(wh->frame_control)) { struct sk_buff *ack_skb; struct ieee80211_tx_info *ack_info; ack_skb = skb_copy(skb, GFP_ATOMIC); ack_info = IEEE80211_SKB_CB(ack_skb); pcie_tx_prepare_info(priv, 0, ack_info); ieee80211_tx_status(hw, ack_skb); } pcie_tx_encapsulate_frame(priv, skb, k_conf, NULL); } else {
bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb) { struct rx_fwinfo *p_drvinfo; u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); struct ieee80211_hdr *hdr; stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); stats->hwerror = (u16)(stats->crc | stats->icv); stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); stats->isfirst_ampdu = (bool) ((GET_RX_STATUS_DESC_PAGGR(pdesc) == 1) && (GET_RX_STATUS_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); stats->is_ht = (bool)GET_RX_STATUS_DESC_RX_HT(pdesc); stats->is_cck = SE_RX_HAL_IS_CCK_RATE(pdesc); if (stats->hwerror) return false; rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; if (stats->crc) rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; if (stats->rx_is40Mhzpacket) rx_status->flag |= RX_FLAG_40MHZ; if (stats->is_ht) rx_status->flag |= RX_FLAG_HT; rx_status->flag |= RX_FLAG_MACTIME_START; /* hw will set stats->decrypted true, if it finds the * frame is open data frame or mgmt frame, * hw will not decrypt robust management frame * for IEEE80211w but still set stats->decrypted * true, so here we should set it back to undecrypted * for IEEE80211w frame, and mac80211 sw will help * to decrypt it */ if (stats->decrypted) { hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size + stats->rx_bufshift); if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else rx_status->flag |= RX_FLAG_DECRYPTED; } rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, false, stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { p_drvinfo = (struct rx_fwinfo *)(skb->data + stats->rx_bufshift); rtl92s_translate_rx_signal_stuff(hw, skb, stats, pdesc, p_drvinfo); } /*rx_status->qual = stats->signal; */ rx_status->signal = stats->recvsignalpower + 10; return true; }
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct ath10k *ar = htt->ar; struct device *dev = ar->dev; struct sk_buff *txdesc = NULL; struct htt_cmd *cmd; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); int len = 0; int msdu_id = -1; int res; int skb_len; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; len += sizeof(cmd->hdr); len += sizeof(cmd->mgmt_tx); spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); spin_unlock_bh(&htt->tx_lock); if (res < 0) goto err; msdu_id = res; if ((ieee80211_is_action(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control)) { skb_put(msdu, IEEE80211_CCMP_MIC_LEN); } txdesc = ath10k_htc_alloc_skb(ar, len); if (!txdesc) { res = -ENOMEM; goto err_free_msdu_id; } skb_len = msdu->len; skb_cb->paddr = dma_map_single(dev, msdu->data, skb_len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); if (res) { res = -EIO; goto err_free_txdesc; } skb_put(txdesc, len); cmd = (struct htt_cmd *)txdesc->data; memset(cmd, 0, len); cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX; cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); cmd->mgmt_tx.len = __cpu_to_le32(skb_len); cmd->mgmt_tx.desc_id = __cpu_to_le32(msdu_id); cmd->mgmt_tx.vdev_id = __cpu_to_le32(vdev_id); memcpy(cmd->mgmt_tx.hdr, msdu->data, min_t(int, skb_len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) goto err_unmap_msdu; #ifdef CONFIG_ATH10K_DEBUGFS ar->debug.tx_bytes += skb_len; #endif return 0; err_unmap_msdu: dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err: return res; }
int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, struct sk_buff *msdu) { struct ath10k *ar = htt->ar; struct device *dev = ar->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); struct ath10k_hif_sg_item sg_items[2]; struct ath10k_htt_txbuf *txbuf; struct htt_data_tx_desc_frag *frags; bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET); u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth); int prefetch_len; int res; u8 flags0 = 0; u16 msdu_id, flags1 = 0; u16 freq = 0; int skb_len; u32 frags_paddr = 0; u32 txbuf_paddr; struct htt_msdu_ext_desc *ext_desc = NULL; spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); spin_unlock_bh(&htt->tx_lock); if (res < 0) goto err; msdu_id = res; prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); txbuf = &htt->txbuf.vaddr[msdu_id]; txbuf_paddr = htt->txbuf.paddr + (sizeof(struct ath10k_htt_txbuf) * msdu_id); if ((ieee80211_is_action(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control)) { skb_put(msdu, IEEE80211_CCMP_MIC_LEN); } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && txmode == ATH10K_HW_TXRX_RAW && ieee80211_has_protected(hdr->frame_control)) { skb_put(msdu, IEEE80211_CCMP_MIC_LEN); } skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); if (res) { res = -EIO; goto err_free_msdu_id; } if (unlikely(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) freq = ar->scan.roc_freq; switch (txmode) { case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; /* pass through */ case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { memset(&htt->frag_desc.vaddr[msdu_id], 0, sizeof(struct htt_msdu_ext_desc)); frags = (struct htt_data_tx_desc_frag *) &htt->frag_desc.vaddr[msdu_id].frags; ext_desc = &htt->frag_desc.vaddr[msdu_id]; frags[0].tword_addr.paddr_lo = __cpu_to_le32(skb_cb->paddr); frags[0].tword_addr.paddr_hi = 0; frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); frags_paddr = htt->frag_desc.paddr + (sizeof(struct htt_msdu_ext_desc) * msdu_id); } else { frags = txbuf->frags; frags[0].dword_addr.paddr = __cpu_to_le32(skb_cb->paddr); frags[0].dword_addr.len = __cpu_to_le32(msdu->len); frags[1].dword_addr.paddr = 0; frags[1].dword_addr.len = 0; frags_paddr = txbuf_paddr; } flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); break; case ATH10K_HW_TXRX_MGMT: flags0 |= SM(ATH10K_HW_TXRX_MGMT, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; frags_paddr = skb_cb->paddr; break; } /* Normally all commands go through HTC which manages tx credits for * each endpoint and notifies when tx is completed. * * HTT endpoint is creditless so there's no need to care about HTC * flags. In that case it is trivial to fill the HTC header here. * * MSDU transmission is considered completed upon HTT event. This * implies no relevant resources can be freed until after the event is * received. That's why HTC tx completion handler itself is ignored by * setting NULL to transfer_context for all sg items. * * There is simply no point in pushing HTT TX_FRM through HTC tx path * as it's a waste of resources. By bypassing HTC it is possible to * avoid extra memory allocations, compress data structures and thus * improve performance. */ txbuf->htc_hdr.eid = htt->eid; txbuf->htc_hdr.len = __cpu_to_le16(sizeof(txbuf->cmd_hdr) + sizeof(txbuf->cmd_tx) + prefetch_len); txbuf->htc_hdr.flags = 0; if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); if (msdu->ip_summed == CHECKSUM_PARTIAL && !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; if (ar->hw_params.continuous_frag_desc) ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; } /* Prevent firmware from sending up tx inspection requests. There's * nothing ath10k can do with frames requested for inspection so force * it to simply rely a regular tx completion with discard status. */ flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; txbuf->cmd_tx.flags0 = flags0; txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); if (ath10k_mac_tx_frm_has_freq(ar)) { txbuf->cmd_tx.offchan_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID); txbuf->cmd_tx.offchan_tx.freq = __cpu_to_le16(freq); } else { txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); } skb_len = msdu->len; trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n", flags0, flags1, skb_len, msdu_id, frags_paddr, (u32)skb_cb->paddr, vdev_id, tid, freq); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", msdu->data, skb_len); trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); trace_ath10k_tx_payload(ar, msdu->data, msdu->len); sg_items[0].transfer_id = 0; sg_items[0].transfer_context = NULL; sg_items[0].vaddr = &txbuf->htc_hdr; sg_items[0].paddr = txbuf_paddr + sizeof(txbuf->frags); sg_items[0].len = sizeof(txbuf->htc_hdr) + sizeof(txbuf->cmd_hdr) + sizeof(txbuf->cmd_tx); sg_items[1].transfer_id = 0; sg_items[1].transfer_context = NULL; sg_items[1].vaddr = msdu->data; sg_items[1].paddr = skb_cb->paddr; sg_items[1].len = prefetch_len; res = ath10k_hif_tx_sg(htt->ar, htt->ar->htc.endpoint[htt->eid].ul_pipe_id, sg_items, ARRAY_SIZE(sg_items)); if (res) goto err_unmap_msdu; #ifdef CONFIG_ATH10K_DEBUGFS ar->debug.tx_bytes += skb_len; #endif return 0; err_unmap_msdu: dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_msdu_id: ath10k_htt_tx_free_msdu_id(htt, msdu_id); err: return res; }
static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ath9k_htc_rxbuf *rxbuf, struct ieee80211_rx_status *rx_status) { struct ieee80211_hdr *hdr; struct ieee80211_hw *hw = priv->hw; struct sk_buff *skb = rxbuf->skb; struct ath_common *common = ath9k_hw_common(priv->ah); struct ath_htc_rx_status *rxstatus; int hdrlen, padpos, padsize; int last_rssi = ATH_RSSI_DUMMY_MARKER; __le16 fc; if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { ath_print(common, ATH_DBG_FATAL, "Corrupted RX frame, dropping\n"); goto rx_next; } rxstatus = (struct ath_htc_rx_status *)skb->data; if (be16_to_cpu(rxstatus->rs_datalen) - (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { ath_print(common, ATH_DBG_FATAL, "Corrupted RX data len, dropping " "(dlen: %d, skblen: %d)\n", rxstatus->rs_datalen, skb->len); goto rx_next; } /* Get the RX status information */ memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; hdrlen = ieee80211_get_hdrlen_from_skb(skb); padpos = ath9k_cmn_padpos(fc); padsize = padpos & 3; if (padsize && skb->len >= padpos+padsize+FCS_LEN) { memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); if (rxbuf->rxstatus.rs_status != 0) { if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) goto rx_next; if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { /* FIXME */ } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { if (ieee80211_is_ctl(fc)) /* * Sometimes, we get invalid * MIC failures on valid control frames. * Remove these mic errors. */ rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; else rx_status->flag |= RX_FLAG_MMIC_ERROR; } /* * Reject error frames with the exception of * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { if (rxbuf->rxstatus.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) goto rx_next; } else { if (rxbuf->rxstatus.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { goto rx_next; } } } if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { u8 keyix; keyix = rxbuf->rxstatus.rs_keyix; if (keyix != ATH9K_RXKEYIX_INVALID) { rx_status->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; if (test_bit(keyix, common->keymap)) rx_status->flag |= RX_FLAG_DECRYPTED; }
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct device *dev = htt->ar->dev; struct htt_cmd *cmd; struct htt_data_tx_desc_frag *tx_frags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ath10k_skb_cb *skb_cb; struct sk_buff *txdesc = NULL; struct sk_buff *txfrag = NULL; u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id; u8 tid; int prefetch_len, desc_len, frag_len; dma_addr_t frags_paddr; int msdu_id = -1; int res; u8 flags0; u16 flags1; res = ath10k_htt_tx_inc_pending(htt); if (res) return res; prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len; frag_len = sizeof(*tx_frags) * 2; txdesc = ath10k_htc_alloc_skb(desc_len); if (!txdesc) { res = -ENOMEM; goto err; } txfrag = dev_alloc_skb(frag_len); if (!txfrag) { res = -ENOMEM; goto err; } if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { ath10k_warn("htt alignment check failed. dropping packet.\n"); res = -EIO; goto err; } spin_lock_bh(&htt->tx_lock); msdu_id = ath10k_htt_tx_alloc_msdu_id(htt); if (msdu_id < 0) { spin_unlock_bh(&htt->tx_lock); res = msdu_id; goto err; } htt->pending_tx[msdu_id] = txdesc; spin_unlock_bh(&htt->tx_lock); res = ath10k_skb_map(dev, msdu); if (res) goto err; /* tx fragment list must be terminated with zero-entry */ skb_put(txfrag, frag_len); tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data; tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); tx_frags[0].len = __cpu_to_le32(msdu->len); tx_frags[1].paddr = __cpu_to_le32(0); tx_frags[1].len = __cpu_to_le32(0); res = ath10k_skb_map(dev, txfrag); if (res) goto err; ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx msdu 0x%llx\n", (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr, (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ", txfrag->data, frag_len); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", msdu->data, msdu->len); skb_put(txdesc, desc_len); cmd = (struct htt_cmd *)txdesc->data; memset(cmd, 0, desc_len); tid = ATH10K_SKB_CB(msdu)->htt.tid; ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid); flags0 = 0; if (!ieee80211_has_protected(hdr->frame_control)) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); flags1 = 0; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); frags_paddr = ATH10K_SKB_CB(txfrag)->paddr; cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; cmd->data_tx.flags0 = flags0; cmd->data_tx.flags1 = __cpu_to_le16(flags1); cmd->data_tx.len = __cpu_to_le16(msdu->len); cmd->data_tx.id = __cpu_to_le16(msdu_id); cmd->data_tx.frags_paddr = __cpu_to_le32(frags_paddr); cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); memcpy(cmd->data_tx.prefetch, msdu->data, prefetch_len); /* refcount is decremented by HTC and HTT completions until it reaches * zero and is freed */ skb_cb = ATH10K_SKB_CB(txdesc); skb_cb->htt.msdu_id = msdu_id; skb_cb->htt.refcount = 2; skb_cb->htt.txfrag = txfrag; skb_cb->htt.msdu = msdu; res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) goto err; return 0; err: if (txfrag) ath10k_skb_unmap(dev, txfrag); if (txdesc) dev_kfree_skb_any(txdesc); if (txfrag) dev_kfree_skb_any(txfrag); if (msdu_id >= 0) { spin_lock_bh(&htt->tx_lock); htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); } ath10k_htt_tx_dec_pending(htt); ath10k_skb_unmap(dev, msdu); return res; }
bool rtl8822be_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 *p_phystrpt = NULL; struct ieee80211_hdr *hdr; u32 phystatus = GET_RX_DESC_PHYST(pdesc); if (GET_RX_DESC_C2H(pdesc) == 0) status->packet_report_type = NORMAL_RX; else status->packet_report_type = C2H_PACKET; status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc); status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) * RX_DRV_INFO_SIZE_UNIT; status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03); status->icv = (u16)GET_RX_DESC_ICV_ERR(pdesc); status->crc = (u16)GET_RX_DESC_CRC32(pdesc); status->hwerror = (status->crc | status->icv); status->decrypted = !GET_RX_DESC_SWDEC(pdesc); status->rate = (u8)GET_RX_DESC_RX_RATE(pdesc); status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1); status->isfirst_ampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1); status->timestamp_low = GET_RX_DESC_TSFL(pdesc); status->is_ht = rtl8822be_get_rxdesc_is_ht(hw, pdesc); status->is_vht = rtl8822be_get_rxdesc_is_vht(hw, pdesc); status->vht_nss = rtl8822be_get_rx_vht_nss(hw, pdesc); status->is_cck = RX_HAL_IS_CCK_RATE(status->rate); status->macid = GET_RX_DESC_MACID(pdesc); if (GET_RX_DESC_PATTERN_MATCH(pdesc)) status->wake_match = BIT(2); else if (GET_RX_DESC_MAGIC_WAKE(pdesc)) status->wake_match = BIT(1); else if (GET_RX_DESC_UNICAST_WAKE(pdesc)) status->wake_match = BIT(0); else status->wake_match = 0; if (status->wake_match) RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n", status->wake_match); rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; if (phystatus) p_phystrpt = (skb->data + status->rx_bufshift + 24); hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size + status->rx_bufshift + 24); if (status->crc) rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; if (status->is_ht) rx_status->encoding = RX_ENC_HT; if (status->is_vht) rx_status->encoding = RX_ENC_VHT; rx_status->nss = status->vht_nss; rx_status->flag |= RX_FLAG_MACTIME_START; /* hw will set status->decrypted true, if it finds the * frame is open data frame or mgmt frame. */ /* So hw will not decryption robust management frame * for IEEE80211w but still set status->decrypted * true, so here we should set it back to undecrypted * for IEEE80211w frame, and mac80211 sw will help * to decrypt it */ if (status->decrypted) { if ((!_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag |= RX_FLAG_DECRYPTED; else rx_status->flag &= ~RX_FLAG_DECRYPTED; } /* rate_idx: index of data rate into band's * supported rates or MCS index if HT rates * are use (RX_FLAG_HT) */ /* Notice: this is diff with windows define */ rx_status->rate_idx = rtlwifi_rate_mapping( hw, status->is_ht, status->is_vht, status->rate); rx_status->mactime = status->timestamp_low; _rtl8822be_translate_rx_signal_stuff(hw, skb, status, p_phystrpt); /* below info. are filled by _rtl8822be_translate_rx_signal_stuff() */ if (!p_phystrpt) goto label_no_physt; rx_status->signal = status->recvsignalpower; if (status->rx_packet_bw == HT_CHANNEL_WIDTH_20_40) rx_status->bw = RATE_INFO_BW_40; else if (status->rx_packet_bw == HT_CHANNEL_WIDTH_80) rx_status->bw = RATE_INFO_BW_80; label_no_physt: return true; }