diff options
author | Avinash Patil <patila@marvell.com> | 2012-05-08 21:30:28 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-05-16 12:46:36 -0400 |
commit | ede98bfa914ec3285761da4bb9c25d1e160ea85b (patch) | |
tree | 5be00b8cd4bdf8b9f3d46ea1325b046700118479 /drivers/net/wireless | |
parent | e76268da22f9dbe8794d68e6a504a781dfd36998 (diff) |
mwifiex: add custom IE framework
1. support for setting custom IE from application hostapd etc.
Custom IE addition using auto-indexing and Custom IE deletion using
static indices (which are allocated during IE addition and stored in
driver) are supported.
2. Separate file for handling IE related execution.
Signed-off-by: Avinash Patil <patila@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/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/fw.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/ie.c | 149 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/init.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/ioctl.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/uap_cmd.c | 28 |
8 files changed, 201 insertions, 1 deletions
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 3ec71aeb6aa8..3f66ebb0a630 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile | |||
@@ -30,6 +30,7 @@ mwifiex-y += join.o | |||
30 | mwifiex-y += sta_ioctl.o | 30 | mwifiex-y += sta_ioctl.o |
31 | mwifiex-y += sta_cmd.o | 31 | mwifiex-y += sta_cmd.o |
32 | mwifiex-y += uap_cmd.o | 32 | mwifiex-y += uap_cmd.o |
33 | mwifiex-y += ie.o | ||
33 | mwifiex-y += sta_cmdresp.o | 34 | mwifiex-y += sta_cmdresp.o |
34 | mwifiex-y += sta_event.o | 35 | mwifiex-y += sta_event.o |
35 | mwifiex-y += sta_tx.o | 36 | mwifiex-y += sta_tx.o |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 4fd7a05fee18..0cb2b0cc3ee8 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -94,6 +94,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { | |||
94 | #define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) | 94 | #define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) |
95 | 95 | ||
96 | #define UAP_BSS_PARAMS_I 0 | 96 | #define UAP_BSS_PARAMS_I 0 |
97 | #define UAP_CUSTOM_IE_I 1 | ||
98 | #define MWIFIEX_AUTO_IDX_MASK 0xffff | ||
99 | #define MWIFIEX_DELETE_MASK 0x0000 | ||
97 | 100 | ||
98 | #define TLV_TYPE_UAP_SSID 0x0000 | 101 | #define TLV_TYPE_UAP_SSID 0x0000 |
99 | 102 | ||
@@ -1299,6 +1302,20 @@ struct host_cmd_ds_802_11_subsc_evt { | |||
1299 | __le16 events; | 1302 | __le16 events; |
1300 | } __packed; | 1303 | } __packed; |
1301 | 1304 | ||
1305 | struct mwifiex_ie { | ||
1306 | __le16 ie_index; | ||
1307 | __le16 mgmt_subtype_mask; | ||
1308 | __le16 ie_length; | ||
1309 | u8 ie_buffer[IEEE_MAX_IE_SIZE]; | ||
1310 | } __packed; | ||
1311 | |||
1312 | #define MAX_MGMT_IE_INDEX 16 | ||
1313 | struct mwifiex_ie_list { | ||
1314 | __le16 type; | ||
1315 | __le16 len; | ||
1316 | struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX]; | ||
1317 | } __packed; | ||
1318 | |||
1302 | struct host_cmd_ds_command { | 1319 | struct host_cmd_ds_command { |
1303 | __le16 command; | 1320 | __le16 command; |
1304 | __le16 size; | 1321 | __le16 size; |
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c new file mode 100644 index 000000000000..772bf3e57006 --- /dev/null +++ b/drivers/net/wireless/mwifiex/ie.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Marvell Wireless LAN device driver: management IE handling- setting and | ||
3 | * deleting IE. | ||
4 | * | ||
5 | * Copyright (C) 2012, Marvell International Ltd. | ||
6 | * | ||
7 | * This software file (the "File") is distributed by Marvell International | ||
8 | * Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
9 | * (the "License"). You may use, redistribute and/or modify this File in | ||
10 | * accordance with the terms and conditions of the License, a copy of which | ||
11 | * is available by writing to the Free Software Foundation, Inc., | ||
12 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the | ||
13 | * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | ||
14 | * | ||
15 | * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
17 | * ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
18 | * this warranty disclaimer. | ||
19 | */ | ||
20 | |||
21 | #include "main.h" | ||
22 | |||
23 | /* This function checks if current IE index is used by any on other interface. | ||
24 | * Return: -1: yes, current IE index is used by someone else. | ||
25 | * 0: no, current IE index is NOT used by other interface. | ||
26 | */ | ||
27 | static int | ||
28 | mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx) | ||
29 | { | ||
30 | int i; | ||
31 | struct mwifiex_adapter *adapter = priv->adapter; | ||
32 | struct mwifiex_ie *ie; | ||
33 | |||
34 | for (i = 0; i < adapter->priv_num; i++) { | ||
35 | if (adapter->priv[i] != priv) { | ||
36 | ie = &adapter->priv[i]->mgmt_ie[idx]; | ||
37 | if (ie->mgmt_subtype_mask && ie->ie_length) | ||
38 | return -1; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | /* Get unused IE index. This index will be used for setting new IE */ | ||
46 | static int | ||
47 | mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask, | ||
48 | struct mwifiex_ie *ie, u16 *index) | ||
49 | { | ||
50 | u16 mask, len, i; | ||
51 | |||
52 | for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) { | ||
53 | mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask); | ||
54 | len = le16_to_cpu(priv->mgmt_ie[i].ie_length) + | ||
55 | le16_to_cpu(ie->ie_length); | ||
56 | |||
57 | if (mask == MWIFIEX_AUTO_IDX_MASK) | ||
58 | continue; | ||
59 | |||
60 | if (mask == subtype_mask) { | ||
61 | if (len > IEEE_MAX_IE_SIZE) | ||
62 | continue; | ||
63 | |||
64 | *index = i; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | if (!priv->mgmt_ie[i].ie_length) { | ||
69 | if (mwifiex_ie_index_used_by_other_intf(priv, i)) | ||
70 | continue; | ||
71 | |||
72 | *index = i; | ||
73 | return 0; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | return -1; | ||
78 | } | ||
79 | |||
80 | /* This function prepares IE data buffer for command to be sent to FW */ | ||
81 | static int | ||
82 | mwifiex_update_autoindex_ies(struct mwifiex_private *priv, | ||
83 | struct mwifiex_ie_list *ie_list) | ||
84 | { | ||
85 | u16 travel_len, index, mask; | ||
86 | s16 input_len; | ||
87 | struct mwifiex_ie *ie; | ||
88 | u8 *tmp; | ||
89 | |||
90 | input_len = le16_to_cpu(ie_list->len); | ||
91 | travel_len = sizeof(struct host_cmd_tlv); | ||
92 | |||
93 | ie_list->len = 0; | ||
94 | |||
95 | while (input_len > 0) { | ||
96 | ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len); | ||
97 | input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE; | ||
98 | travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE; | ||
99 | |||
100 | index = le16_to_cpu(ie->ie_index); | ||
101 | mask = le16_to_cpu(ie->mgmt_subtype_mask); | ||
102 | |||
103 | if (index == MWIFIEX_AUTO_IDX_MASK) { | ||
104 | /* automatic addition */ | ||
105 | if (mwifiex_ie_get_autoidx(priv, mask, ie, &index)) | ||
106 | return -1; | ||
107 | if (index == MWIFIEX_AUTO_IDX_MASK) | ||
108 | return -1; | ||
109 | |||
110 | tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer; | ||
111 | tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length); | ||
112 | memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length)); | ||
113 | le16_add_cpu(&priv->mgmt_ie[index].ie_length, | ||
114 | le16_to_cpu(ie->ie_length)); | ||
115 | priv->mgmt_ie[index].ie_index = cpu_to_le16(index); | ||
116 | priv->mgmt_ie[index].mgmt_subtype_mask = | ||
117 | cpu_to_le16(mask); | ||
118 | |||
119 | ie->ie_index = cpu_to_le16(index); | ||
120 | ie->ie_length = priv->mgmt_ie[index].ie_length; | ||
121 | memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer, | ||
122 | le16_to_cpu(priv->mgmt_ie[index].ie_length)); | ||
123 | } else { | ||
124 | if (mask != MWIFIEX_DELETE_MASK) | ||
125 | return -1; | ||
126 | /* | ||
127 | * Check if this index is being used on any | ||
128 | * other interface. | ||
129 | */ | ||
130 | if (mwifiex_ie_index_used_by_other_intf(priv, index)) | ||
131 | return -1; | ||
132 | |||
133 | ie->ie_length = 0; | ||
134 | memcpy(&priv->mgmt_ie[index], ie, | ||
135 | sizeof(struct mwifiex_ie)); | ||
136 | } | ||
137 | |||
138 | le16_add_cpu(&ie_list->len, | ||
139 | le16_to_cpu(priv->mgmt_ie[index].ie_length) + | ||
140 | MWIFIEX_IE_HDR_SIZE); | ||
141 | } | ||
142 | |||
143 | if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) | ||
144 | return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, | ||
145 | HostCmd_ACT_GEN_SET, | ||
146 | UAP_CUSTOM_IE_I, ie_list); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index d440c3eb640b..c1cb004db913 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -279,6 +279,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) | |||
279 | memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); | 279 | memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); |
280 | adapter->arp_filter_size = 0; | 280 | adapter->arp_filter_size = 0; |
281 | adapter->channel_type = NL80211_CHAN_HT20; | 281 | adapter->channel_type = NL80211_CHAN_HT20; |
282 | adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; | ||
282 | } | 283 | } |
283 | 284 | ||
284 | /* | 285 | /* |
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index eb14f558b118..e6be6ee75951 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h | |||
@@ -299,6 +299,8 @@ struct mwifiex_ds_read_eeprom { | |||
299 | 299 | ||
300 | #define IEEE_MAX_IE_SIZE 256 | 300 | #define IEEE_MAX_IE_SIZE 256 |
301 | 301 | ||
302 | #define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE) | ||
303 | |||
302 | struct mwifiex_ds_misc_gen_ie { | 304 | struct mwifiex_ds_misc_gen_ie { |
303 | u32 type; | 305 | u32 type; |
304 | u32 len; | 306 | u32 len; |
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 43e4efad4cf7..49598e6c181f 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -640,6 +640,8 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, | |||
640 | priv->current_key_index = 0; | 640 | priv->current_key_index = 0; |
641 | priv->media_connected = false; | 641 | priv->media_connected = false; |
642 | memset(&priv->nick_name, 0, sizeof(priv->nick_name)); | 642 | memset(&priv->nick_name, 0, sizeof(priv->nick_name)); |
643 | memset(priv->mgmt_ie, 0, | ||
644 | sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); | ||
643 | priv->num_tx_timeout = 0; | 645 | priv->num_tx_timeout = 0; |
644 | memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); | 646 | memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); |
645 | } | 647 | } |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 824bd436c3ae..988d31d6504c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -477,6 +477,7 @@ struct mwifiex_private { | |||
477 | s32 cqm_rssi_thold; | 477 | s32 cqm_rssi_thold; |
478 | u32 cqm_rssi_hyst; | 478 | u32 cqm_rssi_hyst; |
479 | u8 subsc_evt_rssi_state; | 479 | u8 subsc_evt_rssi_state; |
480 | struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX]; | ||
480 | }; | 481 | }; |
481 | 482 | ||
482 | enum mwifiex_ba_status { | 483 | enum mwifiex_ba_status { |
@@ -680,6 +681,7 @@ struct mwifiex_adapter { | |||
680 | spinlock_t queue_lock; /* lock for tx queues */ | 681 | spinlock_t queue_lock; /* lock for tx queues */ |
681 | struct completion fw_load; | 682 | struct completion fw_load; |
682 | u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; | 683 | u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; |
684 | u16 max_mgmt_ie_index; | ||
683 | }; | 685 | }; |
684 | 686 | ||
685 | int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); | 687 | int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); |
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index e43bcaafa1bd..76dfbc42a732 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c | |||
@@ -315,6 +315,26 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) | |||
315 | return 0; | 315 | return 0; |
316 | } | 316 | } |
317 | 317 | ||
318 | /* This function parses custom IEs from IE list and prepares command buffer */ | ||
319 | static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size) | ||
320 | { | ||
321 | struct mwifiex_ie_list *ap_ie = cmd_buf; | ||
322 | struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv; | ||
323 | |||
324 | if (!ap_ie || !ap_ie->len || !ap_ie->ie_list) | ||
325 | return -1; | ||
326 | |||
327 | *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv); | ||
328 | |||
329 | tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE); | ||
330 | tlv_ie->len = ap_ie->len; | ||
331 | tlv += sizeof(struct host_cmd_tlv); | ||
332 | |||
333 | memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len)); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
318 | /* Parse AP config structure and prepare TLV based command structure | 338 | /* Parse AP config structure and prepare TLV based command structure |
319 | * to be sent to FW for uAP configuration | 339 | * to be sent to FW for uAP configuration |
320 | */ | 340 | */ |
@@ -323,7 +343,7 @@ mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action, | |||
323 | u32 type, void *cmd_buf) | 343 | u32 type, void *cmd_buf) |
324 | { | 344 | { |
325 | u8 *tlv; | 345 | u8 *tlv; |
326 | u16 cmd_size, param_size; | 346 | u16 cmd_size, param_size, ie_size; |
327 | struct host_cmd_ds_sys_config *sys_cfg; | 347 | struct host_cmd_ds_sys_config *sys_cfg; |
328 | 348 | ||
329 | cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG); | 349 | cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG); |
@@ -339,6 +359,12 @@ mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action, | |||
339 | return -1; | 359 | return -1; |
340 | cmd->size = cpu_to_le16(param_size); | 360 | cmd->size = cpu_to_le16(param_size); |
341 | break; | 361 | break; |
362 | case UAP_CUSTOM_IE_I: | ||
363 | ie_size = cmd_size; | ||
364 | if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size)) | ||
365 | return -1; | ||
366 | cmd->size = cpu_to_le16(ie_size); | ||
367 | break; | ||
342 | default: | 368 | default: |
343 | return -1; | 369 | return -1; |
344 | } | 370 | } |