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
;
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
> 0) {
95 ie
= (struct mwifiex_ie
*)(((u8
*)ie_list
) + travel_len
);
96 input_len
-= le16_to_cpu(ie
->ie_length
) + MWIFIEX_IE_HDR_SIZE
;
97 travel_len
+= le16_to_cpu(ie
->ie_length
) + MWIFIEX_IE_HDR_SIZE
;
99 index
= le16_to_cpu(ie
->ie_index
);
100 mask
= le16_to_cpu(ie
->mgmt_subtype_mask
);
102 if (index
== MWIFIEX_AUTO_IDX_MASK
) {
103 /* automatic addition */
104 if (mwifiex_ie_get_autoidx(priv
, mask
, ie
, &index
))
106 if (index
== MWIFIEX_AUTO_IDX_MASK
)
109 tmp
= (u8
*)&priv
->mgmt_ie
[index
].ie_buffer
;
110 memcpy(tmp
, &ie
->ie_buffer
, le16_to_cpu(ie
->ie_length
));
111 priv
->mgmt_ie
[index
].ie_length
= ie
->ie_length
;
112 priv
->mgmt_ie
[index
].ie_index
= cpu_to_le16(index
);
113 priv
->mgmt_ie
[index
].mgmt_subtype_mask
=
116 ie
->ie_index
= cpu_to_le16(index
);
118 if (mask
!= MWIFIEX_DELETE_MASK
)
121 * Check if this index is being used on any
124 if (mwifiex_ie_index_used_by_other_intf(priv
, index
))
128 memcpy(&priv
->mgmt_ie
[index
], ie
,
129 sizeof(struct mwifiex_ie
));
132 le16_add_cpu(&ie_list
->len
,
133 le16_to_cpu(priv
->mgmt_ie
[index
].ie_length
) +
134 MWIFIEX_IE_HDR_SIZE
);
137 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
)
138 return mwifiex_send_cmd_async(priv
, HostCmd_CMD_UAP_SYS_CONFIG
,
140 UAP_CUSTOM_IE_I
, ie_list
);
145 /* Copy individual custom IEs for beacon, probe response and assoc response
146 * and prepare single structure for IE setting.
147 * This function also updates allocated IE indices from driver.
150 mwifiex_update_uap_custom_ie(struct mwifiex_private
*priv
,
151 struct mwifiex_ie
*beacon_ie
, u16
*beacon_idx
,
152 struct mwifiex_ie
*pr_ie
, u16
*probe_idx
,
153 struct mwifiex_ie
*ar_ie
, u16
*assoc_idx
)
155 struct mwifiex_ie_list
*ap_custom_ie
;
160 ap_custom_ie
= kzalloc(sizeof(*ap_custom_ie
), GFP_KERNEL
);
164 ap_custom_ie
->type
= cpu_to_le16(TLV_TYPE_MGMT_IE
);
165 pos
= (u8
*)ap_custom_ie
->ie_list
;
168 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
169 le16_to_cpu(beacon_ie
->ie_length
);
170 memcpy(pos
, beacon_ie
, len
);
172 le16_add_cpu(&ap_custom_ie
->len
, len
);
175 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
176 le16_to_cpu(pr_ie
->ie_length
);
177 memcpy(pos
, pr_ie
, len
);
179 le16_add_cpu(&ap_custom_ie
->len
, len
);
182 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
183 le16_to_cpu(ar_ie
->ie_length
);
184 memcpy(pos
, ar_ie
, len
);
186 le16_add_cpu(&ap_custom_ie
->len
, len
);
189 ret
= mwifiex_update_autoindex_ies(priv
, ap_custom_ie
);
191 pos
= (u8
*)(&ap_custom_ie
->ie_list
[0].ie_index
);
192 if (beacon_ie
&& *beacon_idx
== MWIFIEX_AUTO_IDX_MASK
) {
193 /* save beacon ie index after auto-indexing */
194 *beacon_idx
= le16_to_cpu(ap_custom_ie
->ie_list
[0].ie_index
);
195 len
= sizeof(*beacon_ie
) - IEEE_MAX_IE_SIZE
+
196 le16_to_cpu(beacon_ie
->ie_length
);
199 if (pr_ie
&& le16_to_cpu(pr_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
) {
200 /* save probe resp ie index after auto-indexing */
201 *probe_idx
= *((u16
*)pos
);
202 len
= sizeof(*pr_ie
) - IEEE_MAX_IE_SIZE
+
203 le16_to_cpu(pr_ie
->ie_length
);
206 if (ar_ie
&& le16_to_cpu(ar_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
)
207 /* save assoc resp ie index after auto-indexing */
208 *assoc_idx
= *((u16
*)pos
);
214 /* This function checks if the vendor specified IE is present in passed buffer
215 * and copies it to mwifiex_ie structure.
216 * Function takes pointer to struct mwifiex_ie pointer as argument.
217 * If the vendor specified IE is present then memory is allocated for
218 * mwifiex_ie pointer and filled in with IE. Caller should take care of freeing
221 static int mwifiex_update_vs_ie(const u8
*ies
, int ies_len
,
222 struct mwifiex_ie
**ie_ptr
, u16 mask
,
223 unsigned int oui
, u8 oui_type
)
225 struct ieee_types_header
*vs_ie
;
226 struct mwifiex_ie
*ie
= *ie_ptr
;
229 vendor_ie
= cfg80211_find_vendor_ie(oui
, oui_type
, ies
, ies_len
);
232 *ie_ptr
= kzalloc(sizeof(struct mwifiex_ie
),
239 vs_ie
= (struct ieee_types_header
*)vendor_ie
;
240 memcpy(ie
->ie_buffer
+ le16_to_cpu(ie
->ie_length
),
241 vs_ie
, vs_ie
->len
+ 2);
242 le16_add_cpu(&ie
->ie_length
, vs_ie
->len
+ 2);
243 ie
->mgmt_subtype_mask
= cpu_to_le16(mask
);
244 ie
->ie_index
= cpu_to_le16(MWIFIEX_AUTO_IDX_MASK
);
251 /* This function parses beacon IEs, probe response IEs, association response IEs
252 * from cfg80211_ap_settings->beacon and sets these IE to FW.
254 static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private
*priv
,
255 struct cfg80211_beacon_data
*data
)
257 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
, *ar_ie
= NULL
;
258 u16 beacon_idx
= MWIFIEX_AUTO_IDX_MASK
, pr_idx
= MWIFIEX_AUTO_IDX_MASK
;
259 u16 ar_idx
= MWIFIEX_AUTO_IDX_MASK
;
262 if (data
->beacon_ies
&& data
->beacon_ies_len
) {
263 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
264 &beacon_ie
, MGMT_MASK_BEACON
,
266 WLAN_OUI_TYPE_MICROSOFT_WPS
);
267 mwifiex_update_vs_ie(data
->beacon_ies
, data
->beacon_ies_len
,
268 &beacon_ie
, MGMT_MASK_BEACON
,
269 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
272 if (data
->proberesp_ies
&& data
->proberesp_ies_len
) {
273 mwifiex_update_vs_ie(data
->proberesp_ies
,
274 data
->proberesp_ies_len
, &pr_ie
,
275 MGMT_MASK_PROBE_RESP
, WLAN_OUI_MICROSOFT
,
276 WLAN_OUI_TYPE_MICROSOFT_WPS
);
277 mwifiex_update_vs_ie(data
->proberesp_ies
,
278 data
->proberesp_ies_len
, &pr_ie
,
279 MGMT_MASK_PROBE_RESP
,
280 WLAN_OUI_WFA
, WLAN_OUI_TYPE_WFA_P2P
);
283 if (data
->assocresp_ies
&& data
->assocresp_ies_len
) {
284 mwifiex_update_vs_ie(data
->assocresp_ies
,
285 data
->assocresp_ies_len
, &ar_ie
,
286 MGMT_MASK_ASSOC_RESP
|
287 MGMT_MASK_REASSOC_RESP
,
289 WLAN_OUI_TYPE_MICROSOFT_WPS
);
290 mwifiex_update_vs_ie(data
->assocresp_ies
,
291 data
->assocresp_ies_len
, &ar_ie
,
292 MGMT_MASK_ASSOC_RESP
|
293 MGMT_MASK_REASSOC_RESP
, WLAN_OUI_WFA
,
294 WLAN_OUI_TYPE_WFA_P2P
);
297 if (beacon_ie
|| pr_ie
|| ar_ie
) {
298 ret
= mwifiex_update_uap_custom_ie(priv
, beacon_ie
,
300 &pr_idx
, ar_ie
, &ar_idx
);
305 priv
->beacon_idx
= beacon_idx
;
306 priv
->proberesp_idx
= pr_idx
;
307 priv
->assocresp_idx
= ar_idx
;
317 /* This function parses different IEs-tail IEs, beacon IEs, probe response IEs,
318 * association response IEs from cfg80211_ap_settings function and sets these IE
321 int mwifiex_set_mgmt_ies(struct mwifiex_private
*priv
,
322 struct cfg80211_beacon_data
*info
)
324 struct mwifiex_ie
*gen_ie
;
325 struct ieee_types_header
*rsn_ie
, *wpa_ie
= NULL
;
326 u16 rsn_idx
= MWIFIEX_AUTO_IDX_MASK
, ie_len
= 0;
329 if (info
->tail
&& info
->tail_len
) {
330 gen_ie
= kzalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
333 gen_ie
->ie_index
= cpu_to_le16(rsn_idx
);
334 gen_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_BEACON
|
335 MGMT_MASK_PROBE_RESP
|
336 MGMT_MASK_ASSOC_RESP
);
338 rsn_ie
= (void *)cfg80211_find_ie(WLAN_EID_RSN
,
339 info
->tail
, info
->tail_len
);
341 memcpy(gen_ie
->ie_buffer
, rsn_ie
, rsn_ie
->len
+ 2);
342 ie_len
= rsn_ie
->len
+ 2;
343 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
346 vendor_ie
= cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT
,
347 WLAN_OUI_TYPE_MICROSOFT_WPA
,
351 wpa_ie
= (struct ieee_types_header
*)vendor_ie
;
352 memcpy(gen_ie
->ie_buffer
+ ie_len
,
353 wpa_ie
, wpa_ie
->len
+ 2);
354 ie_len
+= wpa_ie
->len
+ 2;
355 gen_ie
->ie_length
= cpu_to_le16(ie_len
);
358 if (rsn_ie
|| wpa_ie
) {
359 if (mwifiex_update_uap_custom_ie(priv
, gen_ie
, &rsn_idx
,
365 priv
->rsn_idx
= rsn_idx
;
371 return mwifiex_set_mgmt_beacon_data_ies(priv
, info
);
374 /* This function removes management IE set */
375 int mwifiex_del_mgmt_ies(struct mwifiex_private
*priv
)
377 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
378 struct mwifiex_ie
*ar_ie
= NULL
, *rsn_ie
= NULL
;
381 if (priv
->rsn_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
382 rsn_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
386 rsn_ie
->ie_index
= cpu_to_le16(priv
->rsn_idx
);
387 rsn_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
388 rsn_ie
->ie_length
= 0;
389 if (mwifiex_update_uap_custom_ie(priv
, rsn_ie
, &priv
->rsn_idx
,
390 NULL
, &priv
->proberesp_idx
,
391 NULL
, &priv
->assocresp_idx
)) {
396 priv
->rsn_idx
= MWIFIEX_AUTO_IDX_MASK
;
399 if (priv
->beacon_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
400 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
405 beacon_ie
->ie_index
= cpu_to_le16(priv
->beacon_idx
);
406 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
407 beacon_ie
->ie_length
= 0;
409 if (priv
->proberesp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
410 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
415 pr_ie
->ie_index
= cpu_to_le16(priv
->proberesp_idx
);
416 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
417 pr_ie
->ie_length
= 0;
419 if (priv
->assocresp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
420 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
425 ar_ie
->ie_index
= cpu_to_le16(priv
->assocresp_idx
);
426 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
427 ar_ie
->ie_length
= 0;
430 if (beacon_ie
|| pr_ie
|| ar_ie
)
431 ret
= mwifiex_update_uap_custom_ie(priv
,
432 beacon_ie
, &priv
->beacon_idx
,
433 pr_ie
, &priv
->proberesp_idx
,
434 ar_ie
, &priv
->assocresp_idx
);