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(priv
->mgmt_ie
[i
].ie_length
) +
55 le16_to_cpu(ie
->ie_length
);
57 if (mask
== MWIFIEX_AUTO_IDX_MASK
)
60 if (mask
== subtype_mask
) {
61 if (len
> IEEE_MAX_IE_SIZE
)
68 if (!priv
->mgmt_ie
[i
].ie_length
) {
69 if (mwifiex_ie_index_used_by_other_intf(priv
, i
))
80 /* This function prepares IE data buffer for command to be sent to FW */
82 mwifiex_update_autoindex_ies(struct mwifiex_private
*priv
,
83 struct mwifiex_ie_list
*ie_list
)
85 u16 travel_len
, index
, mask
;
87 struct mwifiex_ie
*ie
;
90 input_len
= le16_to_cpu(ie_list
->len
);
91 travel_len
= sizeof(struct host_cmd_tlv
);
95 while (input_len
> 0) {
96 ie
= (struct mwifiex_ie
*)(((u8
*)ie_list
) + travel_len
);
97 input_len
-= le16_to_cpu(ie
->ie_length
) + MWIFIEX_IE_HDR_SIZE
;
98 travel_len
+= le16_to_cpu(ie
->ie_length
) + MWIFIEX_IE_HDR_SIZE
;
100 index
= le16_to_cpu(ie
->ie_index
);
101 mask
= le16_to_cpu(ie
->mgmt_subtype_mask
);
103 if (index
== MWIFIEX_AUTO_IDX_MASK
) {
104 /* automatic addition */
105 if (mwifiex_ie_get_autoidx(priv
, mask
, ie
, &index
))
107 if (index
== MWIFIEX_AUTO_IDX_MASK
)
110 tmp
= (u8
*)&priv
->mgmt_ie
[index
].ie_buffer
;
111 tmp
+= le16_to_cpu(priv
->mgmt_ie
[index
].ie_length
);
112 memcpy(tmp
, &ie
->ie_buffer
, le16_to_cpu(ie
->ie_length
));
113 le16_add_cpu(&priv
->mgmt_ie
[index
].ie_length
,
114 le16_to_cpu(ie
->ie_length
));
115 priv
->mgmt_ie
[index
].ie_index
= cpu_to_le16(index
);
116 priv
->mgmt_ie
[index
].mgmt_subtype_mask
=
119 ie
->ie_index
= cpu_to_le16(index
);
120 ie
->ie_length
= priv
->mgmt_ie
[index
].ie_length
;
121 memcpy(&ie
->ie_buffer
, &priv
->mgmt_ie
[index
].ie_buffer
,
122 le16_to_cpu(priv
->mgmt_ie
[index
].ie_length
));
124 if (mask
!= MWIFIEX_DELETE_MASK
)
127 * Check if this index is being used on any
130 if (mwifiex_ie_index_used_by_other_intf(priv
, index
))
134 memcpy(&priv
->mgmt_ie
[index
], ie
,
135 sizeof(struct mwifiex_ie
));
138 le16_add_cpu(&ie_list
->len
,
139 le16_to_cpu(priv
->mgmt_ie
[index
].ie_length
) +
140 MWIFIEX_IE_HDR_SIZE
);
143 if (GET_BSS_ROLE(priv
) == MWIFIEX_BSS_ROLE_UAP
)
144 return mwifiex_send_cmd_async(priv
, HostCmd_CMD_UAP_SYS_CONFIG
,
146 UAP_CUSTOM_IE_I
, ie_list
);
151 /* Copy individual custom IEs for beacon, probe response and assoc response
152 * and prepare single structure for IE setting.
153 * This function also updates allocated IE indices from driver.
156 mwifiex_update_uap_custom_ie(struct mwifiex_private
*priv
,
157 struct mwifiex_ie
*beacon_ie
, u16
*beacon_idx
,
158 struct mwifiex_ie
*pr_ie
, u16
*probe_idx
,
159 struct mwifiex_ie
*ar_ie
, u16
*assoc_idx
)
161 struct mwifiex_ie_list
*ap_custom_ie
;
166 ap_custom_ie
= kzalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
170 ap_custom_ie
->type
= cpu_to_le16(TLV_TYPE_MGMT_IE
);
171 pos
= (u8
*)ap_custom_ie
->ie_list
;
174 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
175 le16_to_cpu(beacon_ie
->ie_length
);
176 memcpy(pos
, beacon_ie
, len
);
178 le16_add_cpu(&ap_custom_ie
->len
, len
);
181 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
182 le16_to_cpu(pr_ie
->ie_length
);
183 memcpy(pos
, pr_ie
, len
);
185 le16_add_cpu(&ap_custom_ie
->len
, len
);
188 len
= sizeof(struct mwifiex_ie
) - IEEE_MAX_IE_SIZE
+
189 le16_to_cpu(ar_ie
->ie_length
);
190 memcpy(pos
, ar_ie
, len
);
192 le16_add_cpu(&ap_custom_ie
->len
, len
);
195 ret
= mwifiex_update_autoindex_ies(priv
, ap_custom_ie
);
197 pos
= (u8
*)(&ap_custom_ie
->ie_list
[0].ie_index
);
198 if (beacon_ie
&& *beacon_idx
== MWIFIEX_AUTO_IDX_MASK
) {
199 /* save beacon ie index after auto-indexing */
200 *beacon_idx
= le16_to_cpu(ap_custom_ie
->ie_list
[0].ie_index
);
201 len
= sizeof(*beacon_ie
) - IEEE_MAX_IE_SIZE
+
202 le16_to_cpu(beacon_ie
->ie_length
);
205 if (pr_ie
&& le16_to_cpu(pr_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
) {
206 /* save probe resp ie index after auto-indexing */
207 *probe_idx
= *((u16
*)pos
);
208 len
= sizeof(*pr_ie
) - IEEE_MAX_IE_SIZE
+
209 le16_to_cpu(pr_ie
->ie_length
);
212 if (ar_ie
&& le16_to_cpu(ar_ie
->ie_index
) == MWIFIEX_AUTO_IDX_MASK
)
213 /* save assoc resp ie index after auto-indexing */
214 *assoc_idx
= *((u16
*)pos
);
219 /* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs,
220 * association response IEs from cfg80211_ap_settings function and sets these IE
223 int mwifiex_set_mgmt_ies(struct mwifiex_private
*priv
,
224 struct cfg80211_ap_settings
*params
)
226 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
227 struct mwifiex_ie
*ar_ie
= NULL
, *rsn_ie
= NULL
;
228 struct ieee_types_header
*ie
= NULL
;
229 u16 beacon_idx
= MWIFIEX_AUTO_IDX_MASK
, pr_idx
= MWIFIEX_AUTO_IDX_MASK
;
230 u16 ar_idx
= MWIFIEX_AUTO_IDX_MASK
, rsn_idx
= MWIFIEX_AUTO_IDX_MASK
;
234 if (params
->beacon
.tail
&& params
->beacon
.tail_len
) {
235 ie
= (void *)cfg80211_find_ie(WLAN_EID_RSN
, params
->beacon
.tail
,
236 params
->beacon
.tail_len
);
238 rsn_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
242 rsn_ie
->ie_index
= cpu_to_le16(rsn_idx
);
243 mask
= MGMT_MASK_BEACON
| MGMT_MASK_PROBE_RESP
|
244 MGMT_MASK_ASSOC_RESP
;
245 rsn_ie
->mgmt_subtype_mask
= cpu_to_le16(mask
);
246 rsn_ie
->ie_length
= cpu_to_le16(ie
->len
+ 2);
247 memcpy(rsn_ie
->ie_buffer
, ie
, ie
->len
+ 2);
249 if (mwifiex_update_uap_custom_ie(priv
, rsn_ie
, &rsn_idx
,
256 priv
->rsn_idx
= rsn_idx
;
260 if (params
->beacon
.beacon_ies
&& params
->beacon
.beacon_ies_len
) {
261 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
267 beacon_ie
->ie_index
= cpu_to_le16(beacon_idx
);
268 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_BEACON
);
269 beacon_ie
->ie_length
=
270 cpu_to_le16(params
->beacon
.beacon_ies_len
);
271 memcpy(beacon_ie
->ie_buffer
, params
->beacon
.beacon_ies
,
272 params
->beacon
.beacon_ies_len
);
275 if (params
->beacon
.proberesp_ies
&& params
->beacon
.proberesp_ies_len
) {
276 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
282 pr_ie
->ie_index
= cpu_to_le16(pr_idx
);
283 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MGMT_MASK_PROBE_RESP
);
285 cpu_to_le16(params
->beacon
.proberesp_ies_len
);
286 memcpy(pr_ie
->ie_buffer
, params
->beacon
.proberesp_ies
,
287 params
->beacon
.proberesp_ies_len
);
290 if (params
->beacon
.assocresp_ies
&& params
->beacon
.assocresp_ies_len
) {
291 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
297 ar_ie
->ie_index
= cpu_to_le16(ar_idx
);
298 mask
= MGMT_MASK_ASSOC_RESP
| MGMT_MASK_REASSOC_RESP
;
299 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(mask
);
301 cpu_to_le16(params
->beacon
.assocresp_ies_len
);
302 memcpy(ar_ie
->ie_buffer
, params
->beacon
.assocresp_ies
,
303 params
->beacon
.assocresp_ies_len
);
306 if (beacon_ie
|| pr_ie
|| ar_ie
) {
307 ret
= mwifiex_update_uap_custom_ie(priv
, beacon_ie
,
309 &pr_idx
, ar_ie
, &ar_idx
);
314 priv
->beacon_idx
= beacon_idx
;
315 priv
->proberesp_idx
= pr_idx
;
316 priv
->assocresp_idx
= ar_idx
;
327 /* This function removes management IE set */
328 int mwifiex_del_mgmt_ies(struct mwifiex_private
*priv
)
330 struct mwifiex_ie
*beacon_ie
= NULL
, *pr_ie
= NULL
;
331 struct mwifiex_ie
*ar_ie
= NULL
, *rsn_ie
= NULL
;
334 if (priv
->rsn_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
335 rsn_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
339 rsn_ie
->ie_index
= cpu_to_le16(priv
->rsn_idx
);
340 rsn_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
341 rsn_ie
->ie_length
= 0;
342 if (mwifiex_update_uap_custom_ie(priv
, rsn_ie
, &priv
->rsn_idx
,
343 NULL
, &priv
->proberesp_idx
,
344 NULL
, &priv
->assocresp_idx
)) {
349 priv
->rsn_idx
= MWIFIEX_AUTO_IDX_MASK
;
352 if (priv
->beacon_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
353 beacon_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
358 beacon_ie
->ie_index
= cpu_to_le16(priv
->beacon_idx
);
359 beacon_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
360 beacon_ie
->ie_length
= 0;
362 if (priv
->proberesp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
363 pr_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
368 pr_ie
->ie_index
= cpu_to_le16(priv
->proberesp_idx
);
369 pr_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
370 pr_ie
->ie_length
= 0;
372 if (priv
->assocresp_idx
!= MWIFIEX_AUTO_IDX_MASK
) {
373 ar_ie
= kmalloc(sizeof(struct mwifiex_ie
), GFP_KERNEL
);
378 ar_ie
->ie_index
= cpu_to_le16(priv
->assocresp_idx
);
379 ar_ie
->mgmt_subtype_mask
= cpu_to_le16(MWIFIEX_DELETE_MASK
);
380 ar_ie
->ie_length
= 0;
383 if (beacon_ie
|| pr_ie
|| ar_ie
)
384 ret
= mwifiex_update_uap_custom_ie(priv
,
385 beacon_ie
, &priv
->beacon_idx
,
386 pr_ie
, &priv
->proberesp_idx
,
387 ar_ie
, &priv
->assocresp_idx
);