diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-11-16 06:00:40 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-18 17:09:17 -0500 |
commit | a02ae758e8780d737b6d0135d6292bb3043e7eea (patch) | |
tree | d7a1acb57944f51ddd299a8373b3e9f0174bffe8 /net/mac80211/rx.c | |
parent | af2ced6a32dafb71d21b726c06df57fc574093d7 (diff) |
mac80211: cleanup reorder buffer handling
The reorder buffer handling is written in a quite
peculiar style (especially comments) and also has
a quirk where it invokes the entire reorder code
in ieee80211_sta_manage_reorder_buf() for just a
handful of lines in it with a special argument.
Split out ieee80211_release_reorder_frames which
can then be invoked from BAR handling and other
reordering code, clean up code and comments and
remove function arguments that are now unused from
ieee80211_sta_manage_reorder_buf().
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 162 |
1 files changed, 81 insertions, 81 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 68d9e9c86595..37e9891605b4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -27,11 +27,10 @@ | |||
27 | #include "tkip.h" | 27 | #include "tkip.h" |
28 | #include "wme.h" | 28 | #include "wme.h" |
29 | 29 | ||
30 | static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | 30 | static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, |
31 | struct tid_ampdu_rx *tid_agg_rx, | 31 | struct tid_ampdu_rx *tid_agg_rx, |
32 | struct sk_buff *skb, | 32 | u16 head_seq_num); |
33 | u16 mpdu_seq_num, | 33 | |
34 | int bar_req); | ||
35 | /* | 34 | /* |
36 | * monitor mode reception | 35 | * monitor mode reception |
37 | * | 36 | * |
@@ -1592,11 +1591,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1592 | 1591 | ||
1593 | if (ieee80211_is_back_req(bar->frame_control)) { | 1592 | if (ieee80211_is_back_req(bar->frame_control)) { |
1594 | if (!rx->sta) | 1593 | if (!rx->sta) |
1595 | return RX_CONTINUE; | 1594 | return RX_DROP_MONITOR; |
1596 | tid = le16_to_cpu(bar->control) >> 12; | 1595 | tid = le16_to_cpu(bar->control) >> 12; |
1597 | if (rx->sta->ampdu_mlme.tid_state_rx[tid] | 1596 | if (rx->sta->ampdu_mlme.tid_state_rx[tid] |
1598 | != HT_AGG_STATE_OPERATIONAL) | 1597 | != HT_AGG_STATE_OPERATIONAL) |
1599 | return RX_CONTINUE; | 1598 | return RX_DROP_MONITOR; |
1600 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; | 1599 | tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; |
1601 | 1600 | ||
1602 | start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; | 1601 | start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; |
@@ -1606,13 +1605,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1606 | mod_timer(&tid_agg_rx->session_timer, | 1605 | mod_timer(&tid_agg_rx->session_timer, |
1607 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); | 1606 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); |
1608 | 1607 | ||
1609 | /* manage reordering buffer according to requested */ | 1608 | /* release stored frames up to start of BAR */ |
1610 | /* sequence number */ | 1609 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); |
1611 | rcu_read_lock(); | 1610 | kfree_skb(skb); |
1612 | ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, | 1611 | return RX_QUEUED; |
1613 | start_seq_num, 1); | ||
1614 | rcu_read_unlock(); | ||
1615 | return RX_DROP_UNUSABLE; | ||
1616 | } | 1612 | } |
1617 | 1613 | ||
1618 | return RX_CONTINUE; | 1614 | return RX_CONTINUE; |
@@ -2223,6 +2219,18 @@ no_frame: | |||
2223 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 2219 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); |
2224 | } | 2220 | } |
2225 | 2221 | ||
2222 | static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | ||
2223 | struct tid_ampdu_rx *tid_agg_rx, | ||
2224 | u16 head_seq_num) | ||
2225 | { | ||
2226 | int index; | ||
2227 | |||
2228 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | ||
2229 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | ||
2230 | tid_agg_rx->buf_size; | ||
2231 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); | ||
2232 | } | ||
2233 | } | ||
2226 | 2234 | ||
2227 | /* | 2235 | /* |
2228 | * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If | 2236 | * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If |
@@ -2234,15 +2242,17 @@ no_frame: | |||
2234 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) | 2242 | #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) |
2235 | 2243 | ||
2236 | /* | 2244 | /* |
2237 | * As it function blongs to Rx path it must be called with | 2245 | * As this function belongs to the RX path it must be under |
2238 | * the proper rcu_read_lock protection for its flow. | 2246 | * rcu_read_lock protection. It returns false if the frame |
2247 | * can be processed immediately, true if it was consumed. | ||
2239 | */ | 2248 | */ |
2240 | static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | 2249 | static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, |
2241 | struct tid_ampdu_rx *tid_agg_rx, | 2250 | struct tid_ampdu_rx *tid_agg_rx, |
2242 | struct sk_buff *skb, | 2251 | struct sk_buff *skb) |
2243 | u16 mpdu_seq_num, | ||
2244 | int bar_req) | ||
2245 | { | 2252 | { |
2253 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
2254 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | ||
2255 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | ||
2246 | u16 head_seq_num, buf_size; | 2256 | u16 head_seq_num, buf_size; |
2247 | int index; | 2257 | int index; |
2248 | 2258 | ||
@@ -2252,47 +2262,37 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2252 | /* frame with out of date sequence number */ | 2262 | /* frame with out of date sequence number */ |
2253 | if (seq_less(mpdu_seq_num, head_seq_num)) { | 2263 | if (seq_less(mpdu_seq_num, head_seq_num)) { |
2254 | dev_kfree_skb(skb); | 2264 | dev_kfree_skb(skb); |
2255 | return 1; | 2265 | return true; |
2256 | } | 2266 | } |
2257 | 2267 | ||
2258 | /* if frame sequence number exceeds our buffering window size or | 2268 | /* |
2259 | * block Ack Request arrived - release stored frames */ | 2269 | * If frame the sequence number exceeds our buffering window |
2260 | if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) { | 2270 | * size release some previous frames to make room for this one. |
2261 | /* new head to the ordering buffer */ | 2271 | */ |
2262 | if (bar_req) | 2272 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { |
2263 | head_seq_num = mpdu_seq_num; | 2273 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); |
2264 | else | ||
2265 | head_seq_num = | ||
2266 | seq_inc(seq_sub(mpdu_seq_num, buf_size)); | ||
2267 | /* release stored frames up to new head to stack */ | 2274 | /* release stored frames up to new head to stack */ |
2268 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 2275 | ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); |
2269 | index = seq_sub(tid_agg_rx->head_seq_num, | ||
2270 | tid_agg_rx->ssn) | ||
2271 | % tid_agg_rx->buf_size; | ||
2272 | ieee80211_release_reorder_frame(hw, tid_agg_rx, | ||
2273 | index); | ||
2274 | } | ||
2275 | if (bar_req) | ||
2276 | return 1; | ||
2277 | } | 2276 | } |
2278 | 2277 | ||
2279 | /* now the new frame is always in the range of the reordering */ | 2278 | /* Now the new frame is always in the range of the reordering buffer */ |
2280 | /* buffer window */ | 2279 | |
2281 | index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) | 2280 | index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; |
2282 | % tid_agg_rx->buf_size; | 2281 | |
2283 | /* check if we already stored this frame */ | 2282 | /* check if we already stored this frame */ |
2284 | if (tid_agg_rx->reorder_buf[index]) { | 2283 | if (tid_agg_rx->reorder_buf[index]) { |
2285 | dev_kfree_skb(skb); | 2284 | dev_kfree_skb(skb); |
2286 | return 1; | 2285 | return true; |
2287 | } | 2286 | } |
2288 | 2287 | ||
2289 | /* if arrived mpdu is in the right order and nothing else stored */ | 2288 | /* |
2290 | /* release it immediately */ | 2289 | * If the current MPDU is in the right order and nothing else |
2290 | * is stored we can process it directly, no need to buffer it. | ||
2291 | */ | ||
2291 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 2292 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
2292 | tid_agg_rx->stored_mpdu_num == 0) { | 2293 | tid_agg_rx->stored_mpdu_num == 0) { |
2293 | tid_agg_rx->head_seq_num = | 2294 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); |
2294 | seq_inc(tid_agg_rx->head_seq_num); | 2295 | return false; |
2295 | return 0; | ||
2296 | } | 2296 | } |
2297 | 2297 | ||
2298 | /* put the frame in the reordering buffer */ | 2298 | /* put the frame in the reordering buffer */ |
@@ -2300,8 +2300,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2300 | tid_agg_rx->reorder_time[index] = jiffies; | 2300 | tid_agg_rx->reorder_time[index] = jiffies; |
2301 | tid_agg_rx->stored_mpdu_num++; | 2301 | tid_agg_rx->stored_mpdu_num++; |
2302 | /* release the buffer until next missing frame */ | 2302 | /* release the buffer until next missing frame */ |
2303 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) | 2303 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
2304 | % tid_agg_rx->buf_size; | 2304 | tid_agg_rx->buf_size; |
2305 | if (!tid_agg_rx->reorder_buf[index] && | 2305 | if (!tid_agg_rx->reorder_buf[index] && |
2306 | tid_agg_rx->stored_mpdu_num > 1) { | 2306 | tid_agg_rx->stored_mpdu_num > 1) { |
2307 | /* | 2307 | /* |
@@ -2312,12 +2312,12 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2312 | int skipped = 1; | 2312 | int skipped = 1; |
2313 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | 2313 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; |
2314 | j = (j + 1) % tid_agg_rx->buf_size) { | 2314 | j = (j + 1) % tid_agg_rx->buf_size) { |
2315 | if (tid_agg_rx->reorder_buf[j] == NULL) { | 2315 | if (!tid_agg_rx->reorder_buf[j]) { |
2316 | skipped++; | 2316 | skipped++; |
2317 | continue; | 2317 | continue; |
2318 | } | 2318 | } |
2319 | if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + | 2319 | if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + |
2320 | HZ / 10)) | 2320 | HT_RX_REORDER_BUF_TIMEOUT)) |
2321 | break; | 2321 | break; |
2322 | 2322 | ||
2323 | #ifdef CONFIG_MAC80211_HT_DEBUG | 2323 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -2333,51 +2333,56 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2333 | * Increment the head seq# also for the skipped slots. | 2333 | * Increment the head seq# also for the skipped slots. |
2334 | */ | 2334 | */ |
2335 | tid_agg_rx->head_seq_num = | 2335 | tid_agg_rx->head_seq_num = |
2336 | (tid_agg_rx->head_seq_num + skipped) & | 2336 | (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; |
2337 | SEQ_MASK; | ||
2338 | skipped = 0; | 2337 | skipped = 0; |
2339 | } | 2338 | } |
2340 | } else while (tid_agg_rx->reorder_buf[index]) { | 2339 | } else while (tid_agg_rx->reorder_buf[index]) { |
2341 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); | 2340 | ieee80211_release_reorder_frame(hw, tid_agg_rx, index); |
2342 | index = seq_sub(tid_agg_rx->head_seq_num, | 2341 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
2343 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | 2342 | tid_agg_rx->buf_size; |
2344 | } | 2343 | } |
2345 | return 1; | 2344 | |
2345 | return true; | ||
2346 | } | 2346 | } |
2347 | 2347 | ||
2348 | static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | 2348 | /* |
2349 | struct sk_buff *skb) | 2349 | * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns |
2350 | * true if the MPDU was buffered, false if it should be processed. | ||
2351 | */ | ||
2352 | static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | ||
2353 | struct sk_buff *skb) | ||
2350 | { | 2354 | { |
2351 | struct ieee80211_hw *hw = &local->hw; | 2355 | struct ieee80211_hw *hw = &local->hw; |
2352 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 2356 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
2353 | struct sta_info *sta; | 2357 | struct sta_info *sta; |
2354 | struct tid_ampdu_rx *tid_agg_rx; | 2358 | struct tid_ampdu_rx *tid_agg_rx; |
2355 | u16 sc; | 2359 | u16 sc; |
2356 | u16 mpdu_seq_num; | ||
2357 | u8 ret = 0; | ||
2358 | int tid; | 2360 | int tid; |
2359 | 2361 | ||
2362 | if (!ieee80211_is_data_qos(hdr->frame_control)) | ||
2363 | return false; | ||
2364 | |||
2365 | /* | ||
2366 | * filter the QoS data rx stream according to | ||
2367 | * STA/TID and check if this STA/TID is on aggregation | ||
2368 | */ | ||
2369 | |||
2360 | sta = sta_info_get(local, hdr->addr2); | 2370 | sta = sta_info_get(local, hdr->addr2); |
2361 | if (!sta) | 2371 | if (!sta) |
2362 | return ret; | 2372 | return false; |
2363 | |||
2364 | /* filter the QoS data rx stream according to | ||
2365 | * STA/TID and check if this STA/TID is on aggregation */ | ||
2366 | if (!ieee80211_is_data_qos(hdr->frame_control)) | ||
2367 | goto end_reorder; | ||
2368 | 2373 | ||
2369 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 2374 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
2370 | 2375 | ||
2371 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) | 2376 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) |
2372 | goto end_reorder; | 2377 | return false; |
2373 | 2378 | ||
2374 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | 2379 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; |
2375 | 2380 | ||
2376 | /* qos null data frames are excluded */ | 2381 | /* qos null data frames are excluded */ |
2377 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) | 2382 | if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) |
2378 | goto end_reorder; | 2383 | return false; |
2379 | 2384 | ||
2380 | /* new un-ordered ampdu frame - process it */ | 2385 | /* new, potentially un-ordered, ampdu frame - process it */ |
2381 | 2386 | ||
2382 | /* reset session timer */ | 2387 | /* reset session timer */ |
2383 | if (tid_agg_rx->timeout) | 2388 | if (tid_agg_rx->timeout) |
@@ -2389,16 +2394,11 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2389 | if (sc & IEEE80211_SCTL_FRAG) { | 2394 | if (sc & IEEE80211_SCTL_FRAG) { |
2390 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, | 2395 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, |
2391 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); | 2396 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); |
2392 | ret = 1; | 2397 | dev_kfree_skb(skb); |
2393 | goto end_reorder; | 2398 | return true; |
2394 | } | 2399 | } |
2395 | 2400 | ||
2396 | /* according to mpdu sequence number deal with reordering buffer */ | 2401 | return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb); |
2397 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | ||
2398 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, | ||
2399 | mpdu_seq_num, 0); | ||
2400 | end_reorder: | ||
2401 | return ret; | ||
2402 | } | 2402 | } |
2403 | 2403 | ||
2404 | /* | 2404 | /* |