diff options
author | Stone Piao <piaoyun@marvell.com> | 2012-09-25 23:23:32 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-09-28 13:54:03 -0400 |
commit | e39faa73ef14f67d11d1ed19e398964c4ecebbb9 (patch) | |
tree | 15ca2d7448a975cfdc1bcd357eaacf96fd99d380 /drivers/net/wireless | |
parent | a8aa69dca7f754c9a2b524c90fda0209187ae9d7 (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.c | 92 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/decl.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.c | 34 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_tx.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/wmm.c | 7 |
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 | */ | ||
144 | static int | ||
145 | mwifiex_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 | */ | ||
181 | static int | ||
182 | mwifiex_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 | */ |
144 | static int | 232 | static 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 | */ | ||
474 | int 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 | */ |
474 | static int | 495 | static 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 | */ | ||
968 | static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb) | ||
969 | { | ||
970 | return (*(u32 *)skb->data == PKT_TYPE_MGMT); | ||
971 | } | ||
972 | |||
963 | int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, | 973 | int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, |
964 | u32 func_init_shutdown); | 974 | u32 func_init_shutdown); |
965 | int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); | 975 | int 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 | ||
1023 | int mwifiex_main_process(struct mwifiex_adapter *); | 1033 | int mwifiex_main_process(struct mwifiex_adapter *); |
1024 | 1034 | ||
1035 | int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb); | ||
1036 | |||
1025 | int mwifiex_get_bss_info(struct mwifiex_private *, | 1037 | int mwifiex_get_bss_info(struct mwifiex_private *, |
1026 | struct mwifiex_bss_info *); | 1038 | struct mwifiex_bss_info *); |
1027 | int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | 1039 | int 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 | } |