162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc. 462306a36Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc. 562306a36Sopenharmony_ci * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 662306a36Sopenharmony_ci * Copyright 2008-2010 Johannes Berg <johannes@sipsolutions.net> 762306a36Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 862306a36Sopenharmony_ci * Copyright 2021-2023 Intel Corporation 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/export.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <net/mac80211.h> 1462306a36Sopenharmony_ci#include <asm/unaligned.h> 1562306a36Sopenharmony_ci#include "ieee80211_i.h" 1662306a36Sopenharmony_ci#include "rate.h" 1762306a36Sopenharmony_ci#include "mesh.h" 1862306a36Sopenharmony_ci#include "led.h" 1962306a36Sopenharmony_ci#include "wme.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, 2362306a36Sopenharmony_ci struct sk_buff *skb) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 2662306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 2762306a36Sopenharmony_ci int tmp; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci skb->pkt_type = IEEE80211_TX_STATUS_MSG; 3062306a36Sopenharmony_ci skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? 3162306a36Sopenharmony_ci &local->skb_queue : &local->skb_queue_unreliable, skb); 3262306a36Sopenharmony_ci tmp = skb_queue_len(&local->skb_queue) + 3362306a36Sopenharmony_ci skb_queue_len(&local->skb_queue_unreliable); 3462306a36Sopenharmony_ci while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && 3562306a36Sopenharmony_ci (skb = skb_dequeue(&local->skb_queue_unreliable))) { 3662306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 3762306a36Sopenharmony_ci tmp--; 3862306a36Sopenharmony_ci I802_DEBUG_INC(local->tx_status_drop); 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci tasklet_schedule(&local->tasklet); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_tx_status_irqsafe); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void ieee80211_handle_filtered_frame(struct ieee80211_local *local, 4562306a36Sopenharmony_ci struct sta_info *sta, 4662306a36Sopenharmony_ci struct sk_buff *skb) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 4962306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 5062306a36Sopenharmony_ci int ac; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER | 5362306a36Sopenharmony_ci IEEE80211_TX_CTL_AMPDU | 5462306a36Sopenharmony_ci IEEE80211_TX_CTL_HW_80211_ENCAP)) { 5562306a36Sopenharmony_ci ieee80211_free_txskb(&local->hw, skb); 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* 6062306a36Sopenharmony_ci * This skb 'survived' a round-trip through the driver, and 6162306a36Sopenharmony_ci * hopefully the driver didn't mangle it too badly. However, 6262306a36Sopenharmony_ci * we can definitely not rely on the control information 6362306a36Sopenharmony_ci * being correct. Clear it so we don't get junk there, and 6462306a36Sopenharmony_ci * indicate that it needs new processing, but must not be 6562306a36Sopenharmony_ci * modified/encrypted again. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci memset(&info->control, 0, sizeof(info->control)); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci info->control.jiffies = jiffies; 7062306a36Sopenharmony_ci info->control.vif = &sta->sdata->vif; 7162306a36Sopenharmony_ci info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; 7262306a36Sopenharmony_ci info->flags |= IEEE80211_TX_INTFL_RETRANSMISSION; 7362306a36Sopenharmony_ci info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci sta->deflink.status_stats.filtered++; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * Clear more-data bit on filtered frames, it might be set 7962306a36Sopenharmony_ci * but later frames might time out so it might have to be 8062306a36Sopenharmony_ci * clear again ... It's all rather unlikely (this frame 8162306a36Sopenharmony_ci * should time out first, right?) but let's not confuse 8262306a36Sopenharmony_ci * peers unnecessarily. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) 8562306a36Sopenharmony_ci hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) { 8862306a36Sopenharmony_ci u8 *p = ieee80211_get_qos_ctl(hdr); 8962306a36Sopenharmony_ci int tid = *p & IEEE80211_QOS_CTL_TID_MASK; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * Clear EOSP if set, this could happen e.g. 9362306a36Sopenharmony_ci * if an absence period (us being a P2P GO) 9462306a36Sopenharmony_ci * shortens the SP. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci if (*p & IEEE80211_QOS_CTL_EOSP) 9762306a36Sopenharmony_ci *p &= ~IEEE80211_QOS_CTL_EOSP; 9862306a36Sopenharmony_ci ac = ieee80211_ac_from_tid(tid); 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci ac = IEEE80211_AC_BE; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* 10462306a36Sopenharmony_ci * Clear the TX filter mask for this STA when sending the next 10562306a36Sopenharmony_ci * packet. If the STA went to power save mode, this will happen 10662306a36Sopenharmony_ci * when it wakes up for the next time. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT); 10962306a36Sopenharmony_ci ieee80211_clear_fast_xmit(sta); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* 11262306a36Sopenharmony_ci * This code races in the following way: 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * (1) STA sends frame indicating it will go to sleep and does so 11562306a36Sopenharmony_ci * (2) hardware/firmware adds STA to filter list, passes frame up 11662306a36Sopenharmony_ci * (3) hardware/firmware processes TX fifo and suppresses a frame 11762306a36Sopenharmony_ci * (4) we get TX status before having processed the frame and 11862306a36Sopenharmony_ci * knowing that the STA has gone to sleep. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * This is actually quite unlikely even when both those events are 12162306a36Sopenharmony_ci * processed from interrupts coming in quickly after one another or 12262306a36Sopenharmony_ci * even at the same time because we queue both TX status events and 12362306a36Sopenharmony_ci * RX frames to be processed by a tasklet and process them in the 12462306a36Sopenharmony_ci * same order that they were received or TX status last. Hence, there 12562306a36Sopenharmony_ci * is no race as long as the frame RX is processed before the next TX 12662306a36Sopenharmony_ci * status, which drivers can ensure, see below. 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * Note that this can only happen if the hardware or firmware can 12962306a36Sopenharmony_ci * actually add STAs to the filter list, if this is done by the 13062306a36Sopenharmony_ci * driver in response to set_tim() (which will only reduce the race 13162306a36Sopenharmony_ci * this whole filtering tries to solve, not completely solve it) 13262306a36Sopenharmony_ci * this situation cannot happen. 13362306a36Sopenharmony_ci * 13462306a36Sopenharmony_ci * To completely solve this race drivers need to make sure that they 13562306a36Sopenharmony_ci * (a) don't mix the irq-safe/not irq-safe TX status/RX processing 13662306a36Sopenharmony_ci * functions and 13762306a36Sopenharmony_ci * (b) always process RX events before TX status events if ordering 13862306a36Sopenharmony_ci * can be unknown, for example with different interrupt status 13962306a36Sopenharmony_ci * bits. 14062306a36Sopenharmony_ci * (c) if PS mode transitions are manual (i.e. the flag 14162306a36Sopenharmony_ci * %IEEE80211_HW_AP_LINK_PS is set), always process PS state 14262306a36Sopenharmony_ci * changes before calling TX status events if ordering can be 14362306a36Sopenharmony_ci * unknown. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci if (test_sta_flag(sta, WLAN_STA_PS_STA) && 14662306a36Sopenharmony_ci skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) { 14762306a36Sopenharmony_ci skb_queue_tail(&sta->tx_filtered[ac], skb); 14862306a36Sopenharmony_ci sta_info_recalc_tim(sta); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (!timer_pending(&local->sta_cleanup)) 15162306a36Sopenharmony_ci mod_timer(&local->sta_cleanup, 15262306a36Sopenharmony_ci round_jiffies(jiffies + 15362306a36Sopenharmony_ci STA_INFO_CLEANUP_INTERVAL)); 15462306a36Sopenharmony_ci return; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_PS_STA) && 15862306a36Sopenharmony_ci !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { 15962306a36Sopenharmony_ci /* Software retry the packet once */ 16062306a36Sopenharmony_ci info->flags |= IEEE80211_TX_INTFL_RETRIED; 16162306a36Sopenharmony_ci ieee80211_add_pending_skb(local, skb); 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ps_dbg_ratelimited(sta->sdata, 16662306a36Sopenharmony_ci "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", 16762306a36Sopenharmony_ci skb_queue_len(&sta->tx_filtered[ac]), 16862306a36Sopenharmony_ci !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); 16962306a36Sopenharmony_ci ieee80211_free_txskb(&local->hw, skb); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct tid_ampdu_tx *tid_tx; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); 17762306a36Sopenharmony_ci if (!tid_tx || !tid_tx->bar_pending) 17862306a36Sopenharmony_ci return; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci tid_tx->bar_pending = false; 18162306a36Sopenharmony_ci ieee80211_send_bar(&sta->sdata->vif, addr, tid, tid_tx->failed_bar_ssn); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt = (void *) skb->data; 18762306a36Sopenharmony_ci struct ieee80211_local *local = sta->local; 18862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (ieee80211_is_data_qos(mgmt->frame_control)) { 19162306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *) skb->data; 19262306a36Sopenharmony_ci u8 *qc = ieee80211_get_qos_ctl(hdr); 19362306a36Sopenharmony_ci u16 tid = qc[0] & 0xf; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ieee80211_check_pending_bar(sta, hdr->addr1, tid); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (ieee80211_is_action(mgmt->frame_control) && 19962306a36Sopenharmony_ci !ieee80211_has_protected(mgmt->frame_control) && 20062306a36Sopenharmony_ci mgmt->u.action.category == WLAN_CATEGORY_HT && 20162306a36Sopenharmony_ci mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS && 20262306a36Sopenharmony_ci ieee80211_sdata_running(sdata)) { 20362306a36Sopenharmony_ci enum ieee80211_smps_mode smps_mode; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci switch (mgmt->u.action.u.ht_smps.smps_control) { 20662306a36Sopenharmony_ci case WLAN_HT_SMPS_CONTROL_DYNAMIC: 20762306a36Sopenharmony_ci smps_mode = IEEE80211_SMPS_DYNAMIC; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case WLAN_HT_SMPS_CONTROL_STATIC: 21062306a36Sopenharmony_ci smps_mode = IEEE80211_SMPS_STATIC; 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci case WLAN_HT_SMPS_CONTROL_DISABLED: 21362306a36Sopenharmony_ci default: /* shouldn't happen since we don't send that */ 21462306a36Sopenharmony_ci smps_mode = IEEE80211_SMPS_OFF; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) { 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * This update looks racy, but isn't -- if we come 22162306a36Sopenharmony_ci * here we've definitely got a station that we're 22262306a36Sopenharmony_ci * talking to, and on a managed interface that can 22362306a36Sopenharmony_ci * only be the AP. And the only other place updating 22462306a36Sopenharmony_ci * this variable in managed mode is before association. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci sdata->deflink.smps_mode = smps_mode; 22762306a36Sopenharmony_ci ieee80211_queue_work(&local->hw, &sdata->recalc_smps); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct tid_ampdu_tx *tid_tx; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); 23762306a36Sopenharmony_ci if (!tid_tx) 23862306a36Sopenharmony_ci return; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci tid_tx->failed_bar_ssn = ssn; 24162306a36Sopenharmony_ci tid_tx->bar_pending = true; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info, 24562306a36Sopenharmony_ci struct ieee80211_tx_status *status) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct ieee80211_rate_status *status_rate = NULL; 24862306a36Sopenharmony_ci int len = sizeof(struct ieee80211_radiotap_header); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (status && status->n_rates) 25162306a36Sopenharmony_ci status_rate = &status->rates[status->n_rates - 1]; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_RATE rate */ 25462306a36Sopenharmony_ci if (status_rate && !(status_rate->rate_idx.flags & 25562306a36Sopenharmony_ci (RATE_INFO_FLAGS_MCS | 25662306a36Sopenharmony_ci RATE_INFO_FLAGS_DMG | 25762306a36Sopenharmony_ci RATE_INFO_FLAGS_EDMG | 25862306a36Sopenharmony_ci RATE_INFO_FLAGS_VHT_MCS | 25962306a36Sopenharmony_ci RATE_INFO_FLAGS_HE_MCS))) 26062306a36Sopenharmony_ci len += 2; 26162306a36Sopenharmony_ci else if (info->status.rates[0].idx >= 0 && 26262306a36Sopenharmony_ci !(info->status.rates[0].flags & 26362306a36Sopenharmony_ci (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) 26462306a36Sopenharmony_ci len += 2; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_TX_FLAGS */ 26762306a36Sopenharmony_ci len += 2; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_DATA_RETRIES */ 27062306a36Sopenharmony_ci len += 1; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_MCS 27362306a36Sopenharmony_ci * IEEE80211_RADIOTAP_VHT */ 27462306a36Sopenharmony_ci if (status_rate) { 27562306a36Sopenharmony_ci if (status_rate->rate_idx.flags & RATE_INFO_FLAGS_MCS) 27662306a36Sopenharmony_ci len += 3; 27762306a36Sopenharmony_ci else if (status_rate->rate_idx.flags & RATE_INFO_FLAGS_VHT_MCS) 27862306a36Sopenharmony_ci len = ALIGN(len, 2) + 12; 27962306a36Sopenharmony_ci else if (status_rate->rate_idx.flags & RATE_INFO_FLAGS_HE_MCS) 28062306a36Sopenharmony_ci len = ALIGN(len, 2) + 12; 28162306a36Sopenharmony_ci } else if (info->status.rates[0].idx >= 0) { 28262306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) 28362306a36Sopenharmony_ci len += 3; 28462306a36Sopenharmony_ci else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) 28562306a36Sopenharmony_ci len = ALIGN(len, 2) + 12; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return len; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void 29262306a36Sopenharmony_ciieee80211_add_tx_radiotap_header(struct ieee80211_local *local, 29362306a36Sopenharmony_ci struct sk_buff *skb, int retry_count, 29462306a36Sopenharmony_ci int rtap_len, int shift, 29562306a36Sopenharmony_ci struct ieee80211_tx_status *status) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 29862306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 29962306a36Sopenharmony_ci struct ieee80211_radiotap_header *rthdr; 30062306a36Sopenharmony_ci struct ieee80211_rate_status *status_rate = NULL; 30162306a36Sopenharmony_ci unsigned char *pos; 30262306a36Sopenharmony_ci u16 legacy_rate = 0; 30362306a36Sopenharmony_ci u16 txflags; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (status && status->n_rates) 30662306a36Sopenharmony_ci status_rate = &status->rates[status->n_rates - 1]; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci rthdr = skb_push(skb, rtap_len); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci memset(rthdr, 0, rtap_len); 31162306a36Sopenharmony_ci rthdr->it_len = cpu_to_le16(rtap_len); 31262306a36Sopenharmony_ci rthdr->it_present = 31362306a36Sopenharmony_ci cpu_to_le32(BIT(IEEE80211_RADIOTAP_TX_FLAGS) | 31462306a36Sopenharmony_ci BIT(IEEE80211_RADIOTAP_DATA_RETRIES)); 31562306a36Sopenharmony_ci pos = (unsigned char *)(rthdr + 1); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * XXX: Once radiotap gets the bitmap reset thing the vendor 31962306a36Sopenharmony_ci * extensions proposal contains, we can actually report 32062306a36Sopenharmony_ci * the whole set of tries we did. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_RATE */ 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (status_rate) { 32662306a36Sopenharmony_ci if (!(status_rate->rate_idx.flags & 32762306a36Sopenharmony_ci (RATE_INFO_FLAGS_MCS | 32862306a36Sopenharmony_ci RATE_INFO_FLAGS_DMG | 32962306a36Sopenharmony_ci RATE_INFO_FLAGS_EDMG | 33062306a36Sopenharmony_ci RATE_INFO_FLAGS_VHT_MCS | 33162306a36Sopenharmony_ci RATE_INFO_FLAGS_HE_MCS))) 33262306a36Sopenharmony_ci legacy_rate = status_rate->rate_idx.legacy; 33362306a36Sopenharmony_ci } else if (info->status.rates[0].idx >= 0 && 33462306a36Sopenharmony_ci !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS | 33562306a36Sopenharmony_ci IEEE80211_TX_RC_VHT_MCS))) { 33662306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci sband = local->hw.wiphy->bands[info->band]; 33962306a36Sopenharmony_ci legacy_rate = 34062306a36Sopenharmony_ci sband->bitrates[info->status.rates[0].idx].bitrate; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (legacy_rate) { 34462306a36Sopenharmony_ci rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_RATE)); 34562306a36Sopenharmony_ci *pos = DIV_ROUND_UP(legacy_rate, 5 * (1 << shift)); 34662306a36Sopenharmony_ci /* padding for tx flags */ 34762306a36Sopenharmony_ci pos += 2; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_TX_FLAGS */ 35162306a36Sopenharmony_ci txflags = 0; 35262306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_STAT_ACK) && 35362306a36Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1)) 35462306a36Sopenharmony_ci txflags |= IEEE80211_RADIOTAP_F_TX_FAIL; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 35762306a36Sopenharmony_ci txflags |= IEEE80211_RADIOTAP_F_TX_CTS; 35862306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) 35962306a36Sopenharmony_ci txflags |= IEEE80211_RADIOTAP_F_TX_RTS; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci put_unaligned_le16(txflags, pos); 36262306a36Sopenharmony_ci pos += 2; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_DATA_RETRIES */ 36562306a36Sopenharmony_ci /* for now report the total retry_count */ 36662306a36Sopenharmony_ci *pos = retry_count; 36762306a36Sopenharmony_ci pos++; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (status_rate && (status_rate->rate_idx.flags & RATE_INFO_FLAGS_MCS)) 37062306a36Sopenharmony_ci { 37162306a36Sopenharmony_ci rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_MCS)); 37262306a36Sopenharmony_ci pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS | 37362306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_GI | 37462306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_BW; 37562306a36Sopenharmony_ci if (status_rate->rate_idx.flags & RATE_INFO_FLAGS_SHORT_GI) 37662306a36Sopenharmony_ci pos[1] |= IEEE80211_RADIOTAP_MCS_SGI; 37762306a36Sopenharmony_ci if (status_rate->rate_idx.bw == RATE_INFO_BW_40) 37862306a36Sopenharmony_ci pos[1] |= IEEE80211_RADIOTAP_MCS_BW_40; 37962306a36Sopenharmony_ci pos[2] = status_rate->rate_idx.mcs; 38062306a36Sopenharmony_ci pos += 3; 38162306a36Sopenharmony_ci } else if (status_rate && (status_rate->rate_idx.flags & 38262306a36Sopenharmony_ci RATE_INFO_FLAGS_VHT_MCS)) 38362306a36Sopenharmony_ci { 38462306a36Sopenharmony_ci u16 known = local->hw.radiotap_vht_details & 38562306a36Sopenharmony_ci (IEEE80211_RADIOTAP_VHT_KNOWN_GI | 38662306a36Sopenharmony_ci IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT)); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* required alignment from rthdr */ 39162306a36Sopenharmony_ci pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */ 39462306a36Sopenharmony_ci put_unaligned_le16(known, pos); 39562306a36Sopenharmony_ci pos += 2; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */ 39862306a36Sopenharmony_ci if (status_rate->rate_idx.flags & RATE_INFO_FLAGS_SHORT_GI) 39962306a36Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; 40062306a36Sopenharmony_ci pos++; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* u8 bandwidth */ 40362306a36Sopenharmony_ci switch (status_rate->rate_idx.bw) { 40462306a36Sopenharmony_ci case RATE_INFO_BW_160: 40562306a36Sopenharmony_ci *pos = 11; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci case RATE_INFO_BW_80: 40862306a36Sopenharmony_ci *pos = 4; 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case RATE_INFO_BW_40: 41162306a36Sopenharmony_ci *pos = 1; 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci default: 41462306a36Sopenharmony_ci *pos = 0; 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci pos++; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* u8 mcs_nss[4] */ 42062306a36Sopenharmony_ci *pos = (status_rate->rate_idx.mcs << 4) | 42162306a36Sopenharmony_ci status_rate->rate_idx.nss; 42262306a36Sopenharmony_ci pos += 4; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* u8 coding */ 42562306a36Sopenharmony_ci pos++; 42662306a36Sopenharmony_ci /* u8 group_id */ 42762306a36Sopenharmony_ci pos++; 42862306a36Sopenharmony_ci /* u16 partial_aid */ 42962306a36Sopenharmony_ci pos += 2; 43062306a36Sopenharmony_ci } else if (status_rate && (status_rate->rate_idx.flags & 43162306a36Sopenharmony_ci RATE_INFO_FLAGS_HE_MCS)) 43262306a36Sopenharmony_ci { 43362306a36Sopenharmony_ci struct ieee80211_radiotap_he *he; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_HE)); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* required alignment from rthdr */ 43862306a36Sopenharmony_ci pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2); 43962306a36Sopenharmony_ci he = (struct ieee80211_radiotap_he *)pos; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci he->data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU | 44262306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | 44362306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | 44462306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci he->data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci#define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f) 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci he->data6 |= HE_PREP(DATA6_NSTS, status_rate->rate_idx.nss); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci#define CHECK_GI(s) \ 45362306a36Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \ 45462306a36Sopenharmony_ci (int)NL80211_RATE_INFO_HE_GI_##s) 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci CHECK_GI(0_8); 45762306a36Sopenharmony_ci CHECK_GI(1_6); 45862306a36Sopenharmony_ci CHECK_GI(3_2); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci he->data3 |= HE_PREP(DATA3_DATA_MCS, status_rate->rate_idx.mcs); 46162306a36Sopenharmony_ci he->data3 |= HE_PREP(DATA3_DATA_DCM, status_rate->rate_idx.he_dcm); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci he->data5 |= HE_PREP(DATA5_GI, status_rate->rate_idx.he_gi); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci switch (status_rate->rate_idx.bw) { 46662306a36Sopenharmony_ci case RATE_INFO_BW_20: 46762306a36Sopenharmony_ci he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 46862306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ); 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci case RATE_INFO_BW_40: 47162306a36Sopenharmony_ci he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 47262306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ); 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci case RATE_INFO_BW_80: 47562306a36Sopenharmony_ci he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 47662306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case RATE_INFO_BW_160: 47962306a36Sopenharmony_ci he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 48062306a36Sopenharmony_ci IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci case RATE_INFO_BW_HE_RU: 48362306a36Sopenharmony_ci#define CHECK_RU_ALLOC(s) \ 48462306a36Sopenharmony_ci BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \ 48562306a36Sopenharmony_ci NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4) 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci CHECK_RU_ALLOC(26); 48862306a36Sopenharmony_ci CHECK_RU_ALLOC(52); 48962306a36Sopenharmony_ci CHECK_RU_ALLOC(106); 49062306a36Sopenharmony_ci CHECK_RU_ALLOC(242); 49162306a36Sopenharmony_ci CHECK_RU_ALLOC(484); 49262306a36Sopenharmony_ci CHECK_RU_ALLOC(996); 49362306a36Sopenharmony_ci CHECK_RU_ALLOC(2x996); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC, 49662306a36Sopenharmony_ci status_rate->rate_idx.he_ru_alloc + 4); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci default: 49962306a36Sopenharmony_ci WARN_ONCE(1, "Invalid SU BW %d\n", status_rate->rate_idx.bw); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci pos += sizeof(struct ieee80211_radiotap_he); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (status_rate || info->status.rates[0].idx < 0) 50662306a36Sopenharmony_ci return; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* IEEE80211_RADIOTAP_MCS 50962306a36Sopenharmony_ci * IEEE80211_RADIOTAP_VHT */ 51062306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { 51162306a36Sopenharmony_ci rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_MCS)); 51262306a36Sopenharmony_ci pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS | 51362306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_GI | 51462306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_BW; 51562306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 51662306a36Sopenharmony_ci pos[1] |= IEEE80211_RADIOTAP_MCS_SGI; 51762306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 51862306a36Sopenharmony_ci pos[1] |= IEEE80211_RADIOTAP_MCS_BW_40; 51962306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD) 52062306a36Sopenharmony_ci pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF; 52162306a36Sopenharmony_ci pos[2] = info->status.rates[0].idx; 52262306a36Sopenharmony_ci pos += 3; 52362306a36Sopenharmony_ci } else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { 52462306a36Sopenharmony_ci u16 known = local->hw.radiotap_vht_details & 52562306a36Sopenharmony_ci (IEEE80211_RADIOTAP_VHT_KNOWN_GI | 52662306a36Sopenharmony_ci IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT)); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* required alignment from rthdr */ 53162306a36Sopenharmony_ci pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */ 53462306a36Sopenharmony_ci put_unaligned_le16(known, pos); 53562306a36Sopenharmony_ci pos += 2; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */ 53862306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 53962306a36Sopenharmony_ci *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; 54062306a36Sopenharmony_ci pos++; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* u8 bandwidth */ 54362306a36Sopenharmony_ci if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 54462306a36Sopenharmony_ci *pos = 1; 54562306a36Sopenharmony_ci else if (info->status.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 54662306a36Sopenharmony_ci *pos = 4; 54762306a36Sopenharmony_ci else if (info->status.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 54862306a36Sopenharmony_ci *pos = 11; 54962306a36Sopenharmony_ci else /* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */ 55062306a36Sopenharmony_ci *pos = 0; 55162306a36Sopenharmony_ci pos++; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* u8 mcs_nss[4] */ 55462306a36Sopenharmony_ci *pos = (ieee80211_rate_get_vht_mcs(&info->status.rates[0]) << 4) | 55562306a36Sopenharmony_ci ieee80211_rate_get_vht_nss(&info->status.rates[0]); 55662306a36Sopenharmony_ci pos += 4; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* u8 coding */ 55962306a36Sopenharmony_ci pos++; 56062306a36Sopenharmony_ci /* u8 group_id */ 56162306a36Sopenharmony_ci pos++; 56262306a36Sopenharmony_ci /* u16 partial_aid */ 56362306a36Sopenharmony_ci pos += 2; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/* 56862306a36Sopenharmony_ci * Handles the tx for TDLS teardown frames. 56962306a36Sopenharmony_ci * If the frame wasn't ACKed by the peer - it will be re-sent through the AP 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_cistatic void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local, 57262306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 57362306a36Sopenharmony_ci struct sk_buff *skb, u32 flags) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct sk_buff *teardown_skb; 57662306a36Sopenharmony_ci struct sk_buff *orig_teardown_skb; 57762306a36Sopenharmony_ci bool is_teardown = false; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* Get the teardown data we need and free the lock */ 58062306a36Sopenharmony_ci spin_lock(&sdata->u.mgd.teardown_lock); 58162306a36Sopenharmony_ci teardown_skb = sdata->u.mgd.teardown_skb; 58262306a36Sopenharmony_ci orig_teardown_skb = sdata->u.mgd.orig_teardown_skb; 58362306a36Sopenharmony_ci if ((skb == orig_teardown_skb) && teardown_skb) { 58462306a36Sopenharmony_ci sdata->u.mgd.teardown_skb = NULL; 58562306a36Sopenharmony_ci sdata->u.mgd.orig_teardown_skb = NULL; 58662306a36Sopenharmony_ci is_teardown = true; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci spin_unlock(&sdata->u.mgd.teardown_lock); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (is_teardown) { 59162306a36Sopenharmony_ci /* This mechanism relies on being able to get ACKs */ 59262306a36Sopenharmony_ci WARN_ON(!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* Check if peer has ACKed */ 59562306a36Sopenharmony_ci if (flags & IEEE80211_TX_STAT_ACK) { 59662306a36Sopenharmony_ci dev_kfree_skb_any(teardown_skb); 59762306a36Sopenharmony_ci } else { 59862306a36Sopenharmony_ci tdls_dbg(sdata, 59962306a36Sopenharmony_ci "TDLS Resending teardown through AP\n"); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci ieee80211_subif_start_xmit(teardown_skb, skb->dev); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic struct ieee80211_sub_if_data * 60762306a36Sopenharmony_ciieee80211_sdata_from_skb(struct ieee80211_local *local, struct sk_buff *skb) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (skb->dev) { 61262306a36Sopenharmony_ci list_for_each_entry_rcu(sdata, &local->interfaces, list) { 61362306a36Sopenharmony_ci if (!sdata->dev) 61462306a36Sopenharmony_ci continue; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (skb->dev == sdata->dev) 61762306a36Sopenharmony_ci return sdata; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return NULL; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return rcu_dereference(local->p2p_sdata); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic void ieee80211_report_ack_skb(struct ieee80211_local *local, 62762306a36Sopenharmony_ci struct sk_buff *orig_skb, 62862306a36Sopenharmony_ci bool acked, bool dropped, 62962306a36Sopenharmony_ci ktime_t ack_hwtstamp) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(orig_skb); 63262306a36Sopenharmony_ci struct sk_buff *skb; 63362306a36Sopenharmony_ci unsigned long flags; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci spin_lock_irqsave(&local->ack_status_lock, flags); 63662306a36Sopenharmony_ci skb = idr_remove(&local->ack_status_frames, info->ack_frame_id); 63762306a36Sopenharmony_ci spin_unlock_irqrestore(&local->ack_status_lock, flags); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (!skb) 64062306a36Sopenharmony_ci return; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { 64362306a36Sopenharmony_ci u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie; 64462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 64562306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 64662306a36Sopenharmony_ci bool is_valid_ack_signal = 64762306a36Sopenharmony_ci !!(info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID); 64862306a36Sopenharmony_ci struct cfg80211_tx_status status = { 64962306a36Sopenharmony_ci .cookie = cookie, 65062306a36Sopenharmony_ci .buf = skb->data, 65162306a36Sopenharmony_ci .len = skb->len, 65262306a36Sopenharmony_ci .ack = acked, 65362306a36Sopenharmony_ci }; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (ieee80211_is_timing_measurement(orig_skb) || 65662306a36Sopenharmony_ci ieee80211_is_ftm(orig_skb)) { 65762306a36Sopenharmony_ci status.tx_tstamp = 65862306a36Sopenharmony_ci ktime_to_ns(skb_hwtstamps(orig_skb)->hwtstamp); 65962306a36Sopenharmony_ci status.ack_tstamp = ktime_to_ns(ack_hwtstamp); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci rcu_read_lock(); 66362306a36Sopenharmony_ci sdata = ieee80211_sdata_from_skb(local, skb); 66462306a36Sopenharmony_ci if (sdata) { 66562306a36Sopenharmony_ci if (skb->protocol == sdata->control_port_protocol || 66662306a36Sopenharmony_ci skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) 66762306a36Sopenharmony_ci cfg80211_control_port_tx_status(&sdata->wdev, 66862306a36Sopenharmony_ci cookie, 66962306a36Sopenharmony_ci skb->data, 67062306a36Sopenharmony_ci skb->len, 67162306a36Sopenharmony_ci acked, 67262306a36Sopenharmony_ci GFP_ATOMIC); 67362306a36Sopenharmony_ci else if (ieee80211_is_any_nullfunc(hdr->frame_control)) 67462306a36Sopenharmony_ci cfg80211_probe_status(sdata->dev, hdr->addr1, 67562306a36Sopenharmony_ci cookie, acked, 67662306a36Sopenharmony_ci info->status.ack_signal, 67762306a36Sopenharmony_ci is_valid_ack_signal, 67862306a36Sopenharmony_ci GFP_ATOMIC); 67962306a36Sopenharmony_ci else if (ieee80211_is_mgmt(hdr->frame_control)) 68062306a36Sopenharmony_ci cfg80211_mgmt_tx_status_ext(&sdata->wdev, 68162306a36Sopenharmony_ci &status, 68262306a36Sopenharmony_ci GFP_ATOMIC); 68362306a36Sopenharmony_ci else 68462306a36Sopenharmony_ci pr_warn("Unknown status report in ack skb\n"); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci rcu_read_unlock(); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 69062306a36Sopenharmony_ci } else if (dropped) { 69162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 69262306a36Sopenharmony_ci } else { 69362306a36Sopenharmony_ci /* consumes skb */ 69462306a36Sopenharmony_ci skb_complete_wifi_ack(skb, acked); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic void ieee80211_report_used_skb(struct ieee80211_local *local, 69962306a36Sopenharmony_ci struct sk_buff *skb, bool dropped, 70062306a36Sopenharmony_ci ktime_t ack_hwtstamp) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 70362306a36Sopenharmony_ci u16 tx_time_est = ieee80211_info_get_tx_time_est(info); 70462306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 70562306a36Sopenharmony_ci bool acked = info->flags & IEEE80211_TX_STAT_ACK; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (dropped) 70862306a36Sopenharmony_ci acked = false; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (tx_time_est) { 71162306a36Sopenharmony_ci struct sta_info *sta; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci rcu_read_lock(); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2); 71662306a36Sopenharmony_ci ieee80211_sta_update_pending_airtime(local, sta, 71762306a36Sopenharmony_ci skb_get_queue_mapping(skb), 71862306a36Sopenharmony_ci tx_time_est, 71962306a36Sopenharmony_ci true); 72062306a36Sopenharmony_ci rcu_read_unlock(); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { 72462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci rcu_read_lock(); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci sdata = ieee80211_sdata_from_skb(local, skb); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (!sdata) { 73162306a36Sopenharmony_ci skb->dev = NULL; 73262306a36Sopenharmony_ci } else if (!dropped) { 73362306a36Sopenharmony_ci unsigned int hdr_size = 73462306a36Sopenharmony_ci ieee80211_hdrlen(hdr->frame_control); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Check to see if packet is a TDLS teardown packet */ 73762306a36Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control) && 73862306a36Sopenharmony_ci (ieee80211_get_tdls_action(skb, hdr_size) == 73962306a36Sopenharmony_ci WLAN_TDLS_TEARDOWN)) { 74062306a36Sopenharmony_ci ieee80211_tdls_td_tx_handle(local, sdata, skb, 74162306a36Sopenharmony_ci info->flags); 74262306a36Sopenharmony_ci } else if (ieee80211_s1g_is_twt_setup(skb)) { 74362306a36Sopenharmony_ci if (!acked) { 74462306a36Sopenharmony_ci struct sk_buff *qskb; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci qskb = skb_clone(skb, GFP_ATOMIC); 74762306a36Sopenharmony_ci if (qskb) { 74862306a36Sopenharmony_ci skb_queue_tail(&sdata->status_queue, 74962306a36Sopenharmony_ci qskb); 75062306a36Sopenharmony_ci wiphy_work_queue(local->hw.wiphy, 75162306a36Sopenharmony_ci &sdata->work); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } else { 75562306a36Sopenharmony_ci ieee80211_mgd_conn_tx_status(sdata, 75662306a36Sopenharmony_ci hdr->frame_control, 75762306a36Sopenharmony_ci acked); 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci rcu_read_unlock(); 76262306a36Sopenharmony_ci } else if (info->ack_frame_id) { 76362306a36Sopenharmony_ci ieee80211_report_ack_skb(local, skb, acked, dropped, 76462306a36Sopenharmony_ci ack_hwtstamp); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!dropped && skb->destructor) { 76862306a36Sopenharmony_ci skb->wifi_acked_valid = 1; 76962306a36Sopenharmony_ci skb->wifi_acked = acked; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci ieee80211_led_tx(local); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (skb_has_frag_list(skb)) { 77562306a36Sopenharmony_ci kfree_skb_list(skb_shinfo(skb)->frag_list); 77662306a36Sopenharmony_ci skb_shinfo(skb)->frag_list = NULL; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci/* 78162306a36Sopenharmony_ci * Use a static threshold for now, best value to be determined 78262306a36Sopenharmony_ci * by testing ... 78362306a36Sopenharmony_ci * Should it depend on: 78462306a36Sopenharmony_ci * - on # of retransmissions 78562306a36Sopenharmony_ci * - current throughput (higher value for higher tpt)? 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci#define STA_LOST_PKT_THRESHOLD 50 78862306a36Sopenharmony_ci#define STA_LOST_PKT_TIME HZ /* 1 sec since last ACK */ 78962306a36Sopenharmony_ci#define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */ 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic void ieee80211_lost_packet(struct sta_info *sta, 79262306a36Sopenharmony_ci struct ieee80211_tx_info *info) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci unsigned long pkt_time = STA_LOST_PKT_TIME; 79562306a36Sopenharmony_ci unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* If driver relies on its own algorithm for station kickout, skip 79862306a36Sopenharmony_ci * mac80211 packet loss mechanism. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci if (ieee80211_hw_check(&sta->local->hw, REPORTS_LOW_ACK)) 80162306a36Sopenharmony_ci return; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* This packet was aggregated but doesn't carry status info */ 80462306a36Sopenharmony_ci if ((info->flags & IEEE80211_TX_CTL_AMPDU) && 80562306a36Sopenharmony_ci !(info->flags & IEEE80211_TX_STAT_AMPDU)) 80662306a36Sopenharmony_ci return; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci sta->deflink.status_stats.lost_packets++; 80962306a36Sopenharmony_ci if (sta->sta.tdls) { 81062306a36Sopenharmony_ci pkt_time = STA_LOST_TDLS_PKT_TIME; 81162306a36Sopenharmony_ci pkt_thr = STA_LOST_PKT_THRESHOLD; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* 81562306a36Sopenharmony_ci * If we're in TDLS mode, make sure that all STA_LOST_PKT_THRESHOLD 81662306a36Sopenharmony_ci * of the last packets were lost, and that no ACK was received in the 81762306a36Sopenharmony_ci * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss 81862306a36Sopenharmony_ci * mechanism. 81962306a36Sopenharmony_ci * For non-TDLS, use STA_LOST_PKT_THRESHOLD and STA_LOST_PKT_TIME 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ci if (sta->deflink.status_stats.lost_packets < pkt_thr || 82262306a36Sopenharmony_ci !time_after(jiffies, sta->deflink.status_stats.last_pkt_time + pkt_time)) 82362306a36Sopenharmony_ci return; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, 82662306a36Sopenharmony_ci sta->deflink.status_stats.lost_packets, 82762306a36Sopenharmony_ci GFP_ATOMIC); 82862306a36Sopenharmony_ci sta->deflink.status_stats.lost_packets = 0; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int ieee80211_tx_get_rates(struct ieee80211_hw *hw, 83262306a36Sopenharmony_ci struct ieee80211_tx_info *info, 83362306a36Sopenharmony_ci int *retry_count) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci int count = -1; 83662306a36Sopenharmony_ci int i; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 83962306a36Sopenharmony_ci if ((info->flags & IEEE80211_TX_CTL_AMPDU) && 84062306a36Sopenharmony_ci !(info->flags & IEEE80211_TX_STAT_AMPDU)) { 84162306a36Sopenharmony_ci /* just the first aggr frame carry status info */ 84262306a36Sopenharmony_ci info->status.rates[i].idx = -1; 84362306a36Sopenharmony_ci info->status.rates[i].count = 0; 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci } else if (info->status.rates[i].idx < 0) { 84662306a36Sopenharmony_ci break; 84762306a36Sopenharmony_ci } else if (i >= hw->max_report_rates) { 84862306a36Sopenharmony_ci /* the HW cannot have attempted that rate */ 84962306a36Sopenharmony_ci info->status.rates[i].idx = -1; 85062306a36Sopenharmony_ci info->status.rates[i].count = 0; 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci count += info->status.rates[i].count; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (count < 0) 85862306a36Sopenharmony_ci count = 0; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci *retry_count = count; 86162306a36Sopenharmony_ci return i - 1; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_civoid ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb, 86562306a36Sopenharmony_ci int retry_count, int shift, bool send_to_cooked, 86662306a36Sopenharmony_ci struct ieee80211_tx_status *status) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct sk_buff *skb2; 86962306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 87062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 87162306a36Sopenharmony_ci struct net_device *prev_dev = NULL; 87262306a36Sopenharmony_ci int rtap_len; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* send frame to monitor interfaces now */ 87562306a36Sopenharmony_ci rtap_len = ieee80211_tx_radiotap_len(info, status); 87662306a36Sopenharmony_ci if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) { 87762306a36Sopenharmony_ci pr_err("ieee80211_tx_status: headroom too small\n"); 87862306a36Sopenharmony_ci dev_kfree_skb(skb); 87962306a36Sopenharmony_ci return; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci ieee80211_add_tx_radiotap_header(local, skb, retry_count, 88262306a36Sopenharmony_ci rtap_len, shift, status); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* XXX: is this sufficient for BPF? */ 88562306a36Sopenharmony_ci skb_reset_mac_header(skb); 88662306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 88762306a36Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 88862306a36Sopenharmony_ci skb->protocol = htons(ETH_P_802_2); 88962306a36Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci rcu_read_lock(); 89262306a36Sopenharmony_ci list_for_each_entry_rcu(sdata, &local->interfaces, list) { 89362306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { 89462306a36Sopenharmony_ci if (!ieee80211_sdata_running(sdata)) 89562306a36Sopenharmony_ci continue; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) && 89862306a36Sopenharmony_ci !send_to_cooked) 89962306a36Sopenharmony_ci continue; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (prev_dev) { 90262306a36Sopenharmony_ci skb2 = skb_clone(skb, GFP_ATOMIC); 90362306a36Sopenharmony_ci if (skb2) { 90462306a36Sopenharmony_ci skb2->dev = prev_dev; 90562306a36Sopenharmony_ci netif_rx(skb2); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci prev_dev = sdata->dev; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci if (prev_dev) { 91362306a36Sopenharmony_ci skb->dev = prev_dev; 91462306a36Sopenharmony_ci netif_rx(skb); 91562306a36Sopenharmony_ci skb = NULL; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci rcu_read_unlock(); 91862306a36Sopenharmony_ci dev_kfree_skb(skb); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic void __ieee80211_tx_status(struct ieee80211_hw *hw, 92262306a36Sopenharmony_ci struct ieee80211_tx_status *status, 92362306a36Sopenharmony_ci int rates_idx, int retry_count) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct sk_buff *skb = status->skb; 92662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 92762306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 92862306a36Sopenharmony_ci struct ieee80211_tx_info *info = status->info; 92962306a36Sopenharmony_ci struct sta_info *sta; 93062306a36Sopenharmony_ci __le16 fc; 93162306a36Sopenharmony_ci bool send_to_cooked; 93262306a36Sopenharmony_ci bool acked; 93362306a36Sopenharmony_ci bool noack_success; 93462306a36Sopenharmony_ci struct ieee80211_bar *bar; 93562306a36Sopenharmony_ci int shift = 0; 93662306a36Sopenharmony_ci int tid = IEEE80211_NUM_TIDS; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci fc = hdr->frame_control; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (status->sta) { 94162306a36Sopenharmony_ci sta = container_of(status->sta, struct sta_info, sta); 94262306a36Sopenharmony_ci shift = ieee80211_vif_get_shift(&sta->sdata->vif); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_STATUS_EOSP) 94562306a36Sopenharmony_ci clear_sta_flag(sta, WLAN_STA_SP); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci acked = !!(info->flags & IEEE80211_TX_STAT_ACK); 94862306a36Sopenharmony_ci noack_success = !!(info->flags & 94962306a36Sopenharmony_ci IEEE80211_TX_STAT_NOACK_TRANSMITTED); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* mesh Peer Service Period support */ 95262306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sta->sdata->vif) && 95362306a36Sopenharmony_ci ieee80211_is_data_qos(fc)) 95462306a36Sopenharmony_ci ieee80211_mpsp_trigger_process( 95562306a36Sopenharmony_ci ieee80211_get_qos_ctl(hdr), sta, true, acked); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) && 95862306a36Sopenharmony_ci (ieee80211_is_data(hdr->frame_control)) && 95962306a36Sopenharmony_ci (rates_idx != -1)) 96062306a36Sopenharmony_ci sta->deflink.tx_stats.last_rate = 96162306a36Sopenharmony_ci info->status.rates[rates_idx]; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && 96462306a36Sopenharmony_ci (ieee80211_is_data_qos(fc))) { 96562306a36Sopenharmony_ci u16 ssn; 96662306a36Sopenharmony_ci u8 *qc; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci qc = ieee80211_get_qos_ctl(hdr); 96962306a36Sopenharmony_ci tid = qc[0] & 0xf; 97062306a36Sopenharmony_ci ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) 97162306a36Sopenharmony_ci & IEEE80211_SCTL_SEQ); 97262306a36Sopenharmony_ci ieee80211_send_bar(&sta->sdata->vif, hdr->addr1, 97362306a36Sopenharmony_ci tid, ssn); 97462306a36Sopenharmony_ci } else if (ieee80211_is_data_qos(fc)) { 97562306a36Sopenharmony_ci u8 *qc = ieee80211_get_qos_ctl(hdr); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci tid = qc[0] & 0xf; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (!acked && ieee80211_is_back_req(fc)) { 98162306a36Sopenharmony_ci u16 control; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* 98462306a36Sopenharmony_ci * BAR failed, store the last SSN and retry sending 98562306a36Sopenharmony_ci * the BAR when the next unicast transmission on the 98662306a36Sopenharmony_ci * same TID succeeds. 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci bar = (struct ieee80211_bar *) skb->data; 98962306a36Sopenharmony_ci control = le16_to_cpu(bar->control); 99062306a36Sopenharmony_ci if (!(control & IEEE80211_BAR_CTRL_MULTI_TID)) { 99162306a36Sopenharmony_ci u16 ssn = le16_to_cpu(bar->start_seq_num); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci tid = (control & 99462306a36Sopenharmony_ci IEEE80211_BAR_CTRL_TID_INFO_MASK) >> 99562306a36Sopenharmony_ci IEEE80211_BAR_CTRL_TID_INFO_SHIFT; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci ieee80211_set_bar_pending(sta, tid, ssn); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { 100262306a36Sopenharmony_ci ieee80211_handle_filtered_frame(local, sta, skb); 100362306a36Sopenharmony_ci return; 100462306a36Sopenharmony_ci } else if (ieee80211_is_data_present(fc)) { 100562306a36Sopenharmony_ci if (!acked && !noack_success) 100662306a36Sopenharmony_ci sta->deflink.status_stats.msdu_failed[tid]++; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci sta->deflink.status_stats.msdu_retries[tid] += 100962306a36Sopenharmony_ci retry_count; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) 101362306a36Sopenharmony_ci ieee80211_frame_acked(sta, skb); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* SNMP counters 101862306a36Sopenharmony_ci * Fragments are passed to low-level drivers as separate skbs, so these 101962306a36Sopenharmony_ci * are actually fragments, not frames. Update frame counters only for 102062306a36Sopenharmony_ci * the first fragment of the frame. */ 102162306a36Sopenharmony_ci if ((info->flags & IEEE80211_TX_STAT_ACK) || 102262306a36Sopenharmony_ci (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) { 102362306a36Sopenharmony_ci if (ieee80211_is_first_frag(hdr->seq_ctrl)) { 102462306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11TransmittedFrameCount); 102562306a36Sopenharmony_ci if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) 102662306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount); 102762306a36Sopenharmony_ci if (retry_count > 0) 102862306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11RetryCount); 102962306a36Sopenharmony_ci if (retry_count > 1) 103062306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11MultipleRetryCount); 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* This counter shall be incremented for an acknowledged MPDU 103462306a36Sopenharmony_ci * with an individual address in the address 1 field or an MPDU 103562306a36Sopenharmony_ci * with a multicast address in the address 1 field of type Data 103662306a36Sopenharmony_ci * or Management. */ 103762306a36Sopenharmony_ci if (!is_multicast_ether_addr(hdr->addr1) || 103862306a36Sopenharmony_ci ieee80211_is_data(fc) || 103962306a36Sopenharmony_ci ieee80211_is_mgmt(fc)) 104062306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11TransmittedFragmentCount); 104162306a36Sopenharmony_ci } else { 104262306a36Sopenharmony_ci if (ieee80211_is_first_frag(hdr->seq_ctrl)) 104362306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11FailedCount); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (ieee80211_is_any_nullfunc(fc) && 104762306a36Sopenharmony_ci ieee80211_has_pm(fc) && 104862306a36Sopenharmony_ci ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) && 104962306a36Sopenharmony_ci !(info->flags & IEEE80211_TX_CTL_INJECTED) && 105062306a36Sopenharmony_ci local->ps_sdata && !(local->scanning)) { 105162306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_STAT_ACK) 105262306a36Sopenharmony_ci local->ps_sdata->u.mgd.flags |= 105362306a36Sopenharmony_ci IEEE80211_STA_NULLFUNC_ACKED; 105462306a36Sopenharmony_ci mod_timer(&local->dynamic_ps_timer, 105562306a36Sopenharmony_ci jiffies + msecs_to_jiffies(10)); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* this was a transmitted frame, but now we want to reuse it */ 106162306a36Sopenharmony_ci skb_orphan(skb); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* Need to make a copy before skb->cb gets cleared */ 106462306a36Sopenharmony_ci send_to_cooked = !!(info->flags & IEEE80211_TX_CTL_INJECTED) || 106562306a36Sopenharmony_ci !(ieee80211_is_data(fc)); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* 106862306a36Sopenharmony_ci * This is a bit racy but we can avoid a lot of work 106962306a36Sopenharmony_ci * with this test... 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_ci if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) { 107262306a36Sopenharmony_ci if (status->free_list) 107362306a36Sopenharmony_ci list_add_tail(&skb->list, status->free_list); 107462306a36Sopenharmony_ci else 107562306a36Sopenharmony_ci dev_kfree_skb(skb); 107662306a36Sopenharmony_ci return; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* send to monitor interfaces */ 108062306a36Sopenharmony_ci ieee80211_tx_monitor(local, skb, retry_count, shift, 108162306a36Sopenharmony_ci send_to_cooked, status); 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_civoid ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 108762306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 108862306a36Sopenharmony_ci struct ieee80211_tx_status status = { 108962306a36Sopenharmony_ci .skb = skb, 109062306a36Sopenharmony_ci .info = IEEE80211_SKB_CB(skb), 109162306a36Sopenharmony_ci }; 109262306a36Sopenharmony_ci struct sta_info *sta; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci rcu_read_lock(); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2); 109762306a36Sopenharmony_ci if (sta) 109862306a36Sopenharmony_ci status.sta = &sta->sta; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci ieee80211_tx_status_ext(hw, &status); 110162306a36Sopenharmony_ci rcu_read_unlock(); 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_tx_status); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_civoid ieee80211_tx_status_ext(struct ieee80211_hw *hw, 110662306a36Sopenharmony_ci struct ieee80211_tx_status *status) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 110962306a36Sopenharmony_ci struct ieee80211_tx_info *info = status->info; 111062306a36Sopenharmony_ci struct ieee80211_sta *pubsta = status->sta; 111162306a36Sopenharmony_ci struct sk_buff *skb = status->skb; 111262306a36Sopenharmony_ci struct sta_info *sta = NULL; 111362306a36Sopenharmony_ci int rates_idx, retry_count; 111462306a36Sopenharmony_ci bool acked, noack_success, ack_signal_valid; 111562306a36Sopenharmony_ci u16 tx_time_est; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (pubsta) { 111862306a36Sopenharmony_ci sta = container_of(pubsta, struct sta_info, sta); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (status->n_rates) 112162306a36Sopenharmony_ci sta->deflink.tx_stats.last_rate_info = 112262306a36Sopenharmony_ci status->rates[status->n_rates - 1].rate_idx; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (skb && (tx_time_est = 112662306a36Sopenharmony_ci ieee80211_info_get_tx_time_est(IEEE80211_SKB_CB(skb))) > 0) { 112762306a36Sopenharmony_ci /* Do this here to avoid the expensive lookup of the sta 112862306a36Sopenharmony_ci * in ieee80211_report_used_skb(). 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_ci ieee80211_sta_update_pending_airtime(local, sta, 113162306a36Sopenharmony_ci skb_get_queue_mapping(skb), 113262306a36Sopenharmony_ci tx_time_est, 113362306a36Sopenharmony_ci true); 113462306a36Sopenharmony_ci ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0); 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!status->info) 113862306a36Sopenharmony_ci goto free; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci acked = !!(info->flags & IEEE80211_TX_STAT_ACK); 114362306a36Sopenharmony_ci noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED); 114462306a36Sopenharmony_ci ack_signal_valid = 114562306a36Sopenharmony_ci !!(info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (pubsta) { 114862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = sta->sdata; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci if (!acked && !noack_success) 115162306a36Sopenharmony_ci sta->deflink.status_stats.retry_failed++; 115262306a36Sopenharmony_ci sta->deflink.status_stats.retry_count += retry_count; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { 115562306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION && 115662306a36Sopenharmony_ci skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) 115762306a36Sopenharmony_ci ieee80211_sta_tx_notify(sdata, (void *) skb->data, 115862306a36Sopenharmony_ci acked, info->status.tx_time); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci if (acked) { 116162306a36Sopenharmony_ci sta->deflink.status_stats.last_ack = jiffies; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (sta->deflink.status_stats.lost_packets) 116462306a36Sopenharmony_ci sta->deflink.status_stats.lost_packets = 0; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci /* Track when last packet was ACKed */ 116762306a36Sopenharmony_ci sta->deflink.status_stats.last_pkt_time = jiffies; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* Reset connection monitor */ 117062306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION && 117162306a36Sopenharmony_ci unlikely(sdata->u.mgd.probe_send_count > 0)) 117262306a36Sopenharmony_ci sdata->u.mgd.probe_send_count = 0; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (ack_signal_valid) { 117562306a36Sopenharmony_ci sta->deflink.status_stats.last_ack_signal = 117662306a36Sopenharmony_ci (s8)info->status.ack_signal; 117762306a36Sopenharmony_ci sta->deflink.status_stats.ack_signal_filled = true; 117862306a36Sopenharmony_ci ewma_avg_signal_add(&sta->deflink.status_stats.avg_ack_signal, 117962306a36Sopenharmony_ci -info->status.ack_signal); 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) { 118262306a36Sopenharmony_ci /* 118362306a36Sopenharmony_ci * The STA is in power save mode, so assume 118462306a36Sopenharmony_ci * that this TX packet failed because of that. 118562306a36Sopenharmony_ci */ 118662306a36Sopenharmony_ci if (skb) 118762306a36Sopenharmony_ci ieee80211_handle_filtered_frame(local, sta, skb); 118862306a36Sopenharmony_ci return; 118962306a36Sopenharmony_ci } else if (noack_success) { 119062306a36Sopenharmony_ci /* nothing to do here, do not account as lost */ 119162306a36Sopenharmony_ci } else { 119262306a36Sopenharmony_ci ieee80211_lost_packet(sta, info); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci rate_control_tx_status(local, status); 119762306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sta->sdata->vif)) 119862306a36Sopenharmony_ci ieee80211s_update_metric(local, sta, status); 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) 120262306a36Sopenharmony_ci return __ieee80211_tx_status(hw, status, rates_idx, 120362306a36Sopenharmony_ci retry_count); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (acked || noack_success) { 120662306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11TransmittedFrameCount); 120762306a36Sopenharmony_ci if (!pubsta) 120862306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount); 120962306a36Sopenharmony_ci if (retry_count > 0) 121062306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11RetryCount); 121162306a36Sopenharmony_ci if (retry_count > 1) 121262306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11MultipleRetryCount); 121362306a36Sopenharmony_ci } else { 121462306a36Sopenharmony_ci I802_DEBUG_INC(local->dot11FailedCount); 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cifree: 121862306a36Sopenharmony_ci if (!skb) 121962306a36Sopenharmony_ci return; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci ieee80211_report_used_skb(local, skb, false, status->ack_hwtstamp); 122262306a36Sopenharmony_ci if (status->free_list) 122362306a36Sopenharmony_ci list_add_tail(&skb->list, status->free_list); 122462306a36Sopenharmony_ci else 122562306a36Sopenharmony_ci dev_kfree_skb(skb); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_tx_status_ext); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_civoid ieee80211_tx_rate_update(struct ieee80211_hw *hw, 123062306a36Sopenharmony_ci struct ieee80211_sta *pubsta, 123162306a36Sopenharmony_ci struct ieee80211_tx_info *info) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 123462306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 123562306a36Sopenharmony_ci struct ieee80211_tx_status status = { 123662306a36Sopenharmony_ci .info = info, 123762306a36Sopenharmony_ci .sta = pubsta, 123862306a36Sopenharmony_ci }; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci rate_control_tx_status(local, &status); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) 124362306a36Sopenharmony_ci sta->deflink.tx_stats.last_rate = info->status.rates[0]; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_tx_rate_update); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_civoid ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 125062306a36Sopenharmony_ci cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, 125162306a36Sopenharmony_ci num_packets, GFP_ATOMIC); 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_report_low_ack); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_civoid ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 125862306a36Sopenharmony_ci ktime_t kt = ktime_set(0, 0); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci ieee80211_report_used_skb(local, skb, true, kt); 126162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_free_txskb); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_civoid ieee80211_purge_tx_queue(struct ieee80211_hw *hw, 126662306a36Sopenharmony_ci struct sk_buff_head *skbs) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci struct sk_buff *skb; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci while ((skb = __skb_dequeue(skbs))) 127162306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 127262306a36Sopenharmony_ci} 1273