/* * This skb 'survived' a round-trip through the driver, and * hopefully the driver didn't mangle it too badly. However, * we can definitely not rely on the control information * being correct. Clear it so we don't get junk there, and * indicate that it needs new processing, but must not be * modified/encrypted again.
*/
memset(&info->control, 0, sizeof(info->control));
/* * Clear more-data bit on filtered frames, it might be set * but later frames might time out so it might have to be * clear again ... It's all rather unlikely (this frame * should time out first, right?) but let's not confuse * peers unnecessarily.
*/ if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA))
hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *p = ieee80211_get_qos_ctl(hdr); int tid = *p & IEEE80211_QOS_CTL_TID_MASK;
/* * Clear EOSP if set, this could happen e.g. * if an absence period (us being a P2P GO) * shortens the SP.
*/ if (*p & IEEE80211_QOS_CTL_EOSP)
*p &= ~IEEE80211_QOS_CTL_EOSP;
ac = ieee80211_ac_from_tid(tid);
} else {
ac = IEEE80211_AC_BE;
}
/* * Clear the TX filter mask for this STA when sending the next * packet. If the STA went to power save mode, this will happen * when it wakes up for the next time.
*/
set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT);
ieee80211_clear_fast_xmit(sta);
/* * This code races in the following way: * * (1) STA sends frame indicating it will go to sleep and does so * (2) hardware/firmware adds STA to filter list, passes frame up * (3) hardware/firmware processes TX fifo and suppresses a frame * (4) we get TX status before having processed the frame and * knowing that the STA has gone to sleep. * * This is actually quite unlikely even when both those events are * processed from interrupts coming in quickly after one another or * even at the same time because we queue both TX status events and * RX frames to be processed by a tasklet and process them in the * same order that they were received or TX status last. Hence, there * is no race as long as the frame RX is processed before the next TX * status, which drivers can ensure, see below. * * Note that this can only happen if the hardware or firmware can * actually add STAs to the filter list, if this is done by the * driver in response to set_tim() (which will only reduce the race * this whole filtering tries to solve, not completely solve it) * this situation cannot happen. * * To completely solve this race drivers need to make sure that they * (a) don't mix the irq-safe/not irq-safe TX status/RX processing * functions and * (b) always process RX events before TX status events if ordering * can be unknown, for example with different interrupt status * bits. * (c) if PS mode transitions are manual (i.e. the flag * %IEEE80211_HW_AP_LINK_PS is set), always process PS state * changes before calling TX status events if ordering can be * unknown.
*/ if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) {
skb_queue_tail(&sta->tx_filtered[ac], skb);
sta_info_recalc_tim(sta);
if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup,
round_jiffies(jiffies +
STA_INFO_CLEANUP_INTERVAL)); return;
}
if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
!(info->flags & IEEE80211_TX_INTFL_RETRIED)) { /* Software retry the packet once */
info->flags |= IEEE80211_TX_INTFL_RETRIED;
ieee80211_add_pending_skb(local, skb); return;
}
/* * XXX: Once radiotap gets the bitmap reset thing the vendor * extensions proposal contains, we can actually report * the whole set of tries we did.
*/
/* * Handles the tx for TDLS teardown frames. * If the frame wasn't ACKed by the peer - it will be re-sent through the AP
*/ staticvoid ieee80211_tdls_td_tx_handle(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, u32 flags)
{ struct sk_buff *teardown_skb; struct sk_buff *orig_teardown_skb; bool is_teardown = false;
/* Get the teardown data we need and free the lock */
spin_lock(&sdata->u.mgd.teardown_lock);
teardown_skb = sdata->u.mgd.teardown_skb;
orig_teardown_skb = sdata->u.mgd.orig_teardown_skb; if ((skb == orig_teardown_skb) && teardown_skb) {
sdata->u.mgd.teardown_skb = NULL;
sdata->u.mgd.orig_teardown_skb = NULL;
is_teardown = true;
}
spin_unlock(&sdata->u.mgd.teardown_lock);
if (is_teardown) { /* This mechanism relies on being able to get ACKs */
WARN_ON(!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS));
/* Check if peer has ACKed */ if (flags & IEEE80211_TX_STAT_ACK) {
dev_kfree_skb_any(teardown_skb);
} else {
tdls_dbg(sdata, "TDLS Resending teardown through AP\n");
if (!sdata || !ieee80211_sdata_running(sdata)) return;
if (!acked) return;
if (sdata->vif.type != NL80211_IFTYPE_STATION) return;
if (WARN(link_id >= ARRAY_SIZE(sdata->link), "bad SMPS status link: %d\n", link_id)) return;
link = rcu_dereference(sdata->link[link_id]); if (!link) return;
/* * This update looks racy, but isn't, the only other place * updating this variable is in managed mode before assoc, * and we have to be associated to have a status from the * action frame TX, since we cannot send it while we're not * associated yet.
*/
link->smps_mode = smps_mode;
wiphy_work_queue(sdata->local->hw.wiphy, &link->u.mgd.recalc_smps);
}
if (skb_has_frag_list(skb)) {
kfree_skb_list(skb_shinfo(skb)->frag_list);
skb_shinfo(skb)->frag_list = NULL;
}
}
/* * Use a static threshold for now, best value to be determined * by testing ... * Should it depend on: * - on # of retransmissions * - current throughput (higher value for higher tpt)?
*/ #define STA_LOST_PKT_THRESHOLD 50 #define STA_LOST_PKT_TIME HZ /* 1 sec since last ACK */ #define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */
/* If driver relies on its own algorithm for station kickout, skip * mac80211 packet loss mechanism.
*/ if (ieee80211_hw_check(&sta->local->hw, REPORTS_LOW_ACK)) return;
/* This packet was aggregated but doesn't carry status info */ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
!(info->flags & IEEE80211_TX_STAT_AMPDU)) return;
/* * If we're in TDLS mode, make sure that all STA_LOST_PKT_THRESHOLD * of the last packets were lost, and that no ACK was received in the * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss * mechanism. * For non-TDLS, use STA_LOST_PKT_THRESHOLD and STA_LOST_PKT_TIME
*/ if (sta->deflink.status_stats.lost_packets < pkt_thr ||
!time_after(jiffies, sta->deflink.status_stats.last_pkt_time + pkt_time)) return;
staticint ieee80211_tx_get_rates(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, int *retry_count)
{ int count = -1; int i;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
!(info->flags & IEEE80211_TX_STAT_AMPDU)) { /* just the first aggr frame carry status info */
info->status.rates[i].idx = -1;
info->status.rates[i].count = 0; break;
} elseif (info->status.rates[i].idx < 0) { break;
} elseif (i >= hw->max_report_rates) { /* the HW cannot have attempted that rate */
info->status.rates[i].idx = -1;
info->status.rates[i].count = 0; break;
}
/* mesh Peer Service Period support */ if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
ieee80211_is_data_qos(fc))
ieee80211_mpsp_trigger_process(
ieee80211_get_qos_ctl(hdr), sta, true, acked);
if (!acked && ieee80211_is_back_req(fc)) {
u16 control;
/* * BAR failed, store the last SSN and retry sending * the BAR when the next unicast transmission on the * same TID succeeds.
*/
bar = (struct ieee80211_bar *) skb->data;
control = le16_to_cpu(bar->control); if (!(control & IEEE80211_BAR_CTRL_MULTI_TID)) {
u16 ssn = le16_to_cpu(bar->start_seq_num);
tid = (control &
IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
ieee80211_set_bar_pending(sta, tid, ssn);
}
}
if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
ieee80211_handle_filtered_frame(local, sta, skb); return;
} elseif (ieee80211_is_data_present(fc)) { if (!acked && !noack_success)
sta->deflink.status_stats.msdu_failed[tid]++;
if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
ieee80211_frame_acked(sta, skb);
}
/* SNMP counters * Fragments are passed to low-level drivers as separate skbs, so these * are actually fragments, not frames. Update frame counters only for
* the first fragment of the frame. */ if ((info->flags & IEEE80211_TX_STAT_ACK) ||
(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) { if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
I802_DEBUG_INC(local->dot11TransmittedFrameCount); if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount); if (retry_count > 0)
I802_DEBUG_INC(local->dot11RetryCount); if (retry_count > 1)
I802_DEBUG_INC(local->dot11MultipleRetryCount);
}
/* This counter shall be incremented for an acknowledged MPDU * with an individual address in the address 1 field or an MPDU * with a multicast address in the address 1 field of type Data
* or Management. */ if (!is_multicast_ether_addr(hdr->addr1) ||
ieee80211_is_data(fc) ||
ieee80211_is_mgmt(fc))
I802_DEBUG_INC(local->dot11TransmittedFragmentCount);
} else { if (ieee80211_is_first_frag(hdr->seq_ctrl))
I802_DEBUG_INC(local->dot11FailedCount);
}
/* * This is a bit racy but we can avoid a lot of work * with this test...
*/ if (local->tx_mntrs)
ieee80211_tx_monitor(local, skb, retry_count, status); elseif (status->free_list)
list_add_tail(&skb->list, status->free_list); else
dev_kfree_skb(skb);
}
if (pubsta) {
sta = container_of(pubsta, struct sta_info, sta);
if (status->n_rates)
sta->deflink.tx_stats.last_rate_info =
status->rates[status->n_rates - 1].rate_idx;
}
if (skb && (tx_time_est =
ieee80211_info_get_tx_time_est(IEEE80211_SKB_CB(skb))) > 0) { /* Do this here to avoid the expensive lookup of the sta * in ieee80211_report_used_skb().
*/
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est, true);
ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0);
}
if (ack_signal_valid) {
sta->deflink.status_stats.last_ack_signal =
(s8)info->status.ack_signal;
sta->deflink.status_stats.ack_signal_filled = true;
ewma_avg_signal_add(&sta->deflink.status_stats.avg_ack_signal,
-info->status.ack_signal);
}
} elseif (test_sta_flag(sta, WLAN_STA_PS_STA)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that.
*/ if (skb)
ieee80211_handle_filtered_frame(local, sta, skb); return;
} elseif (noack_success) { /* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}
}
rate_control_tx_status(local, status); if (ieee80211_vif_is_mesh(&sta->sdata->vif))
ieee80211s_update_metric(local, sta, status);
}
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.