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_add_cpu(&ie_list
->len
,
135 le16_to_cpu(priv
->mgmt_ie
[index
].ie_length
) +
136 MWIFIEX_IE_HDR_SIZE
);
137 input_len
-= tlv_len
+ MWIFIEX_IE_HDR_SIZE
;
140 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
)
141 return mwifiex_send_cmd(priv
, HostCmd_CMD_UAP_SYS_CONFIG
,
143 UAP_CUSTOM_IE_I
, ie_list
, false);
148 /* Copy individual custom IEs for beacon, probe response and assoc response
149 * and prepare single structure for IE setting.
150 * This function also updates allocated IE indices from driver.
153 mwifiex_update_uap_custom_ie(struct mwifiex_private
*priv
,
154 struct mwifiex_ie
*beacon_ie
, u16
*beacon_idx
,
155 struct mwifiex_ie
*pr_ie
, u16
*probe_idx
,
156 struct mwifiex_ie
*ar_ie
, u16
*assoc_idx
)
158 struct mwifiex_ie_list
*ap_custom_ie
;
163 ap_custom_ie
= kzalloc(sizeof(*ap_custom_ie
), GFP_KERNEL
);
167 ap_custom_ie
->type
= cpu_to_le16(TLV_TYPE_MGMT_IE
);
168 pos
= (u8
*)ap_custom_ie
->ie_list
;
171 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
172 le16_to_cpu(beacon_ie
->ie_length
);
173 memcpy(pos
, beacon_ie
, len
);
175 le16_add_cpu(&ap_custom_ie
->len
, len
);
178 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
179 le16_to_cpu(pr_ie
->ie_length
);
180 memcpy(pos
, pr_ie
, len
);
182 le16_add_cpu(&ap_custom_ie
->len
, len
);
185 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
186 le16_to_cpu(ar_ie
->ie_length
);
187 memcpy(pos
, ar_ie
, len
);
189 le16_add_cpu(&ap_custom_ie
->len
, len
);
192 ret
= mwifiex_update_autoindex_ies(priv
, ap_custom_ie
);
194 pos
= (u8
*)(&ap_custom_ie
->ie_list
[0].ie_index
);
195 if (beacon_ie
&& *beacon_idx
== MWIFIEX_AUTO_IDX_MASK
) {
196 /* save beacon ie index after auto-indexing */
197 *beacon_idx
= le16_to_cpu(ap_custom_ie
->ie_list
[0].ie_index
);
198 len
= sizeof(*beacon_ie
) - IEEE_MAX_IE_SIZE
+
199 le16_to_cpu(beacon_ie
->ie_length
);
202 if (pr_ie
&& le16_to_cpu(pr_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
) {
203 /* save probe resp ie index after auto-indexing */
204 *probe_idx
= *((u16
*)pos
);
205 len
= sizeof(*pr_ie
) - IEEE_MAX_IE_SIZE
+
206 le16_to_cpu(pr_ie
->ie_length
);
209 if (ar_ie
&& le16_to_cpu(ar_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
)
210 /* save assoc resp ie index after auto-indexing */
211 *assoc_idx
= *((u16
*)pos
);
217 /* This function checks if the vendor specified IE is present in passed buffer
218 * and copies it to mwifiex_ie structure.
219 * Function takes pointer to struct mwifiex_ie pointer as argument.
220 * If the vendor specified IE is present then memory is allocated for
221 * mwifiex_ie pointer and filled in with IE. Caller should take care of freeing
224 static int mwifiex_update_vs_ie(const u8
*ies
, int ies_len
,
225 struct mwifiex_ie
**ie_ptr
, u16 mask
,
226 unsigned int oui
, u8 oui_type
)
228 struct ieee_types_header
*vs_ie
;
229 struct mwifiex_ie
*ie
= *ie_ptr
;
232 vendor_ie
= cfg80211_find_vendor_ie(oui
, oui_type
, ies
, ies_len
);
235 *ie_ptr
= kzalloc(sizeof(struct mwifiex_ie
),
242 vs_ie
= (struct ieee_types_header
*)vendor_ie
;
243 memcpy(ie
->ie_buffer
+ le16_to_cpu(ie
->ie_length
),
244 vs_ie
, vs_ie
->len
+ 2);
245 le16_add_cpu(&ie
->ie_length
, vs_ie
->len
+ 2);
246 ie
->mgmt_subtype_mask
= cpu_to_le16(mask
);
247 ie
->ie_index
= cpu_to_le16(MWIFIEX_AUTO_IDX_MASK
);
254 /* This function parses beacon IEs, probe response IEs, association response IEs
255 * from cfg80211_ap_settings->beacon and sets these IE to FW.
257 static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private
*priv
,
258 struct cfg80211_beacon_data
*data
)
260 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
, *ar_ie
= NULL
;
261 u16 beacon_idx
= MWIFIEX_AUTO_IDX_MASK
, pr_idx
= MWIFIEX_AUTO_IDX_MASK
;
262 u16 ar_idx
= MWIFIEX_AUTO_IDX_MASK
;
265 if (data
->beacon_ies
&& data
->beacon_ies_len
) {
266 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
267 &beacon_ie
, MGMT_MASK_BEACON
,
269 WLAN_OUI_TYPE_MICROSOFT_WPS
);
270 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
271 &beacon_ie
, MGMT_MASK_BEACON
,
272 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
275 if (data
->proberesp_ies
&& data
->proberesp_ies_len
) {
276 mwifiex_update_vs_ie(data
->proberesp_ies
,
277 data
->proberesp_ies_len
, &pr_ie
,
278 MGMT_MASK_PROBE_RESP
, WLAN_OUI_MICROSOFT
,
279 WLAN_OUI_TYPE_MICROSOFT_WPS
);
280 mwifiex_update_vs_ie(data
->proberesp_ies
,
281 data
->proberesp_ies_len
, &pr_ie
,
282 MGMT_MASK_PROBE_RESP
,
283 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
286 if (data
->assocresp_ies
&& data
->assocresp_ies_len
) {
287 mwifiex_update_vs_ie(data
->assocresp_ies
,
288 data
->assocresp_ies_len
, &ar_ie
,
289 MGMT_MASK_ASSOC_RESP
|
290 MGMT_MASK_REASSOC_RESP
,
292 WLAN_OUI_TYPE_MICROSOFT_WPS
);
293 mwifiex_update_vs_ie(data
->assocresp_ies
,
294 data
->assocresp_ies_len
, &ar_ie
,
295 MGMT_MASK_ASSOC_RESP
|
296 MGMT_MASK_REASSOC_RESP
, WLAN_OUI_WFA
,
297 WLAN_OUI_TYPE_WFA_P2P
);
300 if (beacon_ie
|| pr_ie
|| ar_ie
) {
301 ret
= mwifiex_update_uap_custom_ie(priv
, beacon_ie
,
303 &pr_idx
, ar_ie
, &ar_idx
);
308 priv
->beacon_idx
= beacon_idx
;
309 priv
->proberesp_idx
= pr_idx
;
310 priv
->assocresp_idx
= ar_idx
;
320 /* This function parses head and tail IEs, from cfg80211_beacon_data and sets
323 static int mwifiex_uap_parse_tail_ies(struct mwifiex_private
*priv
,
324 struct cfg80211_beacon_data
*info
)
326 struct mwifiex_ie
*gen_ie
;
327 struct ieee_types_header
*hdr
;
328 struct ieee80211_vendor_ie
*vendorhdr
;
329 u16 gen_idx
= MWIFIEX_AUTO_IDX_MASK
, ie_len
= 0;
330 int left_len
, parsed_len
= 0;
332 if (!info
->tail
|| !info
->tail_len
)
335 gen_ie
= kzalloc(sizeof(*gen_ie
), GFP_KERNEL
);
339 left_len
= info
->tail_len
;
341 /* Many IEs are generated in FW by parsing bss configuration.
342 * Let's not add them here; else we may end up duplicating these IEs
344 while (left_len
> sizeof(struct ieee_types_header
)) {
345 hdr
= (void *)(info
->tail
+ parsed_len
);
346 switch (hdr
->element_id
) {
348 case WLAN_EID_SUPP_RATES
:
349 case WLAN_EID_COUNTRY
:
350 case WLAN_EID_PWR_CONSTRAINT
:
351 case WLAN_EID_EXT_SUPP_RATES
:
352 case WLAN_EID_HT_CAPABILITY
:
353 case WLAN_EID_HT_OPERATION
:
354 case WLAN_EID_VHT_CAPABILITY
:
355 case WLAN_EID_VHT_OPERATION
:
356 case WLAN_EID_VENDOR_SPECIFIC
:
359 memcpy(gen_ie
->ie_buffer
+ ie_len
, hdr
,
360 hdr
->len
+ sizeof(struct ieee_types_header
));
361 ie_len
+= hdr
->len
+ sizeof(struct ieee_types_header
);
364 left_len
-= hdr
->len
+ sizeof(struct ieee_types_header
);
365 parsed_len
+= hdr
->len
+ sizeof(struct ieee_types_header
);
368 /* parse only WPA vendor IE from tail, WMM IE is configured by
371 vendorhdr
= (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT
,
372 WLAN_OUI_TYPE_MICROSOFT_WPA
,
373 info
->tail
, info
->tail_len
);
375 memcpy(gen_ie
->ie_buffer
+ ie_len
, vendorhdr
,
376 vendorhdr
->len
+ sizeof(struct ieee_types_header
));
377 ie_len
+= vendorhdr
->len
+ sizeof(struct ieee_types_header
);
385 gen_ie
->ie_index
= cpu_to_le16(gen_idx
);
386 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_BEACON
|
387 MGMT_MASK_PROBE_RESP
|
388 MGMT_MASK_ASSOC_RESP
);
389 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
391 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &gen_idx
, NULL
, NULL
,
397 priv
->gen_idx
= gen_idx
;
402 /* This function parses different IEs-head & tail IEs, beacon IEs,
403 * probe response IEs, association response IEs from cfg80211_ap_settings
404 * function and sets these IE to FW.
406 int mwifiex_set_mgmt_ies(struct mwifiex_private
*priv
,
407 struct cfg80211_beacon_data
*info
)
411 ret
= mwifiex_uap_parse_tail_ies(priv
, info
);
416 return mwifiex_set_mgmt_beacon_data_ies(priv
, info
);
419 /* This function removes management IE set */
420 int mwifiex_del_mgmt_ies(struct mwifiex_private
*priv
)
422 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
423 struct mwifiex_ie
*ar_ie
= NULL
, *gen_ie
= NULL
;
426 if (priv
->gen_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
427 gen_ie
= kmalloc(sizeof(*gen_ie
), GFP_KERNEL
);
431 gen_ie
->ie_index
= cpu_to_le16(priv
->gen_idx
);
432 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
433 gen_ie
->ie_length
= 0;
434 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &priv
->gen_idx
,
435 NULL
, &priv
->proberesp_idx
,
436 NULL
, &priv
->assocresp_idx
)) {
441 priv
->gen_idx
= MWIFIEX_AUTO_IDX_MASK
;
444 if (priv
->beacon_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
445 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
450 beacon_ie
->ie_index
= cpu_to_le16(priv
->beacon_idx
);
451 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
452 beacon_ie
->ie_length
= 0;
454 if (priv
->proberesp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
455 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
460 pr_ie
->ie_index
= cpu_to_le16(priv
->proberesp_idx
);
461 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
462 pr_ie
->ie_length
= 0;
464 if (priv
->assocresp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
465 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
470 ar_ie
->ie_index
= cpu_to_le16(priv
->assocresp_idx
);
471 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
472 ar_ie
->ie_length
= 0;
475 if (beacon_ie
|| pr_ie
|| ar_ie
)
476 ret
= mwifiex_update_uap_custom_ie(priv
,
477 beacon_ie
, &priv
->beacon_idx
,
478 pr_ie
, &priv
->proberesp_idx
,
479 ar_ie
, &priv
->assocresp_idx
);