/** * DOC: RX A-MPDU aggregation * * Aggregation on the RX side requires only implementing the * @ampdu_action callback that is invoked to start/stop any * block-ack sessions for RX aggregation. * * When RX aggregation is started by the peer, the driver is * notified via @ampdu_action function, with the * %IEEE80211_AMPDU_RX_START action, and may reject the request * in which case a negative response is sent to the peer, if it * accepts it a positive response is sent. * * While the session is active, the device/driver are required * to de-aggregate frames and pass them up one by one to mac80211, * which will handle the reorder buffer. * * When the aggregation session is stopped again by the peer or * ourselves, the driver's @ampdu_action function will be called * with the action %IEEE80211_AMPDU_RX_STOP. In this case, the * call must not fail.
*/
for (i = 0; i < tid_rx->buf_size; i++)
__skb_queue_purge(&tid_rx->reorder_buf[i]);
kfree(tid_rx->reorder_buf);
kfree(tid_rx->reorder_time);
kfree(tid_rx);
}
ht_dbg(sta->sdata, "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
sta->sta.addr, tid,
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "initiator",
(int)reason);
if (drv_ampdu_action(local, sta->sdata, ¶ms))
sdata_info(sta->sdata, "HW problem - can not stop rx aggregation for %pM tid %d\n",
sta->sta.addr, tid);
/* check if this is a self generated aggregation halt */ if (initiator == WLAN_BACK_RECIPIENT && tx)
ieee80211_send_delba(sta->sdata, sta->sta.addr,
tid, WLAN_BACK_RECIPIENT, reason);
/* * return here in case tid_rx is not assigned - which will happen if * IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
*/ if (!tid_rx) return;
timer_delete_sync(&tid_rx->session_timer);
/* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
spin_lock_bh(&tid_rx->reorder_lock);
tid_rx->removed = true;
spin_unlock_bh(&tid_rx->reorder_lock);
timer_delete_sync(&tid_rx->reorder_timer);
/* * After accepting the AddBA Request we activated a timer, * resetting it after each frame that arrives from the originator.
*/ staticvoid sta_rx_agg_session_timer_expired(struct timer_list *t)
{ struct tid_ampdu_rx *tid_rx = timer_container_of(tid_rx, t,
session_timer); struct sta_info *sta = tid_rx->sta;
u8 tid = tid_rx->tid; unsignedlong timeout;
if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
ht_dbg(sta->sdata, "STA %pM requests BA session on unsupported tid %d\n",
sta->sta.addr, tid); goto end;
}
if (!sta->sta.valid_links &&
!sta->sta.deflink.ht_cap.ht_supported &&
!sta->sta.deflink.he_cap.has_he &&
!sta->sta.deflink.s1g_cap.s1g) {
ht_dbg(sta->sdata, "STA %pM erroneously requests BA session on tid %d w/o HT\n",
sta->sta.addr, tid); /* send a response anyway, it's an error case if we get here */ goto end;
}
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
sta->sta.addr, tid); goto end;
}
/* sanity check for incoming parameters: * check if configuration can support the BA policy
* and if buffer size does not exceeds max value */ /* XXX: check own ht delayed BA capability?? */ if (((ba_policy != 1) &&
(sta->sta.valid_links ||
!(sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA) ||
!(sta->sta.deflink.s1g_cap.cap[3] & S1G_CAP3_HT_DELAYED_BA))) ||
(buf_size > max_buf_size)) {
status = WLAN_STATUS_INVALID_QOS_PARAM;
ht_dbg_ratelimited(sta->sdata, "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
sta->sta.addr, tid, ba_policy, buf_size); goto end;
} /* determine default buffer size */ if (buf_size == 0)
buf_size = max_buf_size;
/* make sure the size doesn't exceed the maximum supported by the hw */ if (buf_size > sta->sta.max_rx_aggregation_subframes)
buf_size = sta->sta.max_rx_aggregation_subframes;
params.buf_size = buf_size;
ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n",
buf_size, sta->sta.addr);
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) { if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) { struct tid_ampdu_rx *tid_rx;
ht_dbg_ratelimited(sta->sdata, "updated AddBA Req from %pM on tid %u\n",
sta->sta.addr, tid); /* We have no API to update the timeout value in the * driver so reject the timeout update if the timeout * changed. If it did not change, i.e., no real update, * just reply with success.
*/
rcu_read_lock();
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); if (tid_rx && tid_rx->timeout == timeout)
status = WLAN_STATUS_SUCCESS; else
status = WLAN_STATUS_REQUEST_DECLINED;
rcu_read_unlock(); goto end;
}
ht_dbg_ratelimited(sta->sdata, "unexpected AddBA Req from %pM on tid %u\n",
sta->sta.addr, tid);
/* delete existing Rx BA session on the same tid */
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
WLAN_STATUS_UNSPECIFIED_QOS, false);
}
if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
sta->sta.addr, tid, ret); if (!ret)
status = WLAN_STATUS_SUCCESS; goto end;
}
/* prepare A-MPDU MLME for Rx aggregation */
tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL); if (!tid_agg_rx) goto end;
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.