/* multicast and non-data only arrives on default queue */ if (!ieee80211_is_data(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1)) return 0;
/* do not check PN for open AP */ if (!(stats->flag & RX_FLAG_DECRYPTED)) return 0;
/* * avoid checking for default queue - we don't want to replicate * all the logic that's necessary for checking the PN on fragmented * frames, leave that to mac80211
*/ if (queue == 0) return 0;
/* if we are here - this for sure is either CCMP or GCMP */ if (IS_ERR_OR_NULL(sta)) {
IWL_DEBUG_DROP(mvm, "expected hw-decrypted unicast frame for station\n"); return -1;
}
if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) {
len -= 2;
pad_len = 2;
}
/* * For non monitor interface strip the bytes the RADA might not have * removed (it might be disabled, e.g. for mgmt frames). As a monitor * interface cannot exist with other interfaces, this removal is safe * and sufficient, in monitor mode there's no decryption being done.
*/ if (len > mic_crc_len && !ieee80211_hw_check(mvm->hw, RX_INCLUDES_FCS))
len -= mic_crc_len;
/* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and * an additional 8 bytes for SNAP/ethertype, see below) so that * splice() or TCP coalesce are more efficient. * * Since, in addition, ieee80211_data_to_8023() always pull in at * least 8 bytes (possibly more for mesh) we can do the same here * to save the cost of doing it later. That still doesn't pull in * the actual IP header since the typical case has a SNAP header. * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023().
*/
headlen = (len <= skb_tailroom(skb)) ? len :
hdrlen + crypt_len + 8;
/* The firmware may align the packet to DWORD. * The padding is inserted after the IV. * After copying the header + IV skip the padding if * present before copying packet data.
*/
hdrlen += crypt_len;
if (unlikely(headlen < hdrlen)) return -EINVAL;
/* Since data doesn't move data while putting data on skb and that is * the only way we use, data + len is the next place that hdr would be put
*/
skb_set_mac_header(skb, skb->len);
skb_put_data(skb, hdr, hdrlen);
skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen);
/* * If we did CHECKSUM_COMPLETE, the hardware only does it right for * certain cases and starts the checksum after the SNAP. Check if * this is the case - it's easier to just bail out to CHECKSUM_NONE * in the cases the hardware didn't handle, since it's rare to see * such packets, even though the hardware did calculate the checksum * in this case, just starting after the MAC header instead. * * Starting from Bz hardware, it calculates starting directly after * the MAC header, so that matches mac80211's expectation.
*/ if (skb->ip_summed == CHECKSUM_COMPLETE) { struct {
u8 hdr[6];
__be16 type;
} __packed *shdr = (void *)((u8 *)hdr + hdrlen + pad_len);
/* put a TLV on the skb and return data pointer * * Also pad to 4 the len and zero out all data part
*/ staticvoid *
iwl_mvm_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len)
{ struct ieee80211_radiotap_tlv *tlv;
if (likely(!ieee80211_is_beacon(hdr->frame_control))) returnfalse;
/* for the link conf lookup */
guard(rcu)();
/* MAC or link ID depending on FW, but driver has them equal */
id = u8_get_bits(desc->mac_phy_band,
IWL_RX_MPDU_MAC_PHY_BAND_MAC_MASK);
/* >= means AUX MAC/link ID, no energy correction needed then */ if (id >= ARRAY_SIZE(mvm->vif_id_to_mac)) returnfalse;
vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); if (!vif) returnfalse;
mvm_vif = iwl_mvm_vif_from_mac80211(vif);
/* * If we know the MAC by MAC or link ID then the frame was * received for the link, so by filtering it means it was * from the AP the link is connected to.
*/
/* skip also in case we don't have it (yet) */ if (!mvm_vif->deflink.average_beacon_energy) returnfalse;
IWL_DEBUG_STATS(mvm, "energy override by average %d\n",
mvm_vif->deflink.average_beacon_energy);
rx_status->signal = -mvm_vif->deflink.average_beacon_energy; returntrue;
}
staticvoid iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, struct iwl_rx_mpdu_desc *desc, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rx_status,
u32 rate_n_flags, int energy_a, int energy_b)
{ int max_energy;
if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) return 0;
/* * For non-beacon, we don't really care. But beacons may * be filtered out, and we thus need the firmware's replay * detection, otherwise beacons the firmware previously * filtered could be replayed, or something like that, and * it can filter a lot - though usually only if nothing has * changed.
*/ if (!ieee80211_is_beacon(hdr->frame_control)) return 0;
/* key mismatch - will also report !MIC_OK but we shouldn't count it */ if (!(status & IWL_RX_MPDU_STATUS_KEY_VALID)) goto report;
/* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK &&
!(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) {
stats->flag |= RX_FLAG_DECRYPTED; return 0;
}
/* * both keys will have the same cipher and MIC length, use * whichever one is available
*/
key = rcu_dereference(mvmvif->bcn_prot.keys[0]); if (!key) {
key = rcu_dereference(mvmvif->bcn_prot.keys[1]); if (!key) goto report;
}
if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) goto report;
/* get the real key ID */
keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; /* and if that's the other key, look it up */ if (keyid != key->keyidx) { /* * shouldn't happen since firmware checked, but be safe * in case the MIC length is wrong too, for example
*/ if (keyid != 6 && keyid != 7) return -1;
key = rcu_dereference(mvmvif->bcn_prot.keys[keyid - 6]); if (!key) goto report;
}
/* Report status to mac80211 */ if (!(status & IWL_RX_MPDU_STATUS_MIC_OK))
ieee80211_key_mic_failure(key); elseif (status & IWL_RX_MPDU_STATUS_REPLAY_ERROR)
ieee80211_key_replay(key);
report:
wdev = ieee80211_vif_to_wdev(mvmsta->vif); if (wdev->netdev)
cfg80211_rx_unprot_mlme_mgmt(wdev->netdev, (void *)hdr, len);
/* * Drop UNKNOWN frames in aggregation, unless in monitor mode * (where we don't have the keys). * We limit this to aggregation because in TKIP this is a valid * scenario, since we may not have the (correct) TTAK (phase 1 * key) in the firmware.
*/ if (phy_info & IWL_RX_MPDU_PHY_AMPDU &&
(status & IWL_RX_MPDU_STATUS_SEC_MASK) ==
IWL_RX_MPDU_STATUS_SEC_UNKNOWN && !mvm->monitor_on) {
IWL_DEBUG_DROP(mvm, "Dropping packets, bad enc status\n"); return -1;
}
if (unlikely(ieee80211_is_mgmt(hdr->frame_control) &&
!ieee80211_has_protected(hdr->frame_control))) return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status, stats);
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)) {
IWL_DEBUG_DROP(mvm, "Dropping packet, bad MIC (CCM/GCM)\n"); return -1;
}
stats->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED;
*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 (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_DEPRECATE_TTAK) &&
!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK)) return 0;
if (mvm->trans->mac_cfg->gen2 &&
!(status & RX_MPDU_RES_STATUS_MIC_OK))
stats->flag |= RX_FLAG_MMIC_ERROR;
*crypt_len = IEEE80211_TKIP_IV_LEN;
fallthrough; case IWL_RX_MPDU_STATUS_SEC_WEP: if (!(status & IWL_RX_MPDU_STATUS_ICV_OK)) return -1;
if (pkt_flags & FH_RSCSR_RADA_EN) {
stats->flag |= RX_FLAG_ICV_STRIPPED; if (mvm->trans->mac_cfg->gen2)
stats->flag |= RX_FLAG_MMIC_STRIPPED;
}
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; case RX_MPDU_RES_STATUS_SEC_CMAC_GMAC_ENC: break; default: /* * Sometimes we can get frames that were not decrypted * because the firmware didn't have the keys yet. This can * happen after connection where we can get multicast frames * before the GTK is installed. * Silently drop those frames. * Also drop un-decrypted frames in monitor mode.
*/ if (!is_multicast_ether_addr(hdr->addr1) &&
!mvm->monitor_on && net_ratelimit())
IWL_WARN(mvm, "Unhandled alg: 0x%x\n", status);
}
/* * returns true if a packet is a duplicate or invalid tid and should be dropped. * Updates AMSDU PN tracking info
*/ staticbool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, struct ieee80211_rx_status *rx_status, struct ieee80211_hdr *hdr, struct iwl_rx_mpdu_desc *desc)
{ struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_rxq_dup_data *dup_data;
u8 tid, sub_frame_idx;
if (WARN_ON(IS_ERR_OR_NULL(sta))) returnfalse;
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
if (WARN_ON_ONCE(!mvm_sta->dup_data)) returnfalse;
dup_data = &mvm_sta->dup_data[queue];
/* * Drop duplicate 802.11 retransmissions * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
*/ if (ieee80211_is_ctl(hdr->frame_control) ||
ieee80211_is_any_nullfunc(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1)) returnfalse;
if (ieee80211_is_data_qos(hdr->frame_control)) { /* frame has qos control */
tid = ieee80211_get_tid(hdr); if (tid >= IWL_MAX_TID_COUNT) returntrue;
} else {
tid = IWL_MAX_TID_COUNT;
}
/* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */
sub_frame_idx = desc->amsdu_info &
IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
/* Allow same PN as the first subframe for following sub frames */ if (dup_data->last_seq[tid] == hdr->seq_ctrl &&
sub_frame_idx > dup_data->last_sub_frame[tid] &&
desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU)
rx_status->flag |= RX_FLAG_ALLOW_SAME_PN;
while (ieee80211_sn_less(ssn, nssn)) { int index = ssn % baid_data->buf_size; struct sk_buff_head *skb_list = &entries[index].frames; struct sk_buff *skb;
ssn = ieee80211_sn_inc(ssn);
/* * Empty the list. Will have more than one frame for A-MSDU. * Empty list is valid as well since nssn indicates frames were * received.
*/ while ((skb = __skb_dequeue(skb_list))) {
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
reorder_buf->queue,
sta);
reorder_buf->num_stored--;
}
}
reorder_buf->head_sn = nssn;
}
if (WARN_ONCE(baid >= IWL_MAX_BAID, "invalid BAID: %x\n", baid)) return;
rcu_read_lock();
ba_data = rcu_dereference(mvm->baid_map[baid]); if (WARN_ON_ONCE(!ba_data)) goto out;
/* pick any STA ID to find the pointer */
sta_id = ffs(ba_data->sta_mask) - 1;
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) goto out;
reorder_buf = &ba_data->reorder_buf[queue];
/* release all frames that are in the reorder buffer to the stack */
spin_lock_bh(&reorder_buf->lock);
iwl_mvm_release_frames(mvm, sta, NULL, ba_data, reorder_buf,
ieee80211_sn_add(reorder_buf->head_sn,
ba_data->buf_size));
spin_unlock_bh(&reorder_buf->lock);
if (IWL_FW_CHECK(mvm,
baid == IWL_RX_REORDER_DATA_INVALID_BAID ||
baid >= ARRAY_SIZE(mvm->baid_map), "invalid BAID from FW: %d\n", baid)) return;
rcu_read_lock();
ba_data = rcu_dereference(mvm->baid_map[baid]); if (!ba_data) {
IWL_DEBUG_RX(mvm, "Got valid BAID %d but not allocated, invalid frame release!\n",
baid); goto out;
}
/* pick any STA ID to find the pointer */
sta_id = ffs(ba_data->sta_mask) - 1;
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) goto out;
if (mvm->trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_9000) returnfalse;
/* * This also covers the case of receiving a Block Ack Request * outside a BA session; we'll pass it to mac80211 and that * then sends a delBA action frame. * This also covers pure monitor mode, in which case we won't * have any BA sessions.
*/ if (baid == IWL_RX_REORDER_DATA_INVALID_BAID) returnfalse;
/* no sta yet */ if (WARN_ONCE(IS_ERR_OR_NULL(sta), "Got valid BAID without a valid station assigned\n")) returnfalse;
/* not a data packet or a bar */ if (!ieee80211_is_back_req(hdr->frame_control) &&
(!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))) returnfalse;
if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) returnfalse;
baid_data = rcu_dereference(mvm->baid_map[baid]); if (!baid_data) {
IWL_DEBUG_RX(mvm, "Got valid BAID but no baid allocated, bypass the re-ordering buffer. Baid %d reorder 0x%x\n",
baid, reorder); returnfalse;
}
sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1);
if (IWL_FW_CHECK(mvm,
tid != baid_data->tid ||
!(sta_mask & baid_data->sta_mask), "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n",
baid, baid_data->sta_mask, baid_data->tid,
sta_mask, tid)) returnfalse;
if (!buffer->valid) { if (reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN) {
spin_unlock_bh(&buffer->lock); returnfalse;
}
buffer->valid = true;
}
/* drop any duplicated packets */ if (desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_DUPLICATE)) goto drop;
/* drop any oudated packets */ if (reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN) goto drop;
/* release immediately if allowed by nssn and no stored frames */ if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (!amsdu || last_subframe)
buffer->head_sn = nssn;
spin_unlock_bh(&buffer->lock); returnfalse;
}
/* * release immediately if there are no stored frames, and the sn is * equal to the head. * This can happen due to reorder timer, where NSSN is behind head_sn. * When we released everything, and we got the next frame in the * sequence, according to the NSSN we can't release immediately, * while technically there is no hole and we can move forward.
*/ if (!buffer->num_stored && sn == buffer->head_sn) { if (!amsdu || last_subframe)
buffer->head_sn = ieee80211_sn_inc(buffer->head_sn);
spin_unlock_bh(&buffer->lock); returnfalse;
}
/* put in reorder buffer */
index = sn % baid_data->buf_size;
__skb_queue_tail(&entries[index].frames, skb);
buffer->num_stored++;
/* * We cannot trust NSSN for AMSDU sub-frames that are not the last. * The reason is that NSSN advances on the first sub-frame, and may * cause the reorder buffer to advance before all the sub-frames arrive. * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with * SN 1. NSSN for first sub frame will be 3 with the result of driver * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. * If this is the first frame that is stored in the buffer, the head_sn * may be outdated. Update it based on the last NSSN to make sure it * will be released when the frame release notification arrives.
*/ if (!amsdu || last_subframe)
iwl_mvm_release_frames(mvm, sta, napi, baid_data,
buffer, nssn); elseif (buffer->num_stored == 1)
buffer->head_sn = nssn;
data = rcu_dereference(mvm->baid_map[baid]); if (!data) {
IWL_DEBUG_RX(mvm, "Got valid BAID but no baid allocated, bypass the re-ordering buffer. Baid %d reorder 0x%x\n",
baid, reorder_data); goto out;
}
if (!data->timeout) goto out;
timeout = data->timeout; /* * Do not update last rx all the time to avoid cache bouncing * between the rx queues. * Update it every timeout. Worst case is the session will * expire after ~ 2 * timeout, which doesn't matter that much.
*/ if (time_before(data->last_rx + TU_TO_JIFFIES(timeout), now)) /* Update is atomic */
data->last_rx = now;
out:
rcu_read_unlock();
}
staticvoid iwl_mvm_flip_address(u8 *addr)
{ int i;
u8 mac_addr[ETH_ALEN];
for (i = 0; i < ETH_ALEN; i++)
mac_addr[i] = addr[ETH_ALEN - i - 1];
ether_addr_copy(addr, mac_addr);
}
staticvoid
iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data, struct ieee80211_radiotap_he *he, struct ieee80211_radiotap_he_mu *he_mu, struct ieee80211_rx_status *rx_status)
{ /* * Unfortunately, we have to leave the mac80211 data * incorrect for the case that we receive an HE-MU * transmission and *don't* have the HE phy data (due * to the bits being used for TSF). This shouldn't * happen though as management frames where we need * the TSF/timers are not be transmitted in HE-MU.
*/
u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK);
u32 rate_n_flags = phy_data->rate_n_flags;
u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
u8 offs = 0;
/* All RU allocating size/index is in TB format */
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT);
eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160);
eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0);
eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1);
iwl_mvm_decode_eht_ru(mvm, rx_status, eht);
/* We only get here in case of IWL_RX_MPDU_PHY_TSF_OVERLOAD is set * which is on only in case of monitor mode so no need to check monitor * mode
*/
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_PRIMARY_80);
eht->data[1] |=
le32_encode_bits(mvm->monitor_p80,
IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80);
/* report the AMPDU-EOF bit on single frames */ if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
/* update aggregation data for monitor sake on default queue */ if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) &&
(phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) {
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
iwl_mvm_decode_eht_phy_data(mvm, phy_data, rx_status, eht, usig);
#define CHECK_TYPE(F) \
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \
(RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
/* report the AMPDU-EOF bit on single frames */ if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
iwl_mvm_decode_he_phy_data(mvm, phy_data, he, he_mu, rx_status,
queue);
/* update aggregation data for monitor sake on default queue */ if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) &&
(phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) {
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
/* actually data is filled in mac80211 */ if (he_type == RATE_MCS_HE_TYPE_SU ||
he_type == RATE_MCS_HE_TYPE_EXT_SU)
he->data1 |=
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
#define CHECK_TYPE(F) \
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \
(RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
switch (phy_data->info_type) { case IWL_RX_PHY_INFO_TYPE_HT: case IWL_RX_PHY_INFO_TYPE_VHT_SU: case IWL_RX_PHY_INFO_TYPE_VHT_MU: case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: case IWL_RX_PHY_INFO_TYPE_HE_SU: case IWL_RX_PHY_INFO_TYPE_HE_MU: case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: case IWL_RX_PHY_INFO_TYPE_HE_TB: case IWL_RX_PHY_INFO_TYPE_EHT_MU: case IWL_RX_PHY_INFO_TYPE_EHT_TB: case IWL_RX_PHY_INFO_TYPE_EHT_MU_EXT: case IWL_RX_PHY_INFO_TYPE_EHT_TB_EXT:
lsig = skb_put(skb, sizeof(*lsig));
lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN);
lsig->data2 = le16_encode_bits(le32_get_bits(phy_data->d1,
IWL_RX_PHY_DATA1_LSIG_LEN_MASK),
IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH);
rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; break; default: break;
}
}
if (mvmsta->disable_tx)
rx_sta_csa->all_sta_unblocked = false;
}
/* * Note: requires also rx_status->band to be prefilled, as well * as phy_data (apart from phy_data->info_type) * Note: desc/hdr may be NULL
*/ staticvoid iwl_mvm_rx_fill_status(struct iwl_mvm *mvm, struct iwl_rx_mpdu_desc *desc, struct ieee80211_hdr *hdr, struct sk_buff *skb, struct iwl_mvm_rx_phy_data *phy_data, int queue)
{ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
u32 rate_n_flags = phy_data->rate_n_flags;
u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK);
u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; bool is_sgi;
phy_data->info_type = IWL_RX_PHY_INFO_TYPE_NONE;
if (phy_data->phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
phy_data->info_type =
le32_get_bits(phy_data->d1,
IWL_RX_PHY_DATA1_INFO_TYPE_MASK);
/* This may be overridden by iwl_mvm_rx_he() to HE_RU */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; case RATE_MCS_CHAN_WIDTH_40:
rx_status->bw = RATE_INFO_BW_40; break; case RATE_MCS_CHAN_WIDTH_80:
rx_status->bw = RATE_INFO_BW_80; break; case RATE_MCS_CHAN_WIDTH_160:
rx_status->bw = RATE_INFO_BW_160; break; case RATE_MCS_CHAN_WIDTH_320:
rx_status->bw = RATE_INFO_BW_320; break;
}
/* must be before L-SIG data */ if (format == RATE_MCS_MOD_TYPE_HE)
iwl_mvm_rx_he(mvm, skb, phy_data, queue);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.