2 * Marvell Wireless LAN device driver: management IE handling- setting and
5 * Copyright (C) 2012-2014, Marvell International Ltd.
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.
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.
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.
28 mwifiex_ie_index_used_by_other_intf(struct mwifiex_private
*priv
, u16 idx
)
31 struct mwifiex_adapter
*adapter
= priv
->adapter
;
32 struct mwifiex_ie
*ie
;
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
)
45 /* Get unused IE index. This index will be used for setting new IE */
47 mwifiex_ie_get_autoidx(struct mwifiex_private
*priv
, u16 subtype_mask
,
48 struct mwifiex_ie
*ie
, u16
*index
)
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(ie
->ie_length
);
56 if (mask
== MWIFIEX_AUTO_IDX_MASK
)
59 if (mask
== subtype_mask
) {
60 if (len
> IEEE_MAX_IE_SIZE
)
67 if (!priv
->mgmt_ie
[i
].ie_length
) {
68 if (mwifiex_ie_index_used_by_other_intf(priv
, i
))
79 /* This function prepares IE data buffer for command to be sent to FW */
81 mwifiex_update_autoindex_ies(struct mwifiex_private
*priv
,
82 struct mwifiex_ie_list
*ie_list
)
84 u16 travel_len
, index
, mask
;
85 s16 input_len
, tlv_len
;
86 struct mwifiex_ie
*ie
;
89 input_len
= le16_to_cpu(ie_list
->len
);
90 travel_len
= sizeof(struct mwifiex_ie_types_header
);
94 while (input_len
>= sizeof(struct mwifiex_ie_types_header
)) {
95 ie
= (struct mwifiex_ie
*)(((u8
*)ie_list
) + travel_len
);
96 tlv_len
= le16_to_cpu(ie
->ie_length
);
97 travel_len
+= tlv_len
+ MWIFIEX_IE_HDR_SIZE
;
99 if (input_len
< tlv_len
+ MWIFIEX_IE_HDR_SIZE
)
101 index
= le16_to_cpu(ie
->ie_index
);
102 mask
= le16_to_cpu(ie
->mgmt_subtype_mask
);
104 if (index
== MWIFIEX_AUTO_IDX_MASK
) {
105 /* automatic addition */
106 if (mwifiex_ie_get_autoidx(priv
, mask
, ie
, &index
))
108 if (index
== MWIFIEX_AUTO_IDX_MASK
)
111 tmp
= (u8
*)&priv
->mgmt_ie
[index
].ie_buffer
;
112 memcpy(tmp
, &ie
->ie_buffer
, le16_to_cpu(ie
->ie_length
));
113 priv
->mgmt_ie
[index
].ie_length
= ie
->ie_length
;
114 priv
->mgmt_ie
[index
].ie_index
= cpu_to_le16(index
);
115 priv
->mgmt_ie
[index
].mgmt_subtype_mask
=
118 ie
->ie_index
= cpu_to_le16(index
);
120 if (mask
!= MWIFIEX_DELETE_MASK
)
123 * Check if this index is being used on any
126 if (mwifiex_ie_index_used_by_other_intf(priv
, index
))
130 memcpy(&priv
->mgmt_ie
[index
], ie
,
131 sizeof(struct mwifiex_ie
));
134 le16_unaligned_add_cpu(&ie_list
->len
,
136 priv
->mgmt_ie
[index
].ie_length
) +
137 MWIFIEX_IE_HDR_SIZE
);
138 input_len
-= tlv_len
+ MWIFIEX_IE_HDR_SIZE
;
141 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
)
142 return mwifiex_send_cmd(priv
, HostCmd_CMD_UAP_SYS_CONFIG
,
144 UAP_CUSTOM_IE_I
, ie_list
, true);
149 /* Copy individual custom IEs for beacon, probe response and assoc response
150 * and prepare single structure for IE setting.
151 * This function also updates allocated IE indices from driver.
154 mwifiex_update_uap_custom_ie(struct mwifiex_private
*priv
,
155 struct mwifiex_ie
*beacon_ie
, u16
*beacon_idx
,
156 struct mwifiex_ie
*pr_ie
, u16
*probe_idx
,
157 struct mwifiex_ie
*ar_ie
, u16
*assoc_idx
)
159 struct mwifiex_ie_list
*ap_custom_ie
;
164 ap_custom_ie
= kzalloc(sizeof(*ap_custom_ie
), GFP_KERNEL
);
168 ap_custom_ie
->type
= cpu_to_le16(TLV_TYPE_MGMT_IE
);
169 pos
= (u8
*)ap_custom_ie
->ie_list
;
172 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
173 le16_to_cpu(beacon_ie
->ie_length
);
174 memcpy(pos
, beacon_ie
, len
);
176 le16_unaligned_add_cpu(&ap_custom_ie
->len
, len
);
179 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
180 le16_to_cpu(pr_ie
->ie_length
);
181 memcpy(pos
, pr_ie
, len
);
183 le16_unaligned_add_cpu(&ap_custom_ie
->len
, len
);
186 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
187 le16_to_cpu(ar_ie
->ie_length
);
188 memcpy(pos
, ar_ie
, len
);
190 le16_unaligned_add_cpu(&ap_custom_ie
->len
, len
);
193 ret
= mwifiex_update_autoindex_ies(priv
, ap_custom_ie
);
195 pos
= (u8
*)(&ap_custom_ie
->ie_list
[0].ie_index
);
196 if (beacon_ie
&& *beacon_idx
== MWIFIEX_AUTO_IDX_MASK
) {
197 /* save beacon ie index after auto-indexing */
198 *beacon_idx
= le16_to_cpu(ap_custom_ie
->ie_list
[0].ie_index
);
199 len
= sizeof(*beacon_ie
) - IEEE_MAX_IE_SIZE
+
200 le16_to_cpu(beacon_ie
->ie_length
);
203 if (pr_ie
&& le16_to_cpu(pr_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
) {
204 /* save probe resp ie index after auto-indexing */
205 *probe_idx
= *((u16
*)pos
);
206 len
= sizeof(*pr_ie
) - IEEE_MAX_IE_SIZE
+
207 le16_to_cpu(pr_ie
->ie_length
);
210 if (ar_ie
&& le16_to_cpu(ar_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
)
211 /* save assoc resp ie index after auto-indexing */
212 *assoc_idx
= *((u16
*)pos
);
218 /* This function checks if the vendor specified IE is present in passed buffer
219 * and copies it to mwifiex_ie structure.
220 * Function takes pointer to struct mwifiex_ie pointer as argument.
221 * If the vendor specified IE is present then memory is allocated for
222 * mwifiex_ie pointer and filled in with IE. Caller should take care of freeing
225 static int mwifiex_update_vs_ie(const u8
*ies
, int ies_len
,
226 struct mwifiex_ie
**ie_ptr
, u16 mask
,
227 unsigned int oui
, u8 oui_type
)
229 struct ieee_types_header
*vs_ie
;
230 struct mwifiex_ie
*ie
= *ie_ptr
;
233 vendor_ie
= cfg80211_find_vendor_ie(oui
, oui_type
, ies
, ies_len
);
236 *ie_ptr
= kzalloc(sizeof(struct mwifiex_ie
),
243 vs_ie
= (struct ieee_types_header
*)vendor_ie
;
244 memcpy(ie
->ie_buffer
+ le16_to_cpu(ie
->ie_length
),
245 vs_ie
, vs_ie
->len
+ 2);
246 le16_unaligned_add_cpu(&ie
->ie_length
, vs_ie
->len
+ 2);
247 ie
->mgmt_subtype_mask
= cpu_to_le16(mask
);
248 ie
->ie_index
= cpu_to_le16(MWIFIEX_AUTO_IDX_MASK
);
255 /* This function parses beacon IEs, probe response IEs, association response IEs
256 * from cfg80211_ap_settings->beacon and sets these IE to FW.
258 static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private
*priv
,
259 struct cfg80211_beacon_data
*data
)
261 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
, *ar_ie
= NULL
;
262 u16 beacon_idx
= MWIFIEX_AUTO_IDX_MASK
, pr_idx
= MWIFIEX_AUTO_IDX_MASK
;
263 u16 ar_idx
= MWIFIEX_AUTO_IDX_MASK
;
266 if (data
->beacon_ies
&& data
->beacon_ies_len
) {
267 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
268 &beacon_ie
, MGMT_MASK_BEACON
,
270 WLAN_OUI_TYPE_MICROSOFT_WPS
);
271 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
272 &beacon_ie
, MGMT_MASK_BEACON
,
273 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
276 if (data
->proberesp_ies
&& data
->proberesp_ies_len
) {
277 mwifiex_update_vs_ie(data
->proberesp_ies
,
278 data
->proberesp_ies_len
, &pr_ie
,
279 MGMT_MASK_PROBE_RESP
, WLAN_OUI_MICROSOFT
,
280 WLAN_OUI_TYPE_MICROSOFT_WPS
);
281 mwifiex_update_vs_ie(data
->proberesp_ies
,
282 data
->proberesp_ies_len
, &pr_ie
,
283 MGMT_MASK_PROBE_RESP
,
284 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
287 if (data
->assocresp_ies
&& data
->assocresp_ies_len
) {
288 mwifiex_update_vs_ie(data
->assocresp_ies
,
289 data
->assocresp_ies_len
, &ar_ie
,
290 MGMT_MASK_ASSOC_RESP
|
291 MGMT_MASK_REASSOC_RESP
,
293 WLAN_OUI_TYPE_MICROSOFT_WPS
);
294 mwifiex_update_vs_ie(data
->assocresp_ies
,
295 data
->assocresp_ies_len
, &ar_ie
,
296 MGMT_MASK_ASSOC_RESP
|
297 MGMT_MASK_REASSOC_RESP
, WLAN_OUI_WFA
,
298 WLAN_OUI_TYPE_WFA_P2P
);
301 if (beacon_ie
|| pr_ie
|| ar_ie
) {
302 ret
= mwifiex_update_uap_custom_ie(priv
, beacon_ie
,
304 &pr_idx
, ar_ie
, &ar_idx
);
309 priv
->beacon_idx
= beacon_idx
;
310 priv
->proberesp_idx
= pr_idx
;
311 priv
->assocresp_idx
= ar_idx
;
321 /* This function parses head and tail IEs, from cfg80211_beacon_data and sets
324 static int mwifiex_uap_parse_tail_ies(struct mwifiex_private
*priv
,
325 struct cfg80211_beacon_data
*info
)
327 struct mwifiex_ie
*gen_ie
;
328 struct ieee_types_header
*hdr
;
329 struct ieee80211_vendor_ie
*vendorhdr
;
330 u16 gen_idx
= MWIFIEX_AUTO_IDX_MASK
, ie_len
= 0;
331 int left_len
, parsed_len
= 0;
333 if (!info
->tail
|| !info
->tail_len
)
336 gen_ie
= kzalloc(sizeof(*gen_ie
), GFP_KERNEL
);
340 left_len
= info
->tail_len
;
342 /* Many IEs are generated in FW by parsing bss configuration.
343 * Let's not add them here; else we may end up duplicating these IEs
345 while (left_len
> sizeof(struct ieee_types_header
)) {
346 hdr
= (void *)(info
->tail
+ parsed_len
);
347 switch (hdr
->element_id
) {
349 case WLAN_EID_SUPP_RATES
:
350 case WLAN_EID_COUNTRY
:
351 case WLAN_EID_PWR_CONSTRAINT
:
352 case WLAN_EID_EXT_SUPP_RATES
:
353 case WLAN_EID_HT_CAPABILITY
:
354 case WLAN_EID_HT_OPERATION
:
355 case WLAN_EID_VHT_CAPABILITY
:
356 case WLAN_EID_VHT_OPERATION
:
357 case WLAN_EID_VENDOR_SPECIFIC
:
360 memcpy(gen_ie
->ie_buffer
+ ie_len
, hdr
,
361 hdr
->len
+ sizeof(struct ieee_types_header
));
362 ie_len
+= hdr
->len
+ sizeof(struct ieee_types_header
);
365 left_len
-= hdr
->len
+ sizeof(struct ieee_types_header
);
366 parsed_len
+= hdr
->len
+ sizeof(struct ieee_types_header
);
369 /* parse only WPA vendor IE from tail, WMM IE is configured by
372 vendorhdr
= (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT
,
373 WLAN_OUI_TYPE_MICROSOFT_WPA
,
374 info
->tail
, info
->tail_len
);
376 memcpy(gen_ie
->ie_buffer
+ ie_len
, vendorhdr
,
377 vendorhdr
->len
+ sizeof(struct ieee_types_header
));
378 ie_len
+= vendorhdr
->len
+ sizeof(struct ieee_types_header
);
386 gen_ie
->ie_index
= cpu_to_le16(gen_idx
);
387 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_BEACON
|
388 MGMT_MASK_PROBE_RESP
|
389 MGMT_MASK_ASSOC_RESP
);
390 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
392 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &gen_idx
, NULL
, NULL
,
398 priv
->gen_idx
= gen_idx
;
403 /* This function parses different IEs-head & tail IEs, beacon IEs,
404 * probe response IEs, association response IEs from cfg80211_ap_settings
405 * function and sets these IE to FW.
407 int mwifiex_set_mgmt_ies(struct mwifiex_private
*priv
,
408 struct cfg80211_beacon_data
*info
)
412 ret
= mwifiex_uap_parse_tail_ies(priv
, info
);
417 return mwifiex_set_mgmt_beacon_data_ies(priv
, info
);
420 /* This function removes management IE set */
421 int mwifiex_del_mgmt_ies(struct mwifiex_private
*priv
)
423 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
424 struct mwifiex_ie
*ar_ie
= NULL
, *gen_ie
= NULL
;
427 if (priv
->gen_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
428 gen_ie
= kmalloc(sizeof(*gen_ie
), GFP_KERNEL
);
432 gen_ie
->ie_index
= cpu_to_le16(priv
->gen_idx
);
433 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
434 gen_ie
->ie_length
= 0;
435 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &priv
->gen_idx
,
436 NULL
, &priv
->proberesp_idx
,
437 NULL
, &priv
->assocresp_idx
)) {
442 priv
->gen_idx
= MWIFIEX_AUTO_IDX_MASK
;
445 if (priv
->beacon_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
446 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
451 beacon_ie
->ie_index
= cpu_to_le16(priv
->beacon_idx
);
452 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
453 beacon_ie
->ie_length
= 0;
455 if (priv
->proberesp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
456 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
461 pr_ie
->ie_index
= cpu_to_le16(priv
->proberesp_idx
);
462 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
463 pr_ie
->ie_length
= 0;
465 if (priv
->assocresp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
466 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
471 ar_ie
->ie_index
= cpu_to_le16(priv
->assocresp_idx
);
472 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
473 ar_ie
->ie_length
= 0;
476 if (beacon_ie
|| pr_ie
|| ar_ie
)
477 ret
= mwifiex_update_uap_custom_ie(priv
,
478 beacon_ie
, &priv
->beacon_idx
,
479 pr_ie
, &priv
->proberesp_idx
,
480 ar_ie
, &priv
->assocresp_idx
);