aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2014-11-25 09:43:05 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-11-25 14:09:56 -0500
commit808bbebcc8fcbcb2b93aefd8b181a0fdccb407c6 (patch)
tree76730d24264fbea860643fe4c8706b0d45bf2418 /drivers/net/wireless
parent381e9fffe6b8343c2479939178ef7ded50bf32d3 (diff)
mwifiex: add Tx status support for EAPOL packets
Firmware notifies the driver through event if EAPOL data packet has been acked or not. We will inform this status to userspace listening on a socket. Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c3
-rw-r--r--drivers/net/wireless/mwifiex/decl.h2
-rw-r--r--drivers/net/wireless/mwifiex/fw.h17
-rw-r--r--drivers/net/wireless/mwifiex/init.c3
-rw-r--r--drivers/net/wireless/mwifiex/main.c48
-rw-r--r--drivers/net/wireless/mwifiex/main.h7
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c5
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c5
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c20
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c4
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c7
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c10
12 files changed, 127 insertions, 4 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 17f0ee02d6e7..68d5874adc94 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -2988,6 +2988,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
2988 NL80211_FEATURE_INACTIVITY_TIMER | 2988 NL80211_FEATURE_INACTIVITY_TIMER |
2989 NL80211_FEATURE_NEED_OBSS_SCAN; 2989 NL80211_FEATURE_NEED_OBSS_SCAN;
2990 2990
2991 if (adapter->fw_api_ver == MWIFIEX_FW_V15)
2992 wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
2993
2991 /* Reserve space for mwifiex specific private data for BSS */ 2994 /* Reserve space for mwifiex specific private data for BSS */
2992 wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); 2995 wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
2993 2996
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index fc0b1ed80a6a..9daa88a61377 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -76,6 +76,7 @@
76#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) 76#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
77#define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1) 77#define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1)
78#define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2) 78#define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2)
79#define MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS BIT(3)
79 80
80#define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024 81#define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024
81#define MWIFIEX_BRIDGED_PKTS_THR_LOW 128 82#define MWIFIEX_BRIDGED_PKTS_THR_LOW 128
@@ -159,6 +160,7 @@ struct mwifiex_txinfo {
159 u8 bss_num; 160 u8 bss_num;
160 u8 bss_type; 161 u8 bss_type;
161 u32 pkt_len; 162 u32 pkt_len;
163 u8 ack_frame_id;
162}; 164};
163 165
164enum mwifiex_wmm_ac_e { 166enum mwifiex_wmm_ac_e {
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index e095f371545a..fb5936eb82e3 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -494,6 +494,7 @@ enum P2P_MODES {
494#define EVENT_TDLS_GENERIC_EVENT 0x00000052 494#define EVENT_TDLS_GENERIC_EVENT 0x00000052
495#define EVENT_EXT_SCAN_REPORT 0x00000058 495#define EVENT_EXT_SCAN_REPORT 0x00000058
496#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f 496#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
497#define EVENT_TX_STATUS_REPORT 0x00000074
497 498
498#define EVENT_ID_MASK 0xffff 499#define EVENT_ID_MASK 0xffff
499#define BSS_NUM_MASK 0xf 500#define BSS_NUM_MASK 0xf
@@ -542,6 +543,7 @@ struct mwifiex_ie_types_data {
542#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 543#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08
543#define MWIFIEX_TXPD_FLAGS_TDLS_PACKET 0x10 544#define MWIFIEX_TXPD_FLAGS_TDLS_PACKET 0x10
544#define MWIFIEX_RXPD_FLAGS_TDLS_PACKET 0x01 545#define MWIFIEX_RXPD_FLAGS_TDLS_PACKET 0x01
546#define MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS 0x20
545 547
546struct txpd { 548struct txpd {
547 u8 bss_type; 549 u8 bss_type;
@@ -553,7 +555,9 @@ struct txpd {
553 u8 priority; 555 u8 priority;
554 u8 flags; 556 u8 flags;
555 u8 pkt_delay_2ms; 557 u8 pkt_delay_2ms;
556 u8 reserved1; 558 u8 reserved1[2];
559 u8 tx_token_id;
560 u8 reserved[2];
557} __packed; 561} __packed;
558 562
559struct rxpd { 563struct rxpd {
@@ -598,8 +602,9 @@ struct uap_txpd {
598 u8 priority; 602 u8 priority;
599 u8 flags; 603 u8 flags;
600 u8 pkt_delay_2ms; 604 u8 pkt_delay_2ms;
601 u8 reserved1; 605 u8 reserved1[2];
602 __le32 reserved2; 606 u8 tx_token_id;
607 u8 reserved[2];
603}; 608};
604 609
605struct uap_rxpd { 610struct uap_rxpd {
@@ -1224,6 +1229,12 @@ struct mwifiex_event_scan_result {
1224 u8 num_of_set; 1229 u8 num_of_set;
1225} __packed; 1230} __packed;
1226 1231
1232struct tx_status_event {
1233 u8 packet_type;
1234 u8 tx_token_id;
1235 u8 status;
1236} __packed;
1237
1227#define MWIFIEX_USER_SCAN_CHAN_MAX 50 1238#define MWIFIEX_USER_SCAN_CHAN_MAX 50
1228 1239
1229#define MWIFIEX_MAX_SSID_LIST_LENGTH 10 1240#define MWIFIEX_MAX_SSID_LIST_LENGTH 10
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index cc15ab81aa66..520ad4a3018b 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -473,6 +473,9 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
473 473
474 spin_lock_init(&priv->tx_ba_stream_tbl_lock); 474 spin_lock_init(&priv->tx_ba_stream_tbl_lock);
475 spin_lock_init(&priv->rx_reorder_tbl_lock); 475 spin_lock_init(&priv->rx_reorder_tbl_lock);
476
477 spin_lock_init(&priv->ack_status_lock);
478 idr_init(&priv->ack_status_frames);
476 } 479 }
477 480
478 return 0; 481 return 0;
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index cf07279bf602..cf31d36a9fdd 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -608,6 +608,44 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
608 return 0; 608 return 0;
609} 609}
610 610
611static struct sk_buff *
612mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
613 struct sk_buff *skb, u8 flag)
614{
615 struct sk_buff *orig_skb = skb;
616 struct mwifiex_txinfo *tx_info, *orig_tx_info;
617
618 skb = skb_clone(skb, GFP_ATOMIC);
619 if (skb) {
620 unsigned long flags;
621 int id;
622
623 spin_lock_irqsave(&priv->ack_status_lock, flags);
624 id = idr_alloc(&priv->ack_status_frames, orig_skb,
625 1, 0xff, GFP_ATOMIC);
626 spin_unlock_irqrestore(&priv->ack_status_lock, flags);
627
628 if (id >= 0) {
629 tx_info = MWIFIEX_SKB_TXCB(skb);
630 tx_info->ack_frame_id = id;
631 tx_info->flags |= flag;
632 orig_tx_info = MWIFIEX_SKB_TXCB(orig_skb);
633 orig_tx_info->ack_frame_id = id;
634 orig_tx_info->flags |= flag;
635 } else if (skb_shared(skb)) {
636 kfree_skb(orig_skb);
637 } else {
638 kfree_skb(skb);
639 skb = orig_skb;
640 }
641 } else {
642 /* couldn't clone -- lose tx status ... */
643 skb = orig_skb;
644 }
645
646 return skb;
647}
648
611/* 649/*
612 * CFG802.11 network device handler for data transmission. 650 * CFG802.11 network device handler for data transmission.
613 */ 651 */
@@ -617,6 +655,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
617 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 655 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
618 struct sk_buff *new_skb; 656 struct sk_buff *new_skb;
619 struct mwifiex_txinfo *tx_info; 657 struct mwifiex_txinfo *tx_info;
658 bool multicast;
620 659
621 dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", 660 dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",
622 jiffies, priv->bss_type, priv->bss_num); 661 jiffies, priv->bss_type, priv->bss_num);
@@ -657,6 +696,15 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
657 tx_info->bss_type = priv->bss_type; 696 tx_info->bss_type = priv->bss_type;
658 tx_info->pkt_len = skb->len; 697 tx_info->pkt_len = skb->len;
659 698
699 multicast = is_multicast_ether_addr(skb->data);
700
701 if (unlikely(!multicast && skb->sk &&
702 skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS &&
703 priv->adapter->fw_api_ver == MWIFIEX_FW_V15))
704 skb = mwifiex_clone_skb_for_tx_status(priv,
705 skb,
706 MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS);
707
660 /* Record the current time the packet was queued; used to 708 /* Record the current time the packet was queued; used to
661 * determine the amount of time the packet was queued in 709 * determine the amount of time the packet was queued in
662 * the driver before it was sent to the firmware. 710 * the driver before it was sent to the firmware.
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 5a690d5210f0..e19fc2f87436 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -34,6 +34,7 @@
34#include <linux/firmware.h> 34#include <linux/firmware.h>
35#include <linux/ctype.h> 35#include <linux/ctype.h>
36#include <linux/of.h> 36#include <linux/of.h>
37#include <linux/idr.h>
37 38
38#include "decl.h" 39#include "decl.h"
39#include "ioctl.h" 40#include "ioctl.h"
@@ -578,6 +579,9 @@ struct mwifiex_private {
578 u8 check_tdls_tx; 579 u8 check_tdls_tx;
579 struct timer_list auto_tdls_timer; 580 struct timer_list auto_tdls_timer;
580 bool auto_tdls_timer_active; 581 bool auto_tdls_timer_active;
582 struct idr ack_status_frames;
583 /* spin lock for ack status */
584 spinlock_t ack_status_lock;
581}; 585};
582 586
583enum mwifiex_ba_status { 587enum mwifiex_ba_status {
@@ -1335,6 +1339,9 @@ void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);
1335void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); 1339void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);
1336void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); 1340void mwifiex_clean_auto_tdls(struct mwifiex_private *priv);
1337 1341
1342void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
1343 void *event_body);
1344
1338#ifdef CONFIG_DEBUG_FS 1345#ifdef CONFIG_DEBUG_FS
1339void mwifiex_debugfs_init(void); 1346void mwifiex_debugfs_init(void);
1340void mwifiex_debugfs_remove(void); 1347void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 204ecc8faa5b..b8c171df6223 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -504,6 +504,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
504 ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); 504 ret = mwifiex_parse_tdls_event(priv, adapter->event_skb);
505 break; 505 break;
506 506
507 case EVENT_TX_STATUS_REPORT:
508 dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
509 mwifiex_parse_tx_status_event(priv, adapter->event_body);
510 break;
511
507 default: 512 default:
508 dev_dbg(adapter->dev, "event: unknown event id: %#x\n", 513 dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
509 eventcause); 514 eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index dab7b33c54be..c69ecbc1d63f 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -77,6 +77,11 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
77 local_tx_pd->pkt_delay_2ms = 77 local_tx_pd->pkt_delay_2ms =
78 mwifiex_wmm_compute_drv_pkt_delay(priv, skb); 78 mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
79 79
80 if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) {
81 local_tx_pd->tx_token_id = tx_info->ack_frame_id;
82 local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS;
83 }
84
80 if (local_tx_pd->priority < 85 if (local_tx_pd->priority <
81 ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) 86 ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
82 /* 87 /*
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index a5983fc4e83a..782bfd61c300 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -203,3 +203,23 @@ done:
203} 203}
204EXPORT_SYMBOL_GPL(mwifiex_write_data_complete); 204EXPORT_SYMBOL_GPL(mwifiex_write_data_complete);
205 205
206void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
207 void *event_body)
208{
209 struct tx_status_event *tx_status = (void *)priv->adapter->event_body;
210 struct sk_buff *ack_skb;
211 unsigned long flags;
212
213 if (!tx_status->tx_token_id)
214 return;
215
216 spin_lock_irqsave(&priv->ack_status_lock, flags);
217 ack_skb = idr_find(&priv->ack_status_frames, tx_status->tx_token_id);
218 if (ack_skb)
219 idr_remove(&priv->ack_status_frames, tx_status->tx_token_id);
220 spin_unlock_irqrestore(&priv->ack_status_lock, flags);
221
222 /* consumes ack_skb */
223 if (ack_skb)
224 skb_complete_wifi_ack(ack_skb, !tx_status->status);
225}
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index 7c2b97660a03..38390cb85a90 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -172,6 +172,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
172 return mwifiex_handle_event_ext_scan_report(priv, 172 return mwifiex_handle_event_ext_scan_report(priv,
173 adapter->event_skb->data); 173 adapter->event_skb->data);
174 break; 174 break;
175 case EVENT_TX_STATUS_REPORT:
176 dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
177 mwifiex_parse_tx_status_event(priv, adapter->event_body);
178 break;
175 default: 179 default:
176 dev_dbg(adapter->dev, "event: unknown event id: %#x\n", 180 dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
177 eventcause); 181 eventcause);
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
index ec7309d096ab..4580942f6e80 100644
--- a/drivers/net/wireless/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/mwifiex/uap_txrx.c
@@ -370,10 +370,15 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
370 txpd->bss_num = priv->bss_num; 370 txpd->bss_num = priv->bss_num;
371 txpd->bss_type = priv->bss_type; 371 txpd->bss_type = priv->bss_type;
372 txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len)); 372 txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len));
373
374 txpd->priority = (u8)skb->priority; 373 txpd->priority = (u8)skb->priority;
374
375 txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); 375 txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
376 376
377 if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) {
378 txpd->tx_token_id = tx_info->ack_frame_id;
379 txpd->flags |= MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS;
380 }
381
377 if (txpd->priority < ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) 382 if (txpd->priority < ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
378 /* 383 /*
379 * Set the priority specific tx_control field, setting of 0 will 384 * Set the priority specific tx_control field, setting of 0 will
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 94c98a86ebbe..dc1f2adfafc2 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -523,6 +523,13 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
523 } 523 }
524} 524}
525 525
526static int mwifiex_free_ack_frame(int id, void *p, void *data)
527{
528 pr_warn("Have pending ack frames!\n");
529 kfree_skb(p);
530 return 0;
531}
532
526/* 533/*
527 * This function cleans up the Tx and Rx queues. 534 * This function cleans up the Tx and Rx queues.
528 * 535 *
@@ -558,6 +565,9 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
558 565
559 skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) 566 skb_queue_walk_safe(&priv->tdls_txq, skb, tmp)
560 mwifiex_write_data_complete(priv->adapter, skb, 0, -1); 567 mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
568
569 idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL);
570 idr_destroy(&priv->ack_status_frames);
561} 571}
562 572
563/* 573/*