diff options
author | David S. Miller <davem@davemloft.net> | 2011-03-04 15:48:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-04 15:48:25 -0500 |
commit | d72751ede1b9bf993d7bd3377305c8e9e36a3cc4 (patch) | |
tree | 27abaa49de7ff666dbf6bbcb0d7bae2b9f029a2d /net/mac80211 | |
parent | 0a0e9ae1bd788bc19adc4d4ae08c98b233697402 (diff) | |
parent | 85a7045a90052749885e166f40af5e9140032287 (diff) |
Merge branch 'for-davem' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/Kconfig | 2 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 68 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 35 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 33 | ||||
-rw-r--r-- | net/mac80211/ht.c | 5 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 7 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 23 | ||||
-rw-r--r-- | net/mac80211/rx.c | 15 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 4 | ||||
-rw-r--r-- | net/mac80211/status.c | 6 | ||||
-rw-r--r-- | net/mac80211/tx.c | 164 |
12 files changed, 225 insertions, 138 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index dbf5e4006bc1..513f85cc2ae1 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -78,7 +78,7 @@ config MAC80211_RC_DEFAULT | |||
78 | endif | 78 | endif |
79 | 79 | ||
80 | comment "Some wireless drivers require a rate control algorithm" | 80 | comment "Some wireless drivers require a rate control algorithm" |
81 | depends on MAC80211_HAS_RC=n | 81 | depends on MAC80211 && MAC80211_HAS_RC=n |
82 | 82 | ||
83 | config MAC80211_MESH | 83 | config MAC80211_MESH |
84 | bool "Enable mac80211 mesh networking (pre-802.11s) support" | 84 | bool "Enable mac80211 mesh networking (pre-802.11s) support" |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 140503d4c97a..7b701dcddb50 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -316,6 +316,17 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | |||
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) | ||
320 | { | ||
321 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | ||
322 | struct ieee80211_supported_band *sband; | ||
323 | sband = sta->local->hw.wiphy->bands[ | ||
324 | sta->local->hw.conf.channel->band]; | ||
325 | rate->legacy = sband->bitrates[idx].bitrate; | ||
326 | } else | ||
327 | rate->mcs = idx; | ||
328 | } | ||
329 | |||
319 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 330 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
320 | { | 331 | { |
321 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 332 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -330,6 +341,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
330 | STATION_INFO_TX_RETRIES | | 341 | STATION_INFO_TX_RETRIES | |
331 | STATION_INFO_TX_FAILED | | 342 | STATION_INFO_TX_FAILED | |
332 | STATION_INFO_TX_BITRATE | | 343 | STATION_INFO_TX_BITRATE | |
344 | STATION_INFO_RX_BITRATE | | ||
333 | STATION_INFO_RX_DROP_MISC; | 345 | STATION_INFO_RX_DROP_MISC; |
334 | 346 | ||
335 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 347 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
@@ -355,15 +367,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
355 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 367 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
356 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) | 368 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) |
357 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | 369 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
370 | rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx); | ||
358 | 371 | ||
359 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { | 372 | sinfo->rxrate.flags = 0; |
360 | struct ieee80211_supported_band *sband; | 373 | if (sta->last_rx_rate_flag & RX_FLAG_HT) |
361 | sband = sta->local->hw.wiphy->bands[ | 374 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; |
362 | sta->local->hw.conf.channel->band]; | 375 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
363 | sinfo->txrate.legacy = | 376 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
364 | sband->bitrates[sta->last_tx_rate.idx].bitrate; | 377 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
365 | } else | 378 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
366 | sinfo->txrate.mcs = sta->last_tx_rate.idx; | 379 | rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); |
367 | 380 | ||
368 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 381 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
369 | #ifdef CONFIG_MAC80211_MESH | 382 | #ifdef CONFIG_MAC80211_MESH |
@@ -1800,6 +1813,33 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1800 | 1813 | ||
1801 | *cookie = (unsigned long) skb; | 1814 | *cookie = (unsigned long) skb; |
1802 | 1815 | ||
1816 | if (is_offchan && local->ops->offchannel_tx) { | ||
1817 | int ret; | ||
1818 | |||
1819 | IEEE80211_SKB_CB(skb)->band = chan->band; | ||
1820 | |||
1821 | mutex_lock(&local->mtx); | ||
1822 | |||
1823 | if (local->hw_offchan_tx_cookie) { | ||
1824 | mutex_unlock(&local->mtx); | ||
1825 | return -EBUSY; | ||
1826 | } | ||
1827 | |||
1828 | /* TODO: bitrate control, TX processing? */ | ||
1829 | ret = drv_offchannel_tx(local, skb, chan, channel_type, wait); | ||
1830 | |||
1831 | if (ret == 0) | ||
1832 | local->hw_offchan_tx_cookie = *cookie; | ||
1833 | mutex_unlock(&local->mtx); | ||
1834 | |||
1835 | /* | ||
1836 | * Allow driver to return 1 to indicate it wants to have the | ||
1837 | * frame transmitted with a remain_on_channel + regular TX. | ||
1838 | */ | ||
1839 | if (ret != 1) | ||
1840 | return ret; | ||
1841 | } | ||
1842 | |||
1803 | if (is_offchan && local->ops->remain_on_channel) { | 1843 | if (is_offchan && local->ops->remain_on_channel) { |
1804 | unsigned int duration; | 1844 | unsigned int duration; |
1805 | int ret; | 1845 | int ret; |
@@ -1886,6 +1926,18 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | |||
1886 | 1926 | ||
1887 | mutex_lock(&local->mtx); | 1927 | mutex_lock(&local->mtx); |
1888 | 1928 | ||
1929 | if (local->ops->offchannel_tx_cancel_wait && | ||
1930 | local->hw_offchan_tx_cookie == cookie) { | ||
1931 | ret = drv_offchannel_tx_cancel_wait(local); | ||
1932 | |||
1933 | if (!ret) | ||
1934 | local->hw_offchan_tx_cookie = 0; | ||
1935 | |||
1936 | mutex_unlock(&local->mtx); | ||
1937 | |||
1938 | return ret; | ||
1939 | } | ||
1940 | |||
1889 | if (local->ops->cancel_remain_on_channel) { | 1941 | if (local->ops->cancel_remain_on_channel) { |
1890 | cookie ^= 2; | 1942 | cookie ^= 2; |
1891 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | 1943 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 78af32d4bc58..3729296f6f95 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -5,9 +5,9 @@ | |||
5 | #include "ieee80211_i.h" | 5 | #include "ieee80211_i.h" |
6 | #include "driver-trace.h" | 6 | #include "driver-trace.h" |
7 | 7 | ||
8 | static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | 8 | static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) |
9 | { | 9 | { |
10 | return local->ops->tx(&local->hw, skb); | 10 | local->ops->tx(&local->hw, skb); |
11 | } | 11 | } |
12 | 12 | ||
13 | static inline int drv_start(struct ieee80211_local *local) | 13 | static inline int drv_start(struct ieee80211_local *local) |
@@ -495,4 +495,35 @@ static inline int drv_cancel_remain_on_channel(struct ieee80211_local *local) | |||
495 | return ret; | 495 | return ret; |
496 | } | 496 | } |
497 | 497 | ||
498 | static inline int drv_offchannel_tx(struct ieee80211_local *local, | ||
499 | struct sk_buff *skb, | ||
500 | struct ieee80211_channel *chan, | ||
501 | enum nl80211_channel_type channel_type, | ||
502 | unsigned int wait) | ||
503 | { | ||
504 | int ret; | ||
505 | |||
506 | might_sleep(); | ||
507 | |||
508 | trace_drv_offchannel_tx(local, skb, chan, channel_type, wait); | ||
509 | ret = local->ops->offchannel_tx(&local->hw, skb, chan, | ||
510 | channel_type, wait); | ||
511 | trace_drv_return_int(local, ret); | ||
512 | |||
513 | return ret; | ||
514 | } | ||
515 | |||
516 | static inline int drv_offchannel_tx_cancel_wait(struct ieee80211_local *local) | ||
517 | { | ||
518 | int ret; | ||
519 | |||
520 | might_sleep(); | ||
521 | |||
522 | trace_drv_offchannel_tx_cancel_wait(local); | ||
523 | ret = local->ops->offchannel_tx_cancel_wait(&local->hw); | ||
524 | trace_drv_return_int(local, ret); | ||
525 | |||
526 | return ret; | ||
527 | } | ||
528 | |||
498 | #endif /* __MAC80211_DRIVER_OPS */ | 529 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index e5cce19a7d65..520fe2444893 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -884,6 +884,39 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel, | |||
884 | TP_ARGS(local) | 884 | TP_ARGS(local) |
885 | ); | 885 | ); |
886 | 886 | ||
887 | TRACE_EVENT(drv_offchannel_tx, | ||
888 | TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb, | ||
889 | struct ieee80211_channel *chan, | ||
890 | enum nl80211_channel_type channel_type, | ||
891 | unsigned int wait), | ||
892 | |||
893 | TP_ARGS(local, skb, chan, channel_type, wait), | ||
894 | |||
895 | TP_STRUCT__entry( | ||
896 | LOCAL_ENTRY | ||
897 | __field(int, center_freq) | ||
898 | __field(int, channel_type) | ||
899 | __field(unsigned int, wait) | ||
900 | ), | ||
901 | |||
902 | TP_fast_assign( | ||
903 | LOCAL_ASSIGN; | ||
904 | __entry->center_freq = chan->center_freq; | ||
905 | __entry->channel_type = channel_type; | ||
906 | __entry->wait = wait; | ||
907 | ), | ||
908 | |||
909 | TP_printk( | ||
910 | LOCAL_PR_FMT " freq:%dMHz, wait:%dms", | ||
911 | LOCAL_PR_ARG, __entry->center_freq, __entry->wait | ||
912 | ) | ||
913 | ); | ||
914 | |||
915 | DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, | ||
916 | TP_PROTO(struct ieee80211_local *local), | ||
917 | TP_ARGS(local) | ||
918 | ); | ||
919 | |||
887 | /* | 920 | /* |
888 | * Tracing for API calls that drivers call. | 921 | * Tracing for API calls that drivers call. |
889 | */ | 922 | */ |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 75d679d75e63..b9e4b9bd2179 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -66,6 +66,9 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
66 | /* own MCS TX capabilities */ | 66 | /* own MCS TX capabilities */ |
67 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 67 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; |
68 | 68 | ||
69 | /* Copy peer MCS TX capabilities, the driver might need them. */ | ||
70 | ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params; | ||
71 | |||
69 | /* can we TX with MCS rates? */ | 72 | /* can we TX with MCS rates? */ |
70 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | 73 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) |
71 | return; | 74 | return; |
@@ -79,7 +82,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | |||
79 | max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; | 82 | max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; |
80 | 83 | ||
81 | /* | 84 | /* |
82 | * 802.11n D5.0 20.3.5 / 20.6 says: | 85 | * 802.11n-2009 20.3.5 / 20.6 says: |
83 | * - indices 0 to 7 and 32 are single spatial stream | 86 | * - indices 0 to 7 and 32 are single spatial stream |
84 | * - 8 to 31 are multiple spatial streams using equal modulation | 87 | * - 8 to 31 are multiple spatial streams using equal modulation |
85 | * [8..15 for two streams, 16..23 for three and 24..31 for four] | 88 | * [8..15 for two streams, 16..23 for three and 24..31 for four] |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a42aa61269ea..3e81af1fce58 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | 31 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) |
32 | 32 | ||
33 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 33 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
34 | #define IEEE80211_IBSS_MERGE_DELAY 0x400000 | ||
35 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 34 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
36 | 35 | ||
37 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 36 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
@@ -355,7 +354,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
355 | if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) | 354 | if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) |
356 | goto put_bss; | 355 | goto put_bss; |
357 | 356 | ||
358 | if (rx_status->flag & RX_FLAG_TSFT) { | 357 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { |
359 | /* | 358 | /* |
360 | * For correct IBSS merging we need mactime; since mactime is | 359 | * For correct IBSS merging we need mactime; since mactime is |
361 | * defined as the time the first data symbol of the frame hits | 360 | * defined as the time the first data symbol of the frame hits |
@@ -397,10 +396,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
397 | jiffies); | 396 | jiffies); |
398 | #endif | 397 | #endif |
399 | 398 | ||
400 | /* give slow hardware some time to do the TSF sync */ | ||
401 | if (rx_timestamp < IEEE80211_IBSS_MERGE_DELAY) | ||
402 | goto put_bss; | ||
403 | |||
404 | if (beacon_timestamp > rx_timestamp) { | 399 | if (beacon_timestamp > rx_timestamp) { |
405 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 400 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
406 | printk(KERN_DEBUG "%s: beacon TSF higher than " | 401 | printk(KERN_DEBUG "%s: beacon TSF higher than " |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0a570a111a84..a40401701424 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -957,6 +957,7 @@ struct ieee80211_local { | |||
957 | unsigned int hw_roc_duration; | 957 | unsigned int hw_roc_duration; |
958 | u32 hw_roc_cookie; | 958 | u32 hw_roc_cookie; |
959 | bool hw_roc_for_tx; | 959 | bool hw_roc_for_tx; |
960 | unsigned long hw_offchan_tx_cookie; | ||
960 | 961 | ||
961 | /* dummy netdev for use w/ NAPI */ | 962 | /* dummy netdev for use w/ NAPI */ |
962 | struct net_device napi_dev; | 963 | struct net_device napi_dev; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7b3f9df725bd..cc984bd861cf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -145,6 +145,9 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | |||
145 | { | 145 | { |
146 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 146 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
147 | 147 | ||
148 | if (unlikely(!sdata->u.mgd.associated)) | ||
149 | return; | ||
150 | |||
148 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 151 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
149 | return; | 152 | return; |
150 | 153 | ||
@@ -738,9 +741,19 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
738 | return; | 741 | return; |
739 | 742 | ||
740 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 743 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
741 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) | 744 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { |
745 | netif_tx_stop_all_queues(sdata->dev); | ||
746 | /* | ||
747 | * Flush all the frames queued in the driver before | ||
748 | * going to power save | ||
749 | */ | ||
750 | drv_flush(local, false); | ||
742 | ieee80211_send_nullfunc(local, sdata, 1); | 751 | ieee80211_send_nullfunc(local, sdata, 1); |
743 | 752 | ||
753 | /* Flush once again to get the tx status of nullfunc frame */ | ||
754 | drv_flush(local, false); | ||
755 | } | ||
756 | |||
744 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | 757 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && |
745 | (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) || | 758 | (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) || |
746 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { | 759 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { |
@@ -748,6 +761,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
748 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 761 | local->hw.conf.flags |= IEEE80211_CONF_PS; |
749 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 762 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
750 | } | 763 | } |
764 | |||
765 | netif_tx_start_all_queues(sdata->dev); | ||
751 | } | 766 | } |
752 | 767 | ||
753 | void ieee80211_dynamic_ps_timer(unsigned long data) | 768 | void ieee80211_dynamic_ps_timer(unsigned long data) |
@@ -1071,12 +1086,6 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1071 | if (is_multicast_ether_addr(hdr->addr1)) | 1086 | if (is_multicast_ether_addr(hdr->addr1)) |
1072 | return; | 1087 | return; |
1073 | 1088 | ||
1074 | /* | ||
1075 | * In case we receive frames after disassociation. | ||
1076 | */ | ||
1077 | if (!sdata->u.mgd.associated) | ||
1078 | return; | ||
1079 | |||
1080 | ieee80211_sta_reset_conn_monitor(sdata); | 1089 | ieee80211_sta_reset_conn_monitor(sdata); |
1081 | } | 1090 | } |
1082 | 1091 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f502634d43af..5c1930ba8ebe 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -77,7 +77,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, | |||
77 | /* always present fields */ | 77 | /* always present fields */ |
78 | len = sizeof(struct ieee80211_radiotap_header) + 9; | 78 | len = sizeof(struct ieee80211_radiotap_header) + 9; |
79 | 79 | ||
80 | if (status->flag & RX_FLAG_TSFT) | 80 | if (status->flag & RX_FLAG_MACTIME_MPDU) |
81 | len += 8; | 81 | len += 8; |
82 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 82 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
83 | len += 1; | 83 | len += 1; |
@@ -123,7 +123,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
123 | /* the order of the following fields is important */ | 123 | /* the order of the following fields is important */ |
124 | 124 | ||
125 | /* IEEE80211_RADIOTAP_TSFT */ | 125 | /* IEEE80211_RADIOTAP_TSFT */ |
126 | if (status->flag & RX_FLAG_TSFT) { | 126 | if (status->flag & RX_FLAG_MACTIME_MPDU) { |
127 | put_unaligned_le64(status->mactime, pos); | 127 | put_unaligned_le64(status->mactime, pos); |
128 | rthdr->it_present |= | 128 | rthdr->it_present |= |
129 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | 129 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); |
@@ -1156,14 +1156,23 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1156 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1156 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
1157 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | 1157 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, |
1158 | NL80211_IFTYPE_ADHOC); | 1158 | NL80211_IFTYPE_ADHOC); |
1159 | if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) | 1159 | if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) { |
1160 | sta->last_rx = jiffies; | 1160 | sta->last_rx = jiffies; |
1161 | if (ieee80211_is_data(hdr->frame_control)) { | ||
1162 | sta->last_rx_rate_idx = status->rate_idx; | ||
1163 | sta->last_rx_rate_flag = status->flag; | ||
1164 | } | ||
1165 | } | ||
1161 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1166 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
1162 | /* | 1167 | /* |
1163 | * Mesh beacons will update last_rx when if they are found to | 1168 | * Mesh beacons will update last_rx when if they are found to |
1164 | * match the current local configuration when processed. | 1169 | * match the current local configuration when processed. |
1165 | */ | 1170 | */ |
1166 | sta->last_rx = jiffies; | 1171 | sta->last_rx = jiffies; |
1172 | if (ieee80211_is_data(hdr->frame_control)) { | ||
1173 | sta->last_rx_rate_idx = status->rate_idx; | ||
1174 | sta->last_rx_rate_flag = status->flag; | ||
1175 | } | ||
1167 | } | 1176 | } |
1168 | 1177 | ||
1169 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | 1178 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ca0b69060ef7..57681149e37f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -209,6 +209,8 @@ enum plink_state { | |||
209 | * @rate_ctrl_priv: rate control private per-STA pointer | 209 | * @rate_ctrl_priv: rate control private per-STA pointer |
210 | * @last_tx_rate: rate used for last transmit, to report to userspace as | 210 | * @last_tx_rate: rate used for last transmit, to report to userspace as |
211 | * "the" transmit rate | 211 | * "the" transmit rate |
212 | * @last_rx_rate_idx: rx status rate index of the last data packet | ||
213 | * @last_rx_rate_flag: rx status flag of the last data packet | ||
212 | * @lock: used for locking all fields that require locking, see comments | 214 | * @lock: used for locking all fields that require locking, see comments |
213 | * in the header file. | 215 | * in the header file. |
214 | * @flaglock: spinlock for flags accesses | 216 | * @flaglock: spinlock for flags accesses |
@@ -311,6 +313,8 @@ struct sta_info { | |||
311 | unsigned long tx_bytes; | 313 | unsigned long tx_bytes; |
312 | unsigned long tx_fragments; | 314 | unsigned long tx_fragments; |
313 | struct ieee80211_tx_rate last_tx_rate; | 315 | struct ieee80211_tx_rate last_tx_rate; |
316 | int last_rx_rate_idx; | ||
317 | int last_rx_rate_flag; | ||
314 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; | 318 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; |
315 | 319 | ||
316 | /* | 320 | /* |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 010a559bd872..b936dd29e92b 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -318,8 +318,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
318 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 318 | if (info->flags & IEEE80211_TX_STAT_ACK) { |
319 | local->ps_sdata->u.mgd.flags |= | 319 | local->ps_sdata->u.mgd.flags |= |
320 | IEEE80211_STA_NULLFUNC_ACKED; | 320 | IEEE80211_STA_NULLFUNC_ACKED; |
321 | ieee80211_queue_work(&local->hw, | ||
322 | &local->dynamic_ps_enable_work); | ||
323 | } else | 321 | } else |
324 | mod_timer(&local->dynamic_ps_timer, jiffies + | 322 | mod_timer(&local->dynamic_ps_timer, jiffies + |
325 | msecs_to_jiffies(10)); | 323 | msecs_to_jiffies(10)); |
@@ -343,6 +341,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
343 | cookie = local->hw_roc_cookie ^ 2; | 341 | cookie = local->hw_roc_cookie ^ 2; |
344 | local->hw_roc_skb_for_status = NULL; | 342 | local->hw_roc_skb_for_status = NULL; |
345 | } | 343 | } |
344 | |||
345 | if (cookie == local->hw_offchan_tx_cookie) | ||
346 | local->hw_offchan_tx_cookie = 0; | ||
347 | |||
346 | cfg80211_mgmt_tx_status( | 348 | cfg80211_mgmt_tx_status( |
347 | skb->dev, cookie, skb->data, skb->len, | 349 | skb->dev, cookie, skb->data, skb->len, |
348 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | 350 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 34edf7f22b0e..081dcaf6577b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -33,10 +33,6 @@ | |||
33 | #include "wme.h" | 33 | #include "wme.h" |
34 | #include "rate.h" | 34 | #include "rate.h" |
35 | 35 | ||
36 | #define IEEE80211_TX_OK 0 | ||
37 | #define IEEE80211_TX_AGAIN 1 | ||
38 | #define IEEE80211_TX_PENDING 2 | ||
39 | |||
40 | /* misc utils */ | 36 | /* misc utils */ |
41 | 37 | ||
42 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | 38 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, |
@@ -1285,16 +1281,17 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1285 | return TX_CONTINUE; | 1281 | return TX_CONTINUE; |
1286 | } | 1282 | } |
1287 | 1283 | ||
1288 | static int __ieee80211_tx(struct ieee80211_local *local, | 1284 | /* |
1289 | struct sk_buff **skbp, | 1285 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1290 | struct sta_info *sta, | 1286 | */ |
1291 | bool txpending) | 1287 | static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, |
1288 | struct sta_info *sta, bool txpending) | ||
1292 | { | 1289 | { |
1293 | struct sk_buff *skb = *skbp, *next; | 1290 | struct sk_buff *skb = *skbp, *next; |
1294 | struct ieee80211_tx_info *info; | 1291 | struct ieee80211_tx_info *info; |
1295 | struct ieee80211_sub_if_data *sdata; | 1292 | struct ieee80211_sub_if_data *sdata; |
1296 | unsigned long flags; | 1293 | unsigned long flags; |
1297 | int ret, len; | 1294 | int len; |
1298 | bool fragm = false; | 1295 | bool fragm = false; |
1299 | 1296 | ||
1300 | while (skb) { | 1297 | while (skb) { |
@@ -1302,13 +1299,37 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1302 | __le16 fc; | 1299 | __le16 fc; |
1303 | 1300 | ||
1304 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1301 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1305 | ret = IEEE80211_TX_OK; | ||
1306 | if (local->queue_stop_reasons[q] || | 1302 | if (local->queue_stop_reasons[q] || |
1307 | (!txpending && !skb_queue_empty(&local->pending[q]))) | 1303 | (!txpending && !skb_queue_empty(&local->pending[q]))) { |
1308 | ret = IEEE80211_TX_PENDING; | 1304 | /* |
1305 | * Since queue is stopped, queue up frames for later | ||
1306 | * transmission from the tx-pending tasklet when the | ||
1307 | * queue is woken again. | ||
1308 | */ | ||
1309 | |||
1310 | do { | ||
1311 | next = skb->next; | ||
1312 | skb->next = NULL; | ||
1313 | /* | ||
1314 | * NB: If txpending is true, next must already | ||
1315 | * be NULL since we must've gone through this | ||
1316 | * loop before already; therefore we can just | ||
1317 | * queue the frame to the head without worrying | ||
1318 | * about reordering of fragments. | ||
1319 | */ | ||
1320 | if (unlikely(txpending)) | ||
1321 | __skb_queue_head(&local->pending[q], | ||
1322 | skb); | ||
1323 | else | ||
1324 | __skb_queue_tail(&local->pending[q], | ||
1325 | skb); | ||
1326 | } while ((skb = next)); | ||
1327 | |||
1328 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
1329 | flags); | ||
1330 | return false; | ||
1331 | } | ||
1309 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 1332 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
1310 | if (ret != IEEE80211_TX_OK) | ||
1311 | return ret; | ||
1312 | 1333 | ||
1313 | info = IEEE80211_SKB_CB(skb); | 1334 | info = IEEE80211_SKB_CB(skb); |
1314 | 1335 | ||
@@ -1343,15 +1364,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1343 | info->control.sta = NULL; | 1364 | info->control.sta = NULL; |
1344 | 1365 | ||
1345 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | 1366 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; |
1346 | ret = drv_tx(local, skb); | 1367 | drv_tx(local, skb); |
1347 | if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { | ||
1348 | dev_kfree_skb(skb); | ||
1349 | ret = NETDEV_TX_OK; | ||
1350 | } | ||
1351 | if (ret != NETDEV_TX_OK) { | ||
1352 | info->control.vif = &sdata->vif; | ||
1353 | return IEEE80211_TX_AGAIN; | ||
1354 | } | ||
1355 | 1368 | ||
1356 | ieee80211_tpt_led_trig_tx(local, fc, len); | 1369 | ieee80211_tpt_led_trig_tx(local, fc, len); |
1357 | *skbp = skb = next; | 1370 | *skbp = skb = next; |
@@ -1359,7 +1372,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1359 | fragm = true; | 1372 | fragm = true; |
1360 | } | 1373 | } |
1361 | 1374 | ||
1362 | return IEEE80211_TX_OK; | 1375 | return true; |
1363 | } | 1376 | } |
1364 | 1377 | ||
1365 | /* | 1378 | /* |
@@ -1419,23 +1432,24 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1419 | return 0; | 1432 | return 0; |
1420 | } | 1433 | } |
1421 | 1434 | ||
1422 | static void ieee80211_tx(struct ieee80211_sub_if_data *sdata, | 1435 | /* |
1436 | * Returns false if the frame couldn't be transmitted but was queued instead. | ||
1437 | */ | ||
1438 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | ||
1423 | struct sk_buff *skb, bool txpending) | 1439 | struct sk_buff *skb, bool txpending) |
1424 | { | 1440 | { |
1425 | struct ieee80211_local *local = sdata->local; | 1441 | struct ieee80211_local *local = sdata->local; |
1426 | struct ieee80211_tx_data tx; | 1442 | struct ieee80211_tx_data tx; |
1427 | ieee80211_tx_result res_prepare; | 1443 | ieee80211_tx_result res_prepare; |
1428 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1444 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1429 | struct sk_buff *next; | ||
1430 | unsigned long flags; | ||
1431 | int ret, retries; | ||
1432 | u16 queue; | 1445 | u16 queue; |
1446 | bool result = true; | ||
1433 | 1447 | ||
1434 | queue = skb_get_queue_mapping(skb); | 1448 | queue = skb_get_queue_mapping(skb); |
1435 | 1449 | ||
1436 | if (unlikely(skb->len < 10)) { | 1450 | if (unlikely(skb->len < 10)) { |
1437 | dev_kfree_skb(skb); | 1451 | dev_kfree_skb(skb); |
1438 | return; | 1452 | return true; |
1439 | } | 1453 | } |
1440 | 1454 | ||
1441 | rcu_read_lock(); | 1455 | rcu_read_lock(); |
@@ -1445,85 +1459,19 @@ static void ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1445 | 1459 | ||
1446 | if (unlikely(res_prepare == TX_DROP)) { | 1460 | if (unlikely(res_prepare == TX_DROP)) { |
1447 | dev_kfree_skb(skb); | 1461 | dev_kfree_skb(skb); |
1448 | rcu_read_unlock(); | 1462 | goto out; |
1449 | return; | ||
1450 | } else if (unlikely(res_prepare == TX_QUEUED)) { | 1463 | } else if (unlikely(res_prepare == TX_QUEUED)) { |
1451 | rcu_read_unlock(); | 1464 | goto out; |
1452 | return; | ||
1453 | } | 1465 | } |
1454 | 1466 | ||
1455 | tx.channel = local->hw.conf.channel; | 1467 | tx.channel = local->hw.conf.channel; |
1456 | info->band = tx.channel->band; | 1468 | info->band = tx.channel->band; |
1457 | 1469 | ||
1458 | if (invoke_tx_handlers(&tx)) | 1470 | if (!invoke_tx_handlers(&tx)) |
1459 | goto out; | 1471 | result = __ieee80211_tx(local, &tx.skb, tx.sta, txpending); |
1460 | |||
1461 | retries = 0; | ||
1462 | retry: | ||
1463 | ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending); | ||
1464 | switch (ret) { | ||
1465 | case IEEE80211_TX_OK: | ||
1466 | break; | ||
1467 | case IEEE80211_TX_AGAIN: | ||
1468 | /* | ||
1469 | * Since there are no fragmented frames on A-MPDU | ||
1470 | * queues, there's no reason for a driver to reject | ||
1471 | * a frame there, warn and drop it. | ||
1472 | */ | ||
1473 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) | ||
1474 | goto drop; | ||
1475 | /* fall through */ | ||
1476 | case IEEE80211_TX_PENDING: | ||
1477 | skb = tx.skb; | ||
1478 | |||
1479 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
1480 | |||
1481 | if (local->queue_stop_reasons[queue] || | ||
1482 | !skb_queue_empty(&local->pending[queue])) { | ||
1483 | /* | ||
1484 | * if queue is stopped, queue up frames for later | ||
1485 | * transmission from the tasklet | ||
1486 | */ | ||
1487 | do { | ||
1488 | next = skb->next; | ||
1489 | skb->next = NULL; | ||
1490 | if (unlikely(txpending)) | ||
1491 | __skb_queue_head(&local->pending[queue], | ||
1492 | skb); | ||
1493 | else | ||
1494 | __skb_queue_tail(&local->pending[queue], | ||
1495 | skb); | ||
1496 | } while ((skb = next)); | ||
1497 | |||
1498 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
1499 | flags); | ||
1500 | } else { | ||
1501 | /* | ||
1502 | * otherwise retry, but this is a race condition or | ||
1503 | * a driver bug (which we warn about if it persists) | ||
1504 | */ | ||
1505 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
1506 | flags); | ||
1507 | |||
1508 | retries++; | ||
1509 | if (WARN(retries > 10, "tx refused but queue active\n")) | ||
1510 | goto drop; | ||
1511 | goto retry; | ||
1512 | } | ||
1513 | } | ||
1514 | out: | 1472 | out: |
1515 | rcu_read_unlock(); | 1473 | rcu_read_unlock(); |
1516 | return; | 1474 | return result; |
1517 | |||
1518 | drop: | ||
1519 | rcu_read_unlock(); | ||
1520 | |||
1521 | skb = tx.skb; | ||
1522 | while (skb) { | ||
1523 | next = skb->next; | ||
1524 | dev_kfree_skb(skb); | ||
1525 | skb = next; | ||
1526 | } | ||
1527 | } | 1475 | } |
1528 | 1476 | ||
1529 | /* device xmit handlers */ | 1477 | /* device xmit handlers */ |
@@ -2070,6 +2018,11 @@ void ieee80211_clear_tx_pending(struct ieee80211_local *local) | |||
2070 | skb_queue_purge(&local->pending[i]); | 2018 | skb_queue_purge(&local->pending[i]); |
2071 | } | 2019 | } |
2072 | 2020 | ||
2021 | /* | ||
2022 | * Returns false if the frame couldn't be transmitted but was queued instead, | ||
2023 | * which in this case means re-queued -- take as an indication to stop sending | ||
2024 | * more pending frames. | ||
2025 | */ | ||
2073 | static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | 2026 | static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, |
2074 | struct sk_buff *skb) | 2027 | struct sk_buff *skb) |
2075 | { | 2028 | { |
@@ -2077,20 +2030,17 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2077 | struct ieee80211_sub_if_data *sdata; | 2030 | struct ieee80211_sub_if_data *sdata; |
2078 | struct sta_info *sta; | 2031 | struct sta_info *sta; |
2079 | struct ieee80211_hdr *hdr; | 2032 | struct ieee80211_hdr *hdr; |
2080 | int ret; | 2033 | bool result; |
2081 | bool result = true; | ||
2082 | 2034 | ||
2083 | sdata = vif_to_sdata(info->control.vif); | 2035 | sdata = vif_to_sdata(info->control.vif); |
2084 | 2036 | ||
2085 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { | 2037 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { |
2086 | ieee80211_tx(sdata, skb, true); | 2038 | result = ieee80211_tx(sdata, skb, true); |
2087 | } else { | 2039 | } else { |
2088 | hdr = (struct ieee80211_hdr *)skb->data; | 2040 | hdr = (struct ieee80211_hdr *)skb->data; |
2089 | sta = sta_info_get(sdata, hdr->addr1); | 2041 | sta = sta_info_get(sdata, hdr->addr1); |
2090 | 2042 | ||
2091 | ret = __ieee80211_tx(local, &skb, sta, true); | 2043 | result = __ieee80211_tx(local, &skb, sta, true); |
2092 | if (ret != IEEE80211_TX_OK) | ||
2093 | result = false; | ||
2094 | } | 2044 | } |
2095 | 2045 | ||
2096 | return result; | 2046 | return result; |
@@ -2132,8 +2082,6 @@ void ieee80211_tx_pending(unsigned long data) | |||
2132 | flags); | 2082 | flags); |
2133 | 2083 | ||
2134 | txok = ieee80211_tx_pending_skb(local, skb); | 2084 | txok = ieee80211_tx_pending_skb(local, skb); |
2135 | if (!txok) | ||
2136 | __skb_queue_head(&local->pending[i], skb); | ||
2137 | spin_lock_irqsave(&local->queue_stop_reason_lock, | 2085 | spin_lock_irqsave(&local->queue_stop_reason_lock, |
2138 | flags); | 2086 | flags); |
2139 | if (!txok) | 2087 | if (!txok) |