Merge branch 'x86-debug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.git] / drivers / net / wireless / mwifiex / uap_cmd.c
CommitLineData
40d07030
AP
1/*
2 * Marvell Wireless LAN device driver: AP specific command handling
3 *
4 * Copyright (C) 2012, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "main.h"
21
f752dcd5
AP
22/* This function parses security related parameters from cfg80211_ap_settings
23 * and sets into FW understandable bss_config structure.
24 */
25int mwifiex_set_secure_params(struct mwifiex_private *priv,
26 struct mwifiex_uap_bss_param *bss_config,
27 struct cfg80211_ap_settings *params) {
28 int i;
29
6ddcd464
AP
30 if (!params->privacy) {
31 bss_config->protocol = PROTOCOL_NO_SECURITY;
32 bss_config->key_mgmt = KEY_MGMT_NONE;
33 bss_config->wpa_cfg.length = 0;
34 priv->sec_info.wep_enabled = 0;
35 priv->sec_info.wpa_enabled = 0;
36 priv->sec_info.wpa2_enabled = 0;
37
38 return 0;
39 }
40
f752dcd5
AP
41 switch (params->auth_type) {
42 case NL80211_AUTHTYPE_OPEN_SYSTEM:
43 bss_config->auth_mode = WLAN_AUTH_OPEN;
44 break;
45 case NL80211_AUTHTYPE_SHARED_KEY:
46 bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
47 break;
48 case NL80211_AUTHTYPE_NETWORK_EAP:
49 bss_config->auth_mode = WLAN_AUTH_LEAP;
50 break;
51 default:
52 bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
53 break;
54 }
55
56 bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
57
58 for (i = 0; i < params->crypto.n_akm_suites; i++) {
59 switch (params->crypto.akm_suites[i]) {
60 case WLAN_AKM_SUITE_8021X:
61 if (params->crypto.wpa_versions &
62 NL80211_WPA_VERSION_1) {
63 bss_config->protocol = PROTOCOL_WPA;
64 bss_config->key_mgmt = KEY_MGMT_EAP;
65 }
66 if (params->crypto.wpa_versions &
67 NL80211_WPA_VERSION_2) {
68 bss_config->protocol = PROTOCOL_WPA2;
69 bss_config->key_mgmt = KEY_MGMT_EAP;
70 }
71 break;
72 case WLAN_AKM_SUITE_PSK:
73 if (params->crypto.wpa_versions &
74 NL80211_WPA_VERSION_1) {
75 bss_config->protocol = PROTOCOL_WPA;
76 bss_config->key_mgmt = KEY_MGMT_PSK;
77 }
78 if (params->crypto.wpa_versions &
79 NL80211_WPA_VERSION_2) {
80 bss_config->protocol = PROTOCOL_WPA2;
81 bss_config->key_mgmt = KEY_MGMT_PSK;
82 }
83 break;
84 default:
85 break;
86 }
87 }
88 for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
89 switch (params->crypto.ciphers_pairwise[i]) {
90 case WLAN_CIPHER_SUITE_WEP40:
91 case WLAN_CIPHER_SUITE_WEP104:
92 break;
93 case WLAN_CIPHER_SUITE_TKIP:
94 bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
95 break;
96 case WLAN_CIPHER_SUITE_CCMP:
97 bss_config->wpa_cfg.pairwise_cipher_wpa2 =
98 CIPHER_AES_CCMP;
99 default:
100 break;
101 }
102 }
103
104 switch (params->crypto.cipher_group) {
105 case WLAN_CIPHER_SUITE_WEP40:
106 case WLAN_CIPHER_SUITE_WEP104:
107 break;
108 case WLAN_CIPHER_SUITE_TKIP:
109 bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
110 break;
111 case WLAN_CIPHER_SUITE_CCMP:
112 bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
113 break;
114 default:
115 break;
116 }
117
118 return 0;
119}
120
9b930eae
AP
121/* This function initializes some of mwifiex_uap_bss_param variables.
122 * This helps FW in ignoring invalid values. These values may or may not
123 * be get updated to valid ones at later stage.
124 */
125void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
126{
f752dcd5
AP
127 config->bcast_ssid_ctl = 0x7F;
128 config->radio_ctl = 0x7F;
129 config->dtim_period = 0x7F;
130 config->beacon_period = 0x7FFF;
131 config->auth_mode = 0x7F;
9b930eae
AP
132 config->rts_threshold = 0x7FFF;
133 config->frag_threshold = 0x7FFF;
134 config->retry_limit = 0x7F;
135}
136
e76268da
AP
137/* This function parses BSS related parameters from structure
138 * and prepares TLVs. These TLVs are appended to command buffer.
139*/
140static int
141mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
4db16a18 142{
12190c5d
AP
143 struct host_cmd_tlv_dtim_period *dtim_period;
144 struct host_cmd_tlv_beacon_period *beacon_period;
145 struct host_cmd_tlv_ssid *ssid;
7a1c9934 146 struct host_cmd_tlv_bcast_ssid *bcast_ssid;
4db16a18 147 struct host_cmd_tlv_channel_band *chan_band;
9b930eae
AP
148 struct host_cmd_tlv_frag_threshold *frag_threshold;
149 struct host_cmd_tlv_rts_threshold *rts_threshold;
150 struct host_cmd_tlv_retry_limit *retry_limit;
f752dcd5
AP
151 struct host_cmd_tlv_pwk_cipher *pwk_cipher;
152 struct host_cmd_tlv_gwk_cipher *gwk_cipher;
153 struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
154 struct host_cmd_tlv_auth_type *auth_type;
155 struct host_cmd_tlv_passphrase *passphrase;
156 struct host_cmd_tlv_akmp *tlv_akmp;
4db16a18 157 struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
e76268da 158 u16 cmd_size = *param_size;
4db16a18 159
12190c5d
AP
160 if (bss_cfg->ssid.ssid_len) {
161 ssid = (struct host_cmd_tlv_ssid *)tlv;
162 ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
163 ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
164 memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
165 cmd_size += sizeof(struct host_cmd_tlv) +
166 bss_cfg->ssid.ssid_len;
167 tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
7a1c9934
AP
168
169 bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
170 bcast_ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
171 bcast_ssid->tlv.len =
172 cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
173 bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
174 cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
175 tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
12190c5d 176 }
4db16a18
AP
177 if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
178 chan_band = (struct host_cmd_tlv_channel_band *)tlv;
179 chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
180 chan_band->tlv.len =
181 cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
182 sizeof(struct host_cmd_tlv));
183 chan_band->band_config = bss_cfg->band_cfg;
184 chan_band->channel = bss_cfg->channel;
185 cmd_size += sizeof(struct host_cmd_tlv_channel_band);
186 tlv += sizeof(struct host_cmd_tlv_channel_band);
187 }
12190c5d
AP
188 if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
189 bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
190 beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
191 beacon_period->tlv.type =
192 cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
193 beacon_period->tlv.len =
194 cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
195 sizeof(struct host_cmd_tlv));
196 beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
197 cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
198 tlv += sizeof(struct host_cmd_tlv_beacon_period);
199 }
200 if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
201 bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
202 dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
203 dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
204 dtim_period->tlv.len =
205 cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
206 sizeof(struct host_cmd_tlv));
207 dtim_period->period = bss_cfg->dtim_period;
208 cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
209 tlv += sizeof(struct host_cmd_tlv_dtim_period);
210 }
9b930eae
AP
211 if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
212 rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
213 rts_threshold->tlv.type =
214 cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
215 rts_threshold->tlv.len =
216 cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
217 sizeof(struct host_cmd_tlv));
218 rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
219 cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
220 tlv += sizeof(struct host_cmd_tlv_frag_threshold);
221 }
222 if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
223 (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
224 frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
225 frag_threshold->tlv.type =
226 cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
227 frag_threshold->tlv.len =
228 cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
229 sizeof(struct host_cmd_tlv));
230 frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
231 cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
232 tlv += sizeof(struct host_cmd_tlv_frag_threshold);
233 }
234 if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
235 retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
236 retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
237 retry_limit->tlv.len =
238 cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
239 sizeof(struct host_cmd_tlv));
240 retry_limit->limit = (u8)bss_cfg->retry_limit;
241 cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
242 tlv += sizeof(struct host_cmd_tlv_retry_limit);
243 }
f752dcd5
AP
244 if ((bss_cfg->protocol & PROTOCOL_WPA) ||
245 (bss_cfg->protocol & PROTOCOL_WPA2) ||
246 (bss_cfg->protocol & PROTOCOL_EAP)) {
247 tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
248 tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
249 tlv_akmp->tlv.len =
250 cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
251 sizeof(struct host_cmd_tlv));
252 tlv_akmp->key_mgmt_operation =
253 cpu_to_le16(bss_cfg->key_mgmt_operation);
254 tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
255 cmd_size += sizeof(struct host_cmd_tlv_akmp);
256 tlv += sizeof(struct host_cmd_tlv_akmp);
257
258 if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
259 VALID_CIPHER_BITMAP) {
260 pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
261 pwk_cipher->tlv.type =
262 cpu_to_le16(TLV_TYPE_PWK_CIPHER);
263 pwk_cipher->tlv.len = cpu_to_le16(
264 sizeof(struct host_cmd_tlv_pwk_cipher) -
265 sizeof(struct host_cmd_tlv));
266 pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
267 pwk_cipher->cipher =
268 bss_cfg->wpa_cfg.pairwise_cipher_wpa;
269 cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
270 tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
271 }
272 if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
273 VALID_CIPHER_BITMAP) {
274 pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
275 pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
276 pwk_cipher->tlv.len = cpu_to_le16(
277 sizeof(struct host_cmd_tlv_pwk_cipher) -
278 sizeof(struct host_cmd_tlv));
279 pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
280 pwk_cipher->cipher =
281 bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
282 cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
283 tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
284 }
285 if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
286 gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
287 gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
288 gwk_cipher->tlv.len = cpu_to_le16(
289 sizeof(struct host_cmd_tlv_gwk_cipher) -
290 sizeof(struct host_cmd_tlv));
291 gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
292 cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
293 tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
294 }
295 if (bss_cfg->wpa_cfg.length) {
296 passphrase = (struct host_cmd_tlv_passphrase *)tlv;
297 passphrase->tlv.type =
298 cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
299 passphrase->tlv.len =
300 cpu_to_le16(bss_cfg->wpa_cfg.length);
301 memcpy(passphrase->passphrase,
302 bss_cfg->wpa_cfg.passphrase,
303 bss_cfg->wpa_cfg.length);
304 cmd_size += sizeof(struct host_cmd_tlv) +
305 bss_cfg->wpa_cfg.length;
306 tlv += sizeof(struct host_cmd_tlv) +
307 bss_cfg->wpa_cfg.length;
308 }
309 }
310 if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
311 (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
312 auth_type = (struct host_cmd_tlv_auth_type *)tlv;
313 auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
314 auth_type->tlv.len =
315 cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
316 sizeof(struct host_cmd_tlv));
317 auth_type->auth_type = (u8)bss_cfg->auth_mode;
318 cmd_size += sizeof(struct host_cmd_tlv_auth_type);
319 tlv += sizeof(struct host_cmd_tlv_auth_type);
320 }
321 if (bss_cfg->protocol) {
322 encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
323 encrypt_protocol->tlv.type =
324 cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
325 encrypt_protocol->tlv.len =
326 cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
327 - sizeof(struct host_cmd_tlv));
328 encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
329 cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
330 tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
331 }
4db16a18 332
e76268da
AP
333 *param_size = cmd_size;
334
335 return 0;
336}
337
ede98bfa
AP
338/* This function parses custom IEs from IE list and prepares command buffer */
339static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
340{
341 struct mwifiex_ie_list *ap_ie = cmd_buf;
342 struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv;
343
344 if (!ap_ie || !ap_ie->len || !ap_ie->ie_list)
345 return -1;
346
347 *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv);
348
349 tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
350 tlv_ie->len = ap_ie->len;
351 tlv += sizeof(struct host_cmd_tlv);
352
353 memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
354
355 return 0;
356}
357
e76268da
AP
358/* Parse AP config structure and prepare TLV based command structure
359 * to be sent to FW for uAP configuration
360 */
361static int
362mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
363 u32 type, void *cmd_buf)
364{
365 u8 *tlv;
ede98bfa 366 u16 cmd_size, param_size, ie_size;
e76268da
AP
367 struct host_cmd_ds_sys_config *sys_cfg;
368
369 cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
370 cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
371 sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
372 sys_cfg->action = cpu_to_le16(cmd_action);
373 tlv = sys_cfg->tlv;
374
375 switch (type) {
376 case UAP_BSS_PARAMS_I:
377 param_size = cmd_size;
378 if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
379 return -1;
380 cmd->size = cpu_to_le16(param_size);
381 break;
ede98bfa
AP
382 case UAP_CUSTOM_IE_I:
383 ie_size = cmd_size;
384 if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
385 return -1;
386 cmd->size = cpu_to_le16(ie_size);
387 break;
e76268da
AP
388 default:
389 return -1;
390 }
391
4db16a18
AP
392 return 0;
393}
394
40d07030
AP
395/* This function prepares the AP specific commands before sending them
396 * to the firmware.
397 * This is a generic function which calls specific command preparation
398 * routines based upon the command number.
399 */
400int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
e76268da 401 u16 cmd_action, u32 type,
40d07030
AP
402 void *data_buf, void *cmd_buf)
403{
404 struct host_cmd_ds_command *cmd = cmd_buf;
405
406 switch (cmd_no) {
4db16a18 407 case HostCmd_CMD_UAP_SYS_CONFIG:
e76268da 408 if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
4db16a18
AP
409 return -1;
410 break;
40d07030
AP
411 case HostCmd_CMD_UAP_BSS_START:
412 case HostCmd_CMD_UAP_BSS_STOP:
413 cmd->command = cpu_to_le16(cmd_no);
414 cmd->size = cpu_to_le16(S_DS_GEN);
415 break;
416 default:
417 dev_err(priv->adapter->dev,
418 "PREP_CMD: unknown cmd %#x\n", cmd_no);
419 return -1;
420 }
421
422 return 0;
423}
4db16a18
AP
424
425/* This function sets the RF channel for AP.
426 *
427 * This function populates channel information in AP config structure
428 * and sends command to configure channel information in AP.
429 */
430int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
431{
432 struct mwifiex_uap_bss_param *bss_cfg;
433 struct wiphy *wiphy = priv->wdev->wiphy;
434
435 bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
436 if (!bss_cfg)
437 return -ENOMEM;
438
f0e3bd23 439 mwifiex_set_sys_config_invalid_data(bss_cfg);
4db16a18
AP
440 bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
441 bss_cfg->channel = channel;
442
443 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
e76268da
AP
444 HostCmd_ACT_GEN_SET,
445 UAP_BSS_PARAMS_I, bss_cfg)) {
4db16a18
AP
446 wiphy_err(wiphy, "Failed to set the uAP channel\n");
447 kfree(bss_cfg);
448 return -1;
449 }
450
451 kfree(bss_cfg);
452 return 0;
453}
This page took 0.068017 seconds and 5 git commands to generate.