aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorStone Piao <piaoyun@marvell.com>2012-09-25 23:23:32 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-09-28 13:54:03 -0400
commite39faa73ef14f67d11d1ed19e398964c4ecebbb9 (patch)
tree15ca2d7448a975cfdc1bcd357eaacf96fd99d380 /drivers/net/wireless
parenta8aa69dca7f754c9a2b524c90fda0209187ae9d7 (diff)
mwifiex: implement cfg80211 mgmt_tx handler
Implement mgmt_tx in cfg80211 ops through data path. Advertise probe resp offload and skip to send probe resp in AP or GO mode. Signed-off-by: Stone Piao <piaoyun@marvell.com> Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com> Signed-off-by: Kiran Divekar <dkiran@marvell.com> Signed-off-by: Bing Zhao <bzhao@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.c92
-rw-r--r--drivers/net/wireless/mwifiex/decl.h3
-rw-r--r--drivers/net/wireless/mwifiex/main.c34
-rw-r--r--drivers/net/wireless/mwifiex/main.h12
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c12
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c7
6 files changed, 143 insertions, 17 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 6fd4fa6705d9..11942e5e33cf 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -139,6 +139,94 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
139} 139}
140 140
141/* 141/*
142 * This function forms an skb for management frame.
143 */
144static int
145mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
146{
147 u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
148 u16 pkt_len;
149 u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT;
150 struct timeval tv;
151
152 pkt_len = len + ETH_ALEN;
153
154 skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN +
155 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
156 memcpy(skb_push(skb, sizeof(pkt_len)), &pkt_len, sizeof(pkt_len));
157
158 memcpy(skb_push(skb, sizeof(tx_control)),
159 &tx_control, sizeof(tx_control));
160
161 memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type));
162
163 /* Add packet data and address4 */
164 memcpy(skb_put(skb, sizeof(struct ieee80211_hdr_3addr)), buf,
165 sizeof(struct ieee80211_hdr_3addr));
166 memcpy(skb_put(skb, ETH_ALEN), addr, ETH_ALEN);
167 memcpy(skb_put(skb, len - sizeof(struct ieee80211_hdr_3addr)),
168 buf + sizeof(struct ieee80211_hdr_3addr),
169 len - sizeof(struct ieee80211_hdr_3addr));
170
171 skb->priority = LOW_PRIO_TID;
172 do_gettimeofday(&tv);
173 skb->tstamp = timeval_to_ktime(tv);
174
175 return 0;
176}
177
178/*
179 * CFG802.11 operation handler to transmit a management frame.
180 */
181static int
182mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
183 struct ieee80211_channel *chan, bool offchan,
184 enum nl80211_channel_type channel_type,
185 bool channel_type_valid, unsigned int wait,
186 const u8 *buf, size_t len, bool no_cck,
187 bool dont_wait_for_ack, u64 *cookie)
188{
189 struct sk_buff *skb;
190 u16 pkt_len;
191 const struct ieee80211_mgmt *mgmt;
192 struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
193
194 if (!buf || !len) {
195 wiphy_err(wiphy, "invalid buffer and length\n");
196 return -EFAULT;
197 }
198
199 mgmt = (const struct ieee80211_mgmt *)buf;
200 if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA &&
201 ieee80211_is_probe_resp(mgmt->frame_control)) {
202 /* Since we support offload probe resp, we need to skip probe
203 * resp in AP or GO mode */
204 wiphy_dbg(wiphy,
205 "info: skip to send probe resp in AP or GO mode\n");
206 return 0;
207 }
208
209 pkt_len = len + ETH_ALEN;
210 skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN +
211 MWIFIEX_MGMT_FRAME_HEADER_SIZE +
212 pkt_len + sizeof(pkt_len));
213
214 if (!skb) {
215 wiphy_err(wiphy, "allocate skb failed for management frame\n");
216 return -ENOMEM;
217 }
218
219 mwifiex_form_mgmt_frame(skb, buf, len);
220 mwifiex_queue_tx_pkt(priv, skb);
221
222 *cookie = random32() | 1;
223 cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, GFP_ATOMIC);
224
225 wiphy_dbg(wiphy, "info: management frame transmitted\n");
226 return 0;
227}
228
229/*
142 * CFG802.11 operation handler to set Tx power. 230 * CFG802.11 operation handler to set Tx power.
143 */ 231 */
144static int 232static int
@@ -1810,6 +1898,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
1810 .leave_ibss = mwifiex_cfg80211_leave_ibss, 1898 .leave_ibss = mwifiex_cfg80211_leave_ibss,
1811 .add_key = mwifiex_cfg80211_add_key, 1899 .add_key = mwifiex_cfg80211_add_key,
1812 .del_key = mwifiex_cfg80211_del_key, 1900 .del_key = mwifiex_cfg80211_del_key,
1901 .mgmt_tx = mwifiex_cfg80211_mgmt_tx,
1813 .set_default_key = mwifiex_cfg80211_set_default_key, 1902 .set_default_key = mwifiex_cfg80211_set_default_key,
1814 .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, 1903 .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
1815 .set_tx_power = mwifiex_cfg80211_set_tx_power, 1904 .set_tx_power = mwifiex_cfg80211_set_tx_power,
@@ -1872,7 +1961,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
1872 wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom); 1961 wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
1873 1962
1874 wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | 1963 wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
1875 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; 1964 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
1965 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
1876 1966
1877 wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; 1967 wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
1878 wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; 1968 wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 400d360ac91f..d21bcc146f4b 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -33,6 +33,9 @@
33#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd) 33#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
34 * + 4 byte alignment 34 * + 4 byte alignment
35 */ 35 */
36#define MWIFIEX_MGMT_FRAME_HEADER_SIZE 8 /* sizeof(pkt_type)
37 * + sizeof(tx_control)
38 */
36 39
37#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 40#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
38#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 41#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index bfd6667be01e..3bb3417932d0 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -469,6 +469,27 @@ mwifiex_close(struct net_device *dev)
469} 469}
470 470
471/* 471/*
472 * Add buffer into wmm tx queue and queue work to transmit it.
473 */
474int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
475{
476 mwifiex_wmm_add_buf_txqueue(priv, skb);
477 atomic_inc(&priv->adapter->tx_pending);
478
479 if (priv->adapter->scan_delay_cnt)
480 atomic_set(&priv->adapter->is_tx_received, true);
481
482 if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
483 mwifiex_set_trans_start(priv->netdev);
484 mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
485 }
486
487 queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
488
489 return 0;
490}
491
492/*
472 * CFG802.11 network device handler for data transmission. 493 * CFG802.11 network device handler for data transmission.
473 */ 494 */
474static int 495static int
@@ -516,18 +537,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
516 tx_info->bss_type = priv->bss_type; 537 tx_info->bss_type = priv->bss_type;
517 mwifiex_fill_buffer(skb); 538 mwifiex_fill_buffer(skb);
518 539
519 mwifiex_wmm_add_buf_txqueue(priv, skb); 540 mwifiex_queue_tx_pkt(priv, skb);
520 atomic_inc(&priv->adapter->tx_pending);
521
522 if (priv->adapter->scan_delay_cnt)
523 atomic_set(&priv->adapter->is_tx_received, true);
524
525 if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
526 mwifiex_set_trans_start(dev);
527 mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
528 }
529
530 queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
531 541
532 return 0; 542 return 0;
533} 543}
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 90b64b015447..092fbfaeb882 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -98,6 +98,8 @@ enum {
98#define MWIFIEX_OUI_NOT_PRESENT 0 98#define MWIFIEX_OUI_NOT_PRESENT 0
99#define MWIFIEX_OUI_PRESENT 1 99#define MWIFIEX_OUI_PRESENT 1
100 100
101#define PKT_TYPE_MGMT 0xE5
102
101/* 103/*
102 * Do not check for data_received for USB, as data_received 104 * Do not check for data_received for USB, as data_received
103 * is handled in mwifiex_usb_recv for USB 105 * is handled in mwifiex_usb_recv for USB
@@ -960,6 +962,14 @@ mwifiex_netdev_get_priv(struct net_device *dev)
960 return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); 962 return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev));
961} 963}
962 964
965/*
966 * This function checks if a skb holds a management frame.
967 */
968static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb)
969{
970 return (*(u32 *)skb->data == PKT_TYPE_MGMT);
971}
972
963int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, 973int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
964 u32 func_init_shutdown); 974 u32 func_init_shutdown);
965int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); 975int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
@@ -1022,6 +1032,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
1022 1032
1023int mwifiex_main_process(struct mwifiex_adapter *); 1033int mwifiex_main_process(struct mwifiex_adapter *);
1024 1034
1035int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb);
1036
1025int mwifiex_get_bss_info(struct mwifiex_private *, 1037int mwifiex_get_bss_info(struct mwifiex_private *,
1026 struct mwifiex_bss_info *); 1038 struct mwifiex_bss_info *);
1027int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, 1039int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 0a046d3a0c16..7b581af24f5f 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -48,6 +48,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
48 struct txpd *local_tx_pd; 48 struct txpd *local_tx_pd;
49 struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); 49 struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
50 u8 pad; 50 u8 pad;
51 u16 pkt_type, pkt_offset;
51 52
52 if (!skb->len) { 53 if (!skb->len) {
53 dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len); 54 dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
@@ -55,6 +56,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
55 return skb->data; 56 return skb->data;
56 } 57 }
57 58
59 pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
60
58 /* If skb->data is not aligned; add padding */ 61 /* If skb->data is not aligned; add padding */
59 pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; 62 pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;
60 63
@@ -93,7 +96,14 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
93 } 96 }
94 97
95 /* Offset of actual data */ 98 /* Offset of actual data */
96 local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + pad); 99 pkt_offset = sizeof(struct txpd) + pad;
100 if (pkt_type == PKT_TYPE_MGMT) {
101 /* Set the packet type and add header for management frame */
102 local_tx_pd->tx_pkt_type = cpu_to_le16(pkt_type);
103 pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
104 }
105
106 local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset);
97 107
98 /* make space for INTF_HEADER_LEN */ 108 /* make space for INTF_HEADER_LEN */
99 skb_push(skb, INTF_HEADER_LEN); 109 skb_push(skb, INTF_HEADER_LEN);
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 07a45407d3b4..600d8194610e 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -648,7 +648,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
648 u8 ra[ETH_ALEN], tid_down; 648 u8 ra[ETH_ALEN], tid_down;
649 unsigned long flags; 649 unsigned long flags;
650 650
651 if (!priv->media_connected) { 651 if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
652 dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); 652 dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
653 mwifiex_write_data_complete(adapter, skb, -1); 653 mwifiex_write_data_complete(adapter, skb, -1);
654 return; 654 return;
@@ -663,7 +663,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
663 /* In case of infra as we have already created the list during 663 /* In case of infra as we have already created the list during
664 association we just don't have to call get_queue_raptr, we will 664 association we just don't have to call get_queue_raptr, we will
665 have only 1 raptr for a tid in case of infra */ 665 have only 1 raptr for a tid in case of infra */
666 if (!mwifiex_queuing_ra_based(priv)) { 666 if (!mwifiex_queuing_ra_based(priv) &&
667 !mwifiex_is_skb_mgmt_frame(skb)) {
667 if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) 668 if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
668 ra_list = list_first_entry( 669 ra_list = list_first_entry(
669 &priv->wmm.tid_tbl_ptr[tid_down].ra_list, 670 &priv->wmm.tid_tbl_ptr[tid_down].ra_list,
@@ -672,7 +673,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
672 ra_list = NULL; 673 ra_list = NULL;
673 } else { 674 } else {
674 memcpy(ra, skb->data, ETH_ALEN); 675 memcpy(ra, skb->data, ETH_ALEN);
675 if (ra[0] & 0x01) 676 if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb))
676 memset(ra, 0xff, ETH_ALEN); 677 memset(ra, 0xff, ETH_ALEN);
677 ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); 678 ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
678 } 679 }