diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-06-17 07:13:00 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 14:57:54 -0400 |
commit | f1d58c2521eb160178b2151d6326d8dc5d7c8560 (patch) | |
tree | af373bb1a5fbb6bc9436d29095133992d33d6598 /net/mac80211/rx.c | |
parent | 18ad01c43918751cc22f8ee28f6b38b8954a55b2 (diff) |
mac80211: push rx status into skb->cb
Within mac80211, we often need to copy the rx status into
skb->cb. This is wasteful, as drivers could be building it
in there to start with. This patch changes the API so that
drivers are expected to pass the RX status in skb->cb, now
accessible as IEEE80211_SKB_RXCB(skb). It also updates all
drivers to pass the rx status in there, but only by making
them memcpy() it into place before the call to the receive
function (ieee80211_rx(_irqsafe)). Each driver can now be
optimised on its own schedule.
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 | 71 |
1 files changed, 31 insertions, 40 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index de5bba7f910a..0563b6969a21 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -30,7 +30,6 @@ | |||
30 | static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | 30 | static u8 ieee80211_sta_manage_reorder_buf(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 | struct sk_buff *skb, |
33 | struct ieee80211_rx_status *status, | ||
34 | u16 mpdu_seq_num, | 33 | u16 mpdu_seq_num, |
35 | int bar_req); | 34 | int bar_req); |
36 | /* | 35 | /* |
@@ -59,11 +58,11 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
59 | return skb; | 58 | return skb; |
60 | } | 59 | } |
61 | 60 | ||
62 | static inline int should_drop_frame(struct ieee80211_rx_status *status, | 61 | static inline int should_drop_frame(struct sk_buff *skb, |
63 | struct sk_buff *skb, | ||
64 | int present_fcs_len, | 62 | int present_fcs_len, |
65 | int radiotap_len) | 63 | int radiotap_len) |
66 | { | 64 | { |
65 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
67 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 66 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
68 | 67 | ||
69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | 68 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) |
@@ -111,10 +110,10 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | |||
111 | static void | 110 | static void |
112 | ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | 111 | ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, |
113 | struct sk_buff *skb, | 112 | struct sk_buff *skb, |
114 | struct ieee80211_rx_status *status, | ||
115 | struct ieee80211_rate *rate, | 113 | struct ieee80211_rate *rate, |
116 | int rtap_len) | 114 | int rtap_len) |
117 | { | 115 | { |
116 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
118 | struct ieee80211_radiotap_header *rthdr; | 117 | struct ieee80211_radiotap_header *rthdr; |
119 | unsigned char *pos; | 118 | unsigned char *pos; |
120 | 119 | ||
@@ -220,9 +219,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
220 | */ | 219 | */ |
221 | static struct sk_buff * | 220 | static struct sk_buff * |
222 | ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | 221 | ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, |
223 | struct ieee80211_rx_status *status, | ||
224 | struct ieee80211_rate *rate) | 222 | struct ieee80211_rate *rate) |
225 | { | 223 | { |
224 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); | ||
226 | struct ieee80211_sub_if_data *sdata; | 225 | struct ieee80211_sub_if_data *sdata; |
227 | int needed_headroom = 0; | 226 | int needed_headroom = 0; |
228 | struct sk_buff *skb, *skb2; | 227 | struct sk_buff *skb, *skb2; |
@@ -248,8 +247,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
248 | present_fcs_len = FCS_LEN; | 247 | present_fcs_len = FCS_LEN; |
249 | 248 | ||
250 | if (!local->monitors) { | 249 | if (!local->monitors) { |
251 | if (should_drop_frame(status, origskb, present_fcs_len, | 250 | if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { |
252 | rtap_len)) { | ||
253 | dev_kfree_skb(origskb); | 251 | dev_kfree_skb(origskb); |
254 | return NULL; | 252 | return NULL; |
255 | } | 253 | } |
@@ -257,7 +255,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
257 | return remove_monitor_info(local, origskb, rtap_len); | 255 | return remove_monitor_info(local, origskb, rtap_len); |
258 | } | 256 | } |
259 | 257 | ||
260 | if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) { | 258 | if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { |
261 | /* only need to expand headroom if necessary */ | 259 | /* only need to expand headroom if necessary */ |
262 | skb = origskb; | 260 | skb = origskb; |
263 | origskb = NULL; | 261 | origskb = NULL; |
@@ -289,7 +287,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
289 | 287 | ||
290 | /* if necessary, prepend radiotap information */ | 288 | /* if necessary, prepend radiotap information */ |
291 | if (!(status->flag & RX_FLAG_RADIOTAP)) | 289 | if (!(status->flag & RX_FLAG_RADIOTAP)) |
292 | ieee80211_add_rx_radiotap_header(local, skb, status, rate, | 290 | ieee80211_add_rx_radiotap_header(local, skb, rate, |
293 | needed_headroom); | 291 | needed_headroom); |
294 | 292 | ||
295 | skb_reset_mac_header(skb); | 293 | skb_reset_mac_header(skb); |
@@ -421,12 +419,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | |||
421 | struct sk_buff *skb = rx->skb; | 419 | struct sk_buff *skb = rx->skb; |
422 | 420 | ||
423 | if (unlikely(local->hw_scanning)) | 421 | if (unlikely(local->hw_scanning)) |
424 | return ieee80211_scan_rx(rx->sdata, skb, rx->status); | 422 | return ieee80211_scan_rx(rx->sdata, skb); |
425 | 423 | ||
426 | if (unlikely(local->sw_scanning)) { | 424 | if (unlikely(local->sw_scanning)) { |
427 | /* drop all the other packets during a software scan anyway */ | 425 | /* drop all the other packets during a software scan anyway */ |
428 | if (ieee80211_scan_rx(rx->sdata, skb, rx->status) | 426 | if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) |
429 | != RX_QUEUED) | ||
430 | dev_kfree_skb(skb); | 427 | dev_kfree_skb(skb); |
431 | return RX_QUEUED; | 428 | return RX_QUEUED; |
432 | } | 429 | } |
@@ -1620,7 +1617,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1620 | /* manage reordering buffer according to requested */ | 1617 | /* manage reordering buffer according to requested */ |
1621 | /* sequence number */ | 1618 | /* sequence number */ |
1622 | rcu_read_lock(); | 1619 | rcu_read_lock(); |
1623 | ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL, | 1620 | ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, |
1624 | start_seq_num, 1); | 1621 | start_seq_num, 1); |
1625 | rcu_read_unlock(); | 1622 | rcu_read_unlock(); |
1626 | return RX_DROP_UNUSABLE; | 1623 | return RX_DROP_UNUSABLE; |
@@ -1817,13 +1814,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
1817 | return RX_DROP_MONITOR; | 1814 | return RX_DROP_MONITOR; |
1818 | 1815 | ||
1819 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1816 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
1820 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); | 1817 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb); |
1821 | 1818 | ||
1822 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 1819 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
1823 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); | 1820 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb); |
1824 | 1821 | ||
1825 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 1822 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
1826 | return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | 1823 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); |
1827 | 1824 | ||
1828 | return RX_DROP_MONITOR; | 1825 | return RX_DROP_MONITOR; |
1829 | } | 1826 | } |
@@ -2114,9 +2111,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2114 | */ | 2111 | */ |
2115 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | 2112 | static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, |
2116 | struct sk_buff *skb, | 2113 | struct sk_buff *skb, |
2117 | struct ieee80211_rx_status *status, | ||
2118 | struct ieee80211_rate *rate) | 2114 | struct ieee80211_rate *rate) |
2119 | { | 2115 | { |
2116 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
2120 | struct ieee80211_local *local = hw_to_local(hw); | 2117 | struct ieee80211_local *local = hw_to_local(hw); |
2121 | struct ieee80211_sub_if_data *sdata; | 2118 | struct ieee80211_sub_if_data *sdata; |
2122 | struct ieee80211_hdr *hdr; | 2119 | struct ieee80211_hdr *hdr; |
@@ -2227,20 +2224,21 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | |||
2227 | { | 2224 | { |
2228 | struct ieee80211_supported_band *sband; | 2225 | struct ieee80211_supported_band *sband; |
2229 | struct ieee80211_rate *rate; | 2226 | struct ieee80211_rate *rate; |
2230 | struct ieee80211_rx_status status; | 2227 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; |
2228 | struct ieee80211_rx_status *status; | ||
2231 | 2229 | ||
2232 | if (!tid_agg_rx->reorder_buf[index]) | 2230 | if (!skb) |
2233 | goto no_frame; | 2231 | goto no_frame; |
2234 | 2232 | ||
2233 | status = IEEE80211_SKB_RXCB(skb); | ||
2234 | |||
2235 | /* release the reordered frames to stack */ | 2235 | /* release the reordered frames to stack */ |
2236 | memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); | 2236 | sband = hw->wiphy->bands[status->band]; |
2237 | sband = hw->wiphy->bands[status.band]; | 2237 | if (status->flag & RX_FLAG_HT) |
2238 | if (status.flag & RX_FLAG_HT) | ||
2239 | rate = sband->bitrates; /* TODO: HT rates */ | 2238 | rate = sband->bitrates; /* TODO: HT rates */ |
2240 | else | 2239 | else |
2241 | rate = &sband->bitrates[status.rate_idx]; | 2240 | rate = &sband->bitrates[status->rate_idx]; |
2242 | __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], | 2241 | __ieee80211_rx_handle_packet(hw, skb, rate); |
2243 | &status, rate); | ||
2244 | tid_agg_rx->stored_mpdu_num--; | 2242 | tid_agg_rx->stored_mpdu_num--; |
2245 | tid_agg_rx->reorder_buf[index] = NULL; | 2243 | tid_agg_rx->reorder_buf[index] = NULL; |
2246 | 2244 | ||
@@ -2265,7 +2263,6 @@ no_frame: | |||
2265 | static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | 2263 | static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, |
2266 | struct tid_ampdu_rx *tid_agg_rx, | 2264 | struct tid_ampdu_rx *tid_agg_rx, |
2267 | struct sk_buff *skb, | 2265 | struct sk_buff *skb, |
2268 | struct ieee80211_rx_status *rxstatus, | ||
2269 | u16 mpdu_seq_num, | 2266 | u16 mpdu_seq_num, |
2270 | int bar_req) | 2267 | int bar_req) |
2271 | { | 2268 | { |
@@ -2324,8 +2321,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2324 | /* put the frame in the reordering buffer */ | 2321 | /* put the frame in the reordering buffer */ |
2325 | tid_agg_rx->reorder_buf[index] = skb; | 2322 | tid_agg_rx->reorder_buf[index] = skb; |
2326 | tid_agg_rx->reorder_time[index] = jiffies; | 2323 | tid_agg_rx->reorder_time[index] = jiffies; |
2327 | memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus, | ||
2328 | sizeof(*rxstatus)); | ||
2329 | tid_agg_rx->stored_mpdu_num++; | 2324 | tid_agg_rx->stored_mpdu_num++; |
2330 | /* release the buffer until next missing frame */ | 2325 | /* release the buffer until next missing frame */ |
2331 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) | 2326 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) |
@@ -2374,8 +2369,7 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
2374 | } | 2369 | } |
2375 | 2370 | ||
2376 | static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | 2371 | static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, |
2377 | struct sk_buff *skb, | 2372 | struct sk_buff *skb) |
2378 | struct ieee80211_rx_status *status) | ||
2379 | { | 2373 | { |
2380 | struct ieee80211_hw *hw = &local->hw; | 2374 | struct ieee80211_hw *hw = &local->hw; |
2381 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 2375 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
@@ -2424,7 +2418,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2424 | 2418 | ||
2425 | /* according to mpdu sequence number deal with reordering buffer */ | 2419 | /* according to mpdu sequence number deal with reordering buffer */ |
2426 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 2420 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
2427 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status, | 2421 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, |
2428 | mpdu_seq_num, 0); | 2422 | mpdu_seq_num, 0); |
2429 | end_reorder: | 2423 | end_reorder: |
2430 | return ret; | 2424 | return ret; |
@@ -2434,12 +2428,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2434 | * This is the receive path handler. It is called by a low level driver when an | 2428 | * This is the receive path handler. It is called by a low level driver when an |
2435 | * 802.11 MPDU is received from the hardware. | 2429 | * 802.11 MPDU is received from the hardware. |
2436 | */ | 2430 | */ |
2437 | void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, | 2431 | void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) |
2438 | struct ieee80211_rx_status *status) | ||
2439 | { | 2432 | { |
2440 | struct ieee80211_local *local = hw_to_local(hw); | 2433 | struct ieee80211_local *local = hw_to_local(hw); |
2441 | struct ieee80211_rate *rate = NULL; | 2434 | struct ieee80211_rate *rate = NULL; |
2442 | struct ieee80211_supported_band *sband; | 2435 | struct ieee80211_supported_band *sband; |
2436 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
2443 | 2437 | ||
2444 | if (status->band < 0 || | 2438 | if (status->band < 0 || |
2445 | status->band >= IEEE80211_NUM_BANDS) { | 2439 | status->band >= IEEE80211_NUM_BANDS) { |
@@ -2482,7 +2476,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2482 | * if it was previously present. | 2476 | * if it was previously present. |
2483 | * Also, frames with less than 16 bytes are dropped. | 2477 | * Also, frames with less than 16 bytes are dropped. |
2484 | */ | 2478 | */ |
2485 | skb = ieee80211_rx_monitor(local, skb, status, rate); | 2479 | skb = ieee80211_rx_monitor(local, skb, rate); |
2486 | if (!skb) { | 2480 | if (!skb) { |
2487 | rcu_read_unlock(); | 2481 | rcu_read_unlock(); |
2488 | return; | 2482 | return; |
@@ -2500,8 +2494,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
2500 | * frames from other than operational channel), but that should not | 2494 | * frames from other than operational channel), but that should not |
2501 | * happen in normal networks. | 2495 | * happen in normal networks. |
2502 | */ | 2496 | */ |
2503 | if (!ieee80211_rx_reorder_ampdu(local, skb, status)) | 2497 | if (!ieee80211_rx_reorder_ampdu(local, skb)) |
2504 | __ieee80211_rx_handle_packet(hw, skb, status, rate); | 2498 | __ieee80211_rx_handle_packet(hw, skb, rate); |
2505 | 2499 | ||
2506 | rcu_read_unlock(); | 2500 | rcu_read_unlock(); |
2507 | } | 2501 | } |
@@ -2509,16 +2503,13 @@ EXPORT_SYMBOL(__ieee80211_rx); | |||
2509 | 2503 | ||
2510 | /* This is a version of the rx handler that can be called from hard irq | 2504 | /* This is a version of the rx handler that can be called from hard irq |
2511 | * context. Post the skb on the queue and schedule the tasklet */ | 2505 | * context. Post the skb on the queue and schedule the tasklet */ |
2512 | void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, | 2506 | void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) |
2513 | struct ieee80211_rx_status *status) | ||
2514 | { | 2507 | { |
2515 | struct ieee80211_local *local = hw_to_local(hw); | 2508 | struct ieee80211_local *local = hw_to_local(hw); |
2516 | 2509 | ||
2517 | BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); | 2510 | BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); |
2518 | 2511 | ||
2519 | skb->dev = local->mdev; | 2512 | skb->dev = local->mdev; |
2520 | /* copy status into skb->cb for use by tasklet */ | ||
2521 | memcpy(skb->cb, status, sizeof(*status)); | ||
2522 | skb->pkt_type = IEEE80211_RX_MSG; | 2513 | skb->pkt_type = IEEE80211_RX_MSG; |
2523 | skb_queue_tail(&local->skb_queue, skb); | 2514 | skb_queue_tail(&local->skb_queue, skb); |
2524 | tasklet_schedule(&local->tasklet); | 2515 | tasklet_schedule(&local->tasklet); |