diff options
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2dd89670e1cd..0cb41d1a1f20 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -3107,6 +3107,97 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
3107 | } | 3107 | } |
3108 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); | 3108 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); |
3109 | 3109 | ||
3110 | int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3111 | { | ||
3112 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3113 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3114 | struct ieee80211_local *local = sdata->local; | ||
3115 | int ret; | ||
3116 | u32 queues; | ||
3117 | |||
3118 | lockdep_assert_held(&local->sta_mtx); | ||
3119 | |||
3120 | /* only some cases are supported right now */ | ||
3121 | switch (sdata->vif.type) { | ||
3122 | case NL80211_IFTYPE_STATION: | ||
3123 | case NL80211_IFTYPE_AP: | ||
3124 | case NL80211_IFTYPE_AP_VLAN: | ||
3125 | break; | ||
3126 | default: | ||
3127 | WARN_ON(1); | ||
3128 | return -EINVAL; | ||
3129 | } | ||
3130 | |||
3131 | if (WARN_ON(tid >= IEEE80211_NUM_UPS)) | ||
3132 | return -EINVAL; | ||
3133 | |||
3134 | if (sta->reserved_tid == tid) { | ||
3135 | ret = 0; | ||
3136 | goto out; | ||
3137 | } | ||
3138 | |||
3139 | if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) { | ||
3140 | sdata_err(sdata, "TID reservation already active\n"); | ||
3141 | ret = -EALREADY; | ||
3142 | goto out; | ||
3143 | } | ||
3144 | |||
3145 | ieee80211_stop_vif_queues(sdata->local, sdata, | ||
3146 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3147 | |||
3148 | synchronize_net(); | ||
3149 | |||
3150 | /* Tear down BA sessions so we stop aggregating on this TID */ | ||
3151 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
3152 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3153 | __ieee80211_stop_tx_ba_session(sta, tid, | ||
3154 | AGG_STOP_LOCAL_REQUEST); | ||
3155 | } | ||
3156 | |||
3157 | queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); | ||
3158 | __ieee80211_flush_queues(local, sdata, queues); | ||
3159 | |||
3160 | sta->reserved_tid = tid; | ||
3161 | |||
3162 | ieee80211_wake_vif_queues(local, sdata, | ||
3163 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3164 | |||
3165 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | ||
3166 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3167 | |||
3168 | ret = 0; | ||
3169 | out: | ||
3170 | return ret; | ||
3171 | } | ||
3172 | EXPORT_SYMBOL(ieee80211_reserve_tid); | ||
3173 | |||
3174 | void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3175 | { | ||
3176 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3177 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3178 | |||
3179 | lockdep_assert_held(&sdata->local->sta_mtx); | ||
3180 | |||
3181 | /* only some cases are supported right now */ | ||
3182 | switch (sdata->vif.type) { | ||
3183 | case NL80211_IFTYPE_STATION: | ||
3184 | case NL80211_IFTYPE_AP: | ||
3185 | case NL80211_IFTYPE_AP_VLAN: | ||
3186 | break; | ||
3187 | default: | ||
3188 | WARN_ON(1); | ||
3189 | return; | ||
3190 | } | ||
3191 | |||
3192 | if (tid != sta->reserved_tid) { | ||
3193 | sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid); | ||
3194 | return; | ||
3195 | } | ||
3196 | |||
3197 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
3198 | } | ||
3199 | EXPORT_SYMBOL(ieee80211_unreserve_tid); | ||
3200 | |||
3110 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 3201 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
3111 | struct sk_buff *skb, int tid, | 3202 | struct sk_buff *skb, int tid, |
3112 | enum ieee80211_band band) | 3203 | enum ieee80211_band band) |