2 * NXP Wireless LAN device driver: management IE handling- setting and
5 * Copyright 2011-2020 NXP
7 * This software file (the "File") is distributed by NXP
8 * 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 if (le16_to_cpu(ie
->ie_length
) + vs_ie
->len
+ 2 >
247 memcpy(ie
->ie_buffer
+ le16_to_cpu(ie
->ie_length
),
248 vs_ie
, vs_ie
->len
+ 2);
249 le16_unaligned_add_cpu(&ie
->ie_length
, vs_ie
->len
+ 2);
250 ie
->mgmt_subtype_mask
= cpu_to_le16(mask
);
251 ie
->ie_index
= cpu_to_le16(MWIFIEX_AUTO_IDX_MASK
);
258 /* This function parses beacon IEs, probe response IEs, association response IEs
259 * from cfg80211_ap_settings->beacon and sets these IE to FW.
261 static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private
*priv
,
262 struct cfg80211_beacon_data
*data
)
264 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
, *ar_ie
= NULL
;
265 u16 beacon_idx
= MWIFIEX_AUTO_IDX_MASK
, pr_idx
= MWIFIEX_AUTO_IDX_MASK
;
266 u16 ar_idx
= MWIFIEX_AUTO_IDX_MASK
;
269 if (data
->beacon_ies
&& data
->beacon_ies_len
) {
270 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
271 &beacon_ie
, MGMT_MASK_BEACON
,
273 WLAN_OUI_TYPE_MICROSOFT_WPS
);
274 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
275 &beacon_ie
, MGMT_MASK_BEACON
,
276 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
279 if (data
->proberesp_ies
&& data
->proberesp_ies_len
) {
280 mwifiex_update_vs_ie(data
->proberesp_ies
,
281 data
->proberesp_ies_len
, &pr_ie
,
282 MGMT_MASK_PROBE_RESP
, WLAN_OUI_MICROSOFT
,
283 WLAN_OUI_TYPE_MICROSOFT_WPS
);
284 mwifiex_update_vs_ie(data
->proberesp_ies
,
285 data
->proberesp_ies_len
, &pr_ie
,
286 MGMT_MASK_PROBE_RESP
,
287 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
290 if (data
->assocresp_ies
&& data
->assocresp_ies_len
) {
291 mwifiex_update_vs_ie(data
->assocresp_ies
,
292 data
->assocresp_ies_len
, &ar_ie
,
293 MGMT_MASK_ASSOC_RESP
|
294 MGMT_MASK_REASSOC_RESP
,
296 WLAN_OUI_TYPE_MICROSOFT_WPS
);
297 mwifiex_update_vs_ie(data
->assocresp_ies
,
298 data
->assocresp_ies_len
, &ar_ie
,
299 MGMT_MASK_ASSOC_RESP
|
300 MGMT_MASK_REASSOC_RESP
, WLAN_OUI_WFA
,
301 WLAN_OUI_TYPE_WFA_P2P
);
304 if (beacon_ie
|| pr_ie
|| ar_ie
) {
305 ret
= mwifiex_update_uap_custom_ie(priv
, beacon_ie
,
307 &pr_idx
, ar_ie
, &ar_idx
);
312 priv
->beacon_idx
= beacon_idx
;
313 priv
->proberesp_idx
= pr_idx
;
314 priv
->assocresp_idx
= ar_idx
;
324 /* This function parses head and tail IEs, from cfg80211_beacon_data and sets
327 static int mwifiex_uap_parse_tail_ies(struct mwifiex_private
*priv
,
328 struct cfg80211_beacon_data
*info
)
330 struct mwifiex_ie
*gen_ie
;
331 struct ieee_types_header
*hdr
;
332 struct ieee80211_vendor_ie
*vendorhdr
;
333 u16 gen_idx
= MWIFIEX_AUTO_IDX_MASK
, ie_len
= 0;
334 int left_len
, parsed_len
= 0;
335 unsigned int token_len
;
338 if (!info
->tail
|| !info
->tail_len
)
341 gen_ie
= kzalloc(sizeof(*gen_ie
), GFP_KERNEL
);
345 left_len
= info
->tail_len
;
347 /* Many IEs are generated in FW by parsing bss configuration.
348 * Let's not add them here; else we may end up duplicating these IEs
350 while (left_len
> sizeof(struct ieee_types_header
)) {
351 hdr
= (void *)(info
->tail
+ parsed_len
);
352 token_len
= hdr
->len
+ sizeof(struct ieee_types_header
);
353 if (token_len
> left_len
) {
358 switch (hdr
->element_id
) {
360 case WLAN_EID_SUPP_RATES
:
361 case WLAN_EID_COUNTRY
:
362 case WLAN_EID_PWR_CONSTRAINT
:
363 case WLAN_EID_ERP_INFO
:
364 case WLAN_EID_EXT_SUPP_RATES
:
365 case WLAN_EID_HT_CAPABILITY
:
366 case WLAN_EID_HT_OPERATION
:
367 case WLAN_EID_VHT_CAPABILITY
:
368 case WLAN_EID_VHT_OPERATION
:
370 case WLAN_EID_VENDOR_SPECIFIC
:
371 /* Skip only Microsoft WMM IE */
372 if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT
,
373 WLAN_OUI_TYPE_MICROSOFT_WMM
,
379 if (ie_len
+ token_len
> IEEE_MAX_IE_SIZE
) {
383 memcpy(gen_ie
->ie_buffer
+ ie_len
, hdr
, token_len
);
387 left_len
-= token_len
;
388 parsed_len
+= token_len
;
391 /* parse only WPA vendor IE from tail, WMM IE is configured by
394 vendorhdr
= (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT
,
395 WLAN_OUI_TYPE_MICROSOFT_WPA
,
396 info
->tail
, info
->tail_len
);
398 token_len
= vendorhdr
->len
+ sizeof(struct ieee_types_header
);
399 if (ie_len
+ token_len
> IEEE_MAX_IE_SIZE
) {
403 memcpy(gen_ie
->ie_buffer
+ ie_len
, vendorhdr
, token_len
);
410 gen_ie
->ie_index
= cpu_to_le16(gen_idx
);
411 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_BEACON
|
412 MGMT_MASK_PROBE_RESP
|
413 MGMT_MASK_ASSOC_RESP
);
414 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
416 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &gen_idx
, NULL
, NULL
,
422 priv
->gen_idx
= gen_idx
;
429 /* This function parses different IEs-head & tail IEs, beacon IEs,
430 * probe response IEs, association response IEs from cfg80211_ap_settings
431 * function and sets these IE to FW.
433 int mwifiex_set_mgmt_ies(struct mwifiex_private
*priv
,
434 struct cfg80211_beacon_data
*info
)
438 ret
= mwifiex_uap_parse_tail_ies(priv
, info
);
443 return mwifiex_set_mgmt_beacon_data_ies(priv
, info
);
446 /* This function removes management IE set */
447 int mwifiex_del_mgmt_ies(struct mwifiex_private
*priv
)
449 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
450 struct mwifiex_ie
*ar_ie
= NULL
, *gen_ie
= NULL
;
453 if (priv
->gen_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
454 gen_ie
= kmalloc(sizeof(*gen_ie
), GFP_KERNEL
);
458 gen_ie
->ie_index
= cpu_to_le16(priv
->gen_idx
);
459 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
460 gen_ie
->ie_length
= 0;
461 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &priv
->gen_idx
,
462 NULL
, &priv
->proberesp_idx
,
463 NULL
, &priv
->assocresp_idx
)) {
468 priv
->gen_idx
= MWIFIEX_AUTO_IDX_MASK
;
471 if (priv
->beacon_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
472 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
477 beacon_ie
->ie_index
= cpu_to_le16(priv
->beacon_idx
);
478 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
479 beacon_ie
->ie_length
= 0;
481 if (priv
->proberesp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
482 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
487 pr_ie
->ie_index
= cpu_to_le16(priv
->proberesp_idx
);
488 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
489 pr_ie
->ie_length
= 0;
491 if (priv
->assocresp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
492 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
497 ar_ie
->ie_index
= cpu_to_le16(priv
->assocresp_idx
);
498 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
499 ar_ie
->ie_length
= 0;
502 if (beacon_ie
|| pr_ie
|| ar_ie
)
503 ret
= mwifiex_update_uap_custom_ie(priv
,
504 beacon_ie
, &priv
->beacon_idx
,
505 pr_ie
, &priv
->proberesp_idx
,
506 ar_ie
, &priv
->assocresp_idx
);