2 * Marvell Wireless LAN device driver: management IE handling- setting and
5 * Copyright (C) 2012, 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_async(priv
, HostCmd_CMD_UAP_SYS_CONFIG
,
143 UAP_CUSTOM_IE_I
, ie_list
);
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 different IEs-tail IEs, beacon IEs, probe response IEs,
321 * association response IEs from cfg80211_ap_settings function and sets these IE
324 int mwifiex_set_mgmt_ies(struct mwifiex_private
*priv
,
325 struct cfg80211_beacon_data
*info
)
327 struct mwifiex_ie
*gen_ie
;
328 struct ieee_types_header
*rsn_ie
, *wpa_ie
= NULL
;
329 u16 rsn_idx
= MWIFIEX_AUTO_IDX_MASK
, ie_len
= 0;
332 if (info
->tail
&& info
->tail_len
) {
333 gen_ie
= kzalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
336 gen_ie
->ie_index
= cpu_to_le16(rsn_idx
);
337 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_BEACON
|
338 MGMT_MASK_PROBE_RESP
|
339 MGMT_MASK_ASSOC_RESP
);
341 rsn_ie
= (void *)cfg80211_find_ie(WLAN_EID_RSN
,
342 info
->tail
, info
->tail_len
);
344 memcpy(gen_ie
->ie_buffer
, rsn_ie
, rsn_ie
->len
+ 2);
345 ie_len
= rsn_ie
->len
+ 2;
346 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
349 vendor_ie
= cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT
,
350 WLAN_OUI_TYPE_MICROSOFT_WPA
,
354 wpa_ie
= (struct ieee_types_header
*)vendor_ie
;
355 memcpy(gen_ie
->ie_buffer
+ ie_len
,
356 wpa_ie
, wpa_ie
->len
+ 2);
357 ie_len
+= wpa_ie
->len
+ 2;
358 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
361 if (rsn_ie
|| wpa_ie
) {
362 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &rsn_idx
,
368 priv
->rsn_idx
= rsn_idx
;
374 return mwifiex_set_mgmt_beacon_data_ies(priv
, info
);
377 /* This function removes management IE set */
378 int mwifiex_del_mgmt_ies(struct mwifiex_private
*priv
)
380 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
381 struct mwifiex_ie
*ar_ie
= NULL
, *rsn_ie
= NULL
;
384 if (priv
->rsn_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
385 rsn_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
389 rsn_ie
->ie_index
= cpu_to_le16(priv
->rsn_idx
);
390 rsn_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
391 rsn_ie
->ie_length
= 0;
392 if (mwifiex_update_uap_custom_ie(priv
, rsn_ie
, &priv
->rsn_idx
,
393 NULL
, &priv
->proberesp_idx
,
394 NULL
, &priv
->assocresp_idx
)) {
399 priv
->rsn_idx
= MWIFIEX_AUTO_IDX_MASK
;
402 if (priv
->beacon_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
403 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
408 beacon_ie
->ie_index
= cpu_to_le16(priv
->beacon_idx
);
409 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
410 beacon_ie
->ie_length
= 0;
412 if (priv
->proberesp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
413 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
418 pr_ie
->ie_index
= cpu_to_le16(priv
->proberesp_idx
);
419 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
420 pr_ie
->ie_length
= 0;
422 if (priv
->assocresp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
423 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
428 ar_ie
->ie_index
= cpu_to_le16(priv
->assocresp_idx
);
429 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
430 ar_ie
->ie_length
= 0;
433 if (beacon_ie
|| pr_ie
|| ar_ie
)
434 ret
= mwifiex_update_uap_custom_ie(priv
,
435 beacon_ie
, &priv
->beacon_idx
,
436 pr_ie
, &priv
->proberesp_idx
,
437 ar_ie
, &priv
->assocresp_idx
);