|
@@ -3107,6 +3107,97 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
EXPORT_SYMBOL(ieee80211_get_buffered_bc);
|
|
|
|
|
|
+int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid)
|
|
|
+{
|
|
|
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
|
|
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ int ret;
|
|
|
+ u32 queues;
|
|
|
+
|
|
|
+ lockdep_assert_held(&local->sta_mtx);
|
|
|
+
|
|
|
+ /* only some cases are supported right now */
|
|
|
+ switch (sdata->vif.type) {
|
|
|
+ case NL80211_IFTYPE_STATION:
|
|
|
+ case NL80211_IFTYPE_AP:
|
|
|
+ case NL80211_IFTYPE_AP_VLAN:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ WARN_ON(1);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (WARN_ON(tid >= IEEE80211_NUM_UPS))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (sta->reserved_tid == tid) {
|
|
|
+ ret = 0;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) {
|
|
|
+ sdata_err(sdata, "TID reservation already active\n");
|
|
|
+ ret = -EALREADY;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ ieee80211_stop_vif_queues(sdata->local, sdata,
|
|
|
+ IEEE80211_QUEUE_STOP_REASON_RESERVE_TID);
|
|
|
+
|
|
|
+ synchronize_net();
|
|
|
+
|
|
|
+ /* Tear down BA sessions so we stop aggregating on this TID */
|
|
|
+ if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) {
|
|
|
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
|
|
+ __ieee80211_stop_tx_ba_session(sta, tid,
|
|
|
+ AGG_STOP_LOCAL_REQUEST);
|
|
|
+ }
|
|
|
+
|
|
|
+ queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]);
|
|
|
+ __ieee80211_flush_queues(local, sdata, queues);
|
|
|
+
|
|
|
+ sta->reserved_tid = tid;
|
|
|
+
|
|
|
+ ieee80211_wake_vif_queues(local, sdata,
|
|
|
+ IEEE80211_QUEUE_STOP_REASON_RESERVE_TID);
|
|
|
+
|
|
|
+ if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
|
|
|
+ clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
|
|
+
|
|
|
+ ret = 0;
|
|
|
+ out:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(ieee80211_reserve_tid);
|
|
|
+
|
|
|
+void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid)
|
|
|
+{
|
|
|
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
|
|
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
|
|
|
+
|
|
|
+ lockdep_assert_held(&sdata->local->sta_mtx);
|
|
|
+
|
|
|
+ /* only some cases are supported right now */
|
|
|
+ switch (sdata->vif.type) {
|
|
|
+ case NL80211_IFTYPE_STATION:
|
|
|
+ case NL80211_IFTYPE_AP:
|
|
|
+ case NL80211_IFTYPE_AP_VLAN:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ WARN_ON(1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tid != sta->reserved_tid) {
|
|
|
+ sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ sta->reserved_tid = IEEE80211_TID_UNRESERVED;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(ieee80211_unreserve_tid);
|
|
|
+
|
|
|
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
|
|
struct sk_buff *skb, int tid,
|
|
|
enum ieee80211_band band)
|