aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-11-06 08:13:34 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-09 16:14:09 -0500
commita729cff8ad5120d0d5172ec28a3843d1cb458f79 (patch)
tree96e85c0805050ba03a2df2a4278640da8f0454c5
parent1f074bd8eb7a4a210a5119cd7220f89da6c7a2c3 (diff)
mac80211: implement wifi TX status
Implement the socket wifi TX status error queue reflection in mac80211. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/net/mac80211.h5
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/main.c18
-rw-r--r--net/mac80211/status.c38
-rw-r--r--net/mac80211/tx.c56
5 files changed, 115 insertions, 6 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b9b9c9452131..2714646b298f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -518,7 +518,7 @@ struct ieee80211_tx_rate {
518 * @flags: transmit info flags, defined above 518 * @flags: transmit info flags, defined above
519 * @band: the band to transmit on (use for checking for races) 519 * @band: the band to transmit on (use for checking for races)
520 * @antenna_sel_tx: antenna to use, 0 for automatic diversity 520 * @antenna_sel_tx: antenna to use, 0 for automatic diversity
521 * @pad: padding, ignore 521 * @ack_frame_id: internal frame ID for TX status, used internally
522 * @control: union for control data 522 * @control: union for control data
523 * @status: union for status data 523 * @status: union for status data
524 * @driver_data: array of driver_data pointers 524 * @driver_data: array of driver_data pointers
@@ -535,8 +535,7 @@ struct ieee80211_tx_info {
535 535
536 u8 antenna_sel_tx; 536 u8 antenna_sel_tx;
537 537
538 /* 2 byte hole */ 538 u16 ack_frame_id;
539 u8 pad[2];
540 539
541 union { 540 union {
542 struct { 541 struct {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4bef6eca1722..76e656bf78f9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -24,6 +24,7 @@
24#include <linux/spinlock.h> 24#include <linux/spinlock.h>
25#include <linux/etherdevice.h> 25#include <linux/etherdevice.h>
26#include <linux/leds.h> 26#include <linux/leds.h>
27#include <linux/idr.h>
27#include <net/ieee80211_radiotap.h> 28#include <net/ieee80211_radiotap.h>
28#include <net/cfg80211.h> 29#include <net/cfg80211.h>
29#include <net/mac80211.h> 30#include <net/mac80211.h>
@@ -1017,6 +1018,9 @@ struct ieee80211_local {
1017 u32 hw_roc_cookie; 1018 u32 hw_roc_cookie;
1018 bool hw_roc_for_tx; 1019 bool hw_roc_for_tx;
1019 1020
1021 struct idr ack_status_frames;
1022 spinlock_t ack_status_lock;
1023
1020 /* dummy netdev for use w/ NAPI */ 1024 /* dummy netdev for use w/ NAPI */
1021 struct net_device napi_dev; 1025 struct net_device napi_dev;
1022 1026
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8e9327bca910..e323d4e6647b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -596,6 +596,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
596 WIPHY_FLAG_4ADDR_STATION | 596 WIPHY_FLAG_4ADDR_STATION |
597 WIPHY_FLAG_REPORTS_OBSS; 597 WIPHY_FLAG_REPORTS_OBSS;
598 598
599 wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
600
599 if (!ops->set_key) 601 if (!ops->set_key)
600 wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 602 wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
601 603
@@ -669,6 +671,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
669 INIT_WORK(&local->sched_scan_stopped_work, 671 INIT_WORK(&local->sched_scan_stopped_work,
670 ieee80211_sched_scan_stopped_work); 672 ieee80211_sched_scan_stopped_work);
671 673
674 spin_lock_init(&local->ack_status_lock);
675 idr_init(&local->ack_status_frames);
676 /* preallocate at least one entry */
677 idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
678
672 sta_info_init(local); 679 sta_info_init(local);
673 680
674 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { 681 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -1044,6 +1051,13 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
1044} 1051}
1045EXPORT_SYMBOL(ieee80211_unregister_hw); 1052EXPORT_SYMBOL(ieee80211_unregister_hw);
1046 1053
1054static int ieee80211_free_ack_frame(int id, void *p, void *data)
1055{
1056 WARN_ONCE(1, "Have pending ack frames!\n");
1057 kfree_skb(p);
1058 return 0;
1059}
1060
1047void ieee80211_free_hw(struct ieee80211_hw *hw) 1061void ieee80211_free_hw(struct ieee80211_hw *hw)
1048{ 1062{
1049 struct ieee80211_local *local = hw_to_local(hw); 1063 struct ieee80211_local *local = hw_to_local(hw);
@@ -1054,6 +1068,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
1054 if (local->wiphy_ciphers_allocated) 1068 if (local->wiphy_ciphers_allocated)
1055 kfree(local->hw.wiphy->cipher_suites); 1069 kfree(local->hw.wiphy->cipher_suites);
1056 1070
1071 idr_for_each(&local->ack_status_frames,
1072 ieee80211_free_ack_frame, NULL);
1073 idr_destroy(&local->ack_status_frames);
1074
1057 wiphy_free(local->hw.wiphy); 1075 wiphy_free(local->hw.wiphy);
1058} 1076}
1059EXPORT_SYMBOL(ieee80211_free_hw); 1077EXPORT_SYMBOL(ieee80211_free_hw);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 94702f103cfc..83b800d17a9a 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -548,6 +548,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
548 } 548 }
549 } 549 }
550 550
551 if (unlikely(info->ack_frame_id)) {
552 struct sk_buff *ack_skb;
553 unsigned long flags;
554
555 spin_lock_irqsave(&local->ack_status_lock, flags);
556 ack_skb = idr_find(&local->ack_status_frames,
557 info->ack_frame_id);
558 if (ack_skb)
559 idr_remove(&local->ack_status_frames,
560 info->ack_frame_id);
561 spin_unlock_irqrestore(&local->ack_status_lock, flags);
562
563 /* consumes ack_skb */
564 if (ack_skb)
565 skb_complete_wifi_ack(ack_skb,
566 info->flags & IEEE80211_TX_STAT_ACK);
567 }
568
551 /* this was a transmitted frame, but now we want to reuse it */ 569 /* this was a transmitted frame, but now we want to reuse it */
552 skb_orphan(skb); 570 skb_orphan(skb);
553 571
@@ -621,6 +639,26 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
621 639
622void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) 640void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
623{ 641{
642 struct ieee80211_local *local = hw_to_local(hw);
643 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
644
645 if (unlikely(info->ack_frame_id)) {
646 struct sk_buff *ack_skb;
647 unsigned long flags;
648
649 spin_lock_irqsave(&local->ack_status_lock, flags);
650 ack_skb = idr_find(&local->ack_status_frames,
651 info->ack_frame_id);
652 if (ack_skb)
653 idr_remove(&local->ack_status_frames,
654 info->ack_frame_id);
655 spin_unlock_irqrestore(&local->ack_status_lock, flags);
656
657 /* consumes ack_skb */
658 if (ack_skb)
659 dev_kfree_skb_any(ack_skb);
660 }
661
624 dev_kfree_skb_any(skb); 662 dev_kfree_skb_any(skb);
625} 663}
626EXPORT_SYMBOL(ieee80211_free_txskb); 664EXPORT_SYMBOL(ieee80211_free_txskb);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a543d26058db..ab6cb56bc74d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1684,8 +1684,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1684 int nh_pos, h_pos; 1684 int nh_pos, h_pos;
1685 struct sta_info *sta = NULL; 1685 struct sta_info *sta = NULL;
1686 bool wme_sta = false, authorized = false, tdls_auth = false; 1686 bool wme_sta = false, authorized = false, tdls_auth = false;
1687 struct sk_buff *tmp_skb;
1688 bool tdls_direct = false; 1687 bool tdls_direct = false;
1688 bool multicast;
1689 u32 info_flags = 0;
1690 u16 info_id = 0;
1689 1691
1690 if (unlikely(skb->len < ETH_HLEN)) { 1692 if (unlikely(skb->len < ETH_HLEN)) {
1691 ret = NETDEV_TX_OK; 1693 ret = NETDEV_TX_OK;
@@ -1872,7 +1874,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1872 * if it is a multicast address (which can only happen 1874 * if it is a multicast address (which can only happen
1873 * in AP mode) 1875 * in AP mode)
1874 */ 1876 */
1875 if (!is_multicast_ether_addr(hdr.addr1)) { 1877 multicast = is_multicast_ether_addr(hdr.addr1);
1878 if (!multicast) {
1876 rcu_read_lock(); 1879 rcu_read_lock();
1877 sta = sta_info_get(sdata, hdr.addr1); 1880 sta = sta_info_get(sdata, hdr.addr1);
1878 if (sta) { 1881 if (sta) {
@@ -1913,11 +1916,54 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1913 goto fail; 1916 goto fail;
1914 } 1917 }
1915 1918
1919 if (unlikely(!multicast && skb->sk &&
1920 skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
1921 struct sk_buff *orig_skb = skb;
1922
1923 skb = skb_clone(skb, GFP_ATOMIC);
1924 if (skb) {
1925 unsigned long flags;
1926 int id, r;
1927
1928 spin_lock_irqsave(&local->ack_status_lock, flags);
1929 r = idr_get_new_above(&local->ack_status_frames,
1930 orig_skb, 1, &id);
1931 if (r == -EAGAIN) {
1932 idr_pre_get(&local->ack_status_frames,
1933 GFP_ATOMIC);
1934 r = idr_get_new_above(&local->ack_status_frames,
1935 orig_skb, 1, &id);
1936 }
1937 if (WARN_ON(!id) || id > 0xffff) {
1938 idr_remove(&local->ack_status_frames, id);
1939 r = -ERANGE;
1940 }
1941 spin_unlock_irqrestore(&local->ack_status_lock, flags);
1942
1943 if (!r) {
1944 info_id = id;
1945 info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
1946 } else if (skb_shared(skb)) {
1947 kfree_skb(orig_skb);
1948 } else {
1949 kfree_skb(skb);
1950 skb = orig_skb;
1951 }
1952 } else {
1953 /* couldn't clone -- lose tx status ... */
1954 skb = orig_skb;
1955 }
1956 }
1957
1916 /* 1958 /*
1917 * If the skb is shared we need to obtain our own copy. 1959 * If the skb is shared we need to obtain our own copy.
1918 */ 1960 */
1919 if (skb_shared(skb)) { 1961 if (skb_shared(skb)) {
1920 tmp_skb = skb; 1962 struct sk_buff *tmp_skb = skb;
1963
1964 /* can't happen -- skb is a clone if info_id != 0 */
1965 WARN_ON(info_id);
1966
1921 skb = skb_clone(skb, GFP_ATOMIC); 1967 skb = skb_clone(skb, GFP_ATOMIC);
1922 kfree_skb(tmp_skb); 1968 kfree_skb(tmp_skb);
1923 1969
@@ -2018,6 +2064,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
2018 memset(info, 0, sizeof(*info)); 2064 memset(info, 0, sizeof(*info));
2019 2065
2020 dev->trans_start = jiffies; 2066 dev->trans_start = jiffies;
2067
2068 info->flags = info_flags;
2069 info->ack_frame_id = info_id;
2070
2021 ieee80211_xmit(sdata, skb); 2071 ieee80211_xmit(sdata, skb);
2022 2072
2023 return NETDEV_TX_OK; 2073 return NETDEV_TX_OK;