uap_cmd.c revision f752dcd52923b8de82881cf1269f0dc03dbd1088
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
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
30	switch (params->auth_type) {
31	case NL80211_AUTHTYPE_OPEN_SYSTEM:
32		bss_config->auth_mode = WLAN_AUTH_OPEN;
33		break;
34	case NL80211_AUTHTYPE_SHARED_KEY:
35		bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
36		break;
37	case NL80211_AUTHTYPE_NETWORK_EAP:
38		bss_config->auth_mode = WLAN_AUTH_LEAP;
39		break;
40	default:
41		bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
42		break;
43	}
44
45	bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
46
47	for (i = 0; i < params->crypto.n_akm_suites; i++) {
48		switch (params->crypto.akm_suites[i]) {
49		case WLAN_AKM_SUITE_8021X:
50			if (params->crypto.wpa_versions &
51			    NL80211_WPA_VERSION_1) {
52				bss_config->protocol = PROTOCOL_WPA;
53				bss_config->key_mgmt = KEY_MGMT_EAP;
54			}
55			if (params->crypto.wpa_versions &
56			    NL80211_WPA_VERSION_2) {
57				bss_config->protocol = PROTOCOL_WPA2;
58				bss_config->key_mgmt = KEY_MGMT_EAP;
59			}
60			break;
61		case WLAN_AKM_SUITE_PSK:
62			if (params->crypto.wpa_versions &
63			    NL80211_WPA_VERSION_1) {
64				bss_config->protocol = PROTOCOL_WPA;
65				bss_config->key_mgmt = KEY_MGMT_PSK;
66			}
67			if (params->crypto.wpa_versions &
68			    NL80211_WPA_VERSION_2) {
69				bss_config->protocol = PROTOCOL_WPA2;
70				bss_config->key_mgmt = KEY_MGMT_PSK;
71			}
72			break;
73		default:
74			break;
75		}
76	}
77	for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
78		switch (params->crypto.ciphers_pairwise[i]) {
79		case WLAN_CIPHER_SUITE_WEP40:
80		case WLAN_CIPHER_SUITE_WEP104:
81			break;
82		case WLAN_CIPHER_SUITE_TKIP:
83			bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
84			break;
85		case WLAN_CIPHER_SUITE_CCMP:
86			bss_config->wpa_cfg.pairwise_cipher_wpa2 =
87								CIPHER_AES_CCMP;
88		default:
89			break;
90		}
91	}
92
93	switch (params->crypto.cipher_group) {
94	case WLAN_CIPHER_SUITE_WEP40:
95	case WLAN_CIPHER_SUITE_WEP104:
96		break;
97	case WLAN_CIPHER_SUITE_TKIP:
98		bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
99		break;
100	case WLAN_CIPHER_SUITE_CCMP:
101		bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
102		break;
103	default:
104		break;
105	}
106
107	return 0;
108}
109
110/* This function initializes some of mwifiex_uap_bss_param variables.
111 * This helps FW in ignoring invalid values. These values may or may not
112 * be get updated to valid ones at later stage.
113 */
114void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
115{
116	config->bcast_ssid_ctl = 0x7F;
117	config->radio_ctl = 0x7F;
118	config->dtim_period = 0x7F;
119	config->beacon_period = 0x7FFF;
120	config->auth_mode = 0x7F;
121	config->rts_threshold = 0x7FFF;
122	config->frag_threshold = 0x7FFF;
123	config->retry_limit = 0x7F;
124}
125
126/* Parse AP config structure and prepare TLV based command structure
127 * to be sent to FW for uAP configuration
128 */
129static int mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd,
130				      u16 cmd_action, void *cmd_buf)
131{
132	u8 *tlv;
133	struct host_cmd_ds_sys_config *sys_config = &cmd->params.uap_sys_config;
134	struct host_cmd_tlv_dtim_period *dtim_period;
135	struct host_cmd_tlv_beacon_period *beacon_period;
136	struct host_cmd_tlv_ssid *ssid;
137	struct host_cmd_tlv_channel_band *chan_band;
138	struct host_cmd_tlv_frag_threshold *frag_threshold;
139	struct host_cmd_tlv_rts_threshold *rts_threshold;
140	struct host_cmd_tlv_retry_limit *retry_limit;
141	struct host_cmd_tlv_pwk_cipher *pwk_cipher;
142	struct host_cmd_tlv_gwk_cipher *gwk_cipher;
143	struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
144	struct host_cmd_tlv_auth_type *auth_type;
145	struct host_cmd_tlv_passphrase *passphrase;
146	struct host_cmd_tlv_akmp *tlv_akmp;
147	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
148	u16 cmd_size;
149
150	cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
151	cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
152
153	sys_config->action = cpu_to_le16(cmd_action);
154
155	tlv = sys_config->tlv;
156
157	if (bss_cfg->ssid.ssid_len) {
158		ssid = (struct host_cmd_tlv_ssid *)tlv;
159		ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
160		ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
161		memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
162		cmd_size += sizeof(struct host_cmd_tlv) +
163			    bss_cfg->ssid.ssid_len;
164		tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
165	}
166	if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
167		chan_band = (struct host_cmd_tlv_channel_band *)tlv;
168		chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
169		chan_band->tlv.len =
170			cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
171				    sizeof(struct host_cmd_tlv));
172		chan_band->band_config = bss_cfg->band_cfg;
173		chan_band->channel = bss_cfg->channel;
174		cmd_size += sizeof(struct host_cmd_tlv_channel_band);
175		tlv += sizeof(struct host_cmd_tlv_channel_band);
176	}
177	if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
178	    bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
179		beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
180		beacon_period->tlv.type =
181					cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
182		beacon_period->tlv.len =
183			cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
184				    sizeof(struct host_cmd_tlv));
185		beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
186		cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
187		tlv += sizeof(struct host_cmd_tlv_beacon_period);
188	}
189	if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
190	    bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
191		dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
192		dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
193		dtim_period->tlv.len =
194			cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
195				    sizeof(struct host_cmd_tlv));
196		dtim_period->period = bss_cfg->dtim_period;
197		cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
198		tlv += sizeof(struct host_cmd_tlv_dtim_period);
199	}
200	if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
201		rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
202		rts_threshold->tlv.type =
203					cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
204		rts_threshold->tlv.len =
205			cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
206				    sizeof(struct host_cmd_tlv));
207		rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
208		cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
209		tlv += sizeof(struct host_cmd_tlv_frag_threshold);
210	}
211	if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
212	    (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
213		frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
214		frag_threshold->tlv.type =
215				cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
216		frag_threshold->tlv.len =
217			cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
218				    sizeof(struct host_cmd_tlv));
219		frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
220		cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
221		tlv += sizeof(struct host_cmd_tlv_frag_threshold);
222	}
223	if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
224		retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
225		retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
226		retry_limit->tlv.len =
227			cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
228				    sizeof(struct host_cmd_tlv));
229		retry_limit->limit = (u8)bss_cfg->retry_limit;
230		cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
231		tlv += sizeof(struct host_cmd_tlv_retry_limit);
232	}
233	if ((bss_cfg->protocol & PROTOCOL_WPA) ||
234	    (bss_cfg->protocol & PROTOCOL_WPA2) ||
235	    (bss_cfg->protocol & PROTOCOL_EAP)) {
236		tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
237		tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
238		tlv_akmp->tlv.len =
239		    cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
240				sizeof(struct host_cmd_tlv));
241		tlv_akmp->key_mgmt_operation =
242			cpu_to_le16(bss_cfg->key_mgmt_operation);
243		tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
244		cmd_size += sizeof(struct host_cmd_tlv_akmp);
245		tlv += sizeof(struct host_cmd_tlv_akmp);
246
247		if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
248				VALID_CIPHER_BITMAP) {
249			pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
250			pwk_cipher->tlv.type =
251				cpu_to_le16(TLV_TYPE_PWK_CIPHER);
252			pwk_cipher->tlv.len = cpu_to_le16(
253				sizeof(struct host_cmd_tlv_pwk_cipher) -
254				sizeof(struct host_cmd_tlv));
255			pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
256			pwk_cipher->cipher =
257				bss_cfg->wpa_cfg.pairwise_cipher_wpa;
258			cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
259			tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
260		}
261		if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
262				VALID_CIPHER_BITMAP) {
263			pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
264			pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
265			pwk_cipher->tlv.len = cpu_to_le16(
266				sizeof(struct host_cmd_tlv_pwk_cipher) -
267				sizeof(struct host_cmd_tlv));
268			pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
269			pwk_cipher->cipher =
270				bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
271			cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
272			tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
273		}
274		if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
275			gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
276			gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
277			gwk_cipher->tlv.len = cpu_to_le16(
278				sizeof(struct host_cmd_tlv_gwk_cipher) -
279				sizeof(struct host_cmd_tlv));
280			gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
281			cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
282			tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
283		}
284		if (bss_cfg->wpa_cfg.length) {
285			passphrase = (struct host_cmd_tlv_passphrase *)tlv;
286			passphrase->tlv.type =
287				cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
288			passphrase->tlv.len =
289				cpu_to_le16(bss_cfg->wpa_cfg.length);
290			memcpy(passphrase->passphrase,
291			       bss_cfg->wpa_cfg.passphrase,
292			       bss_cfg->wpa_cfg.length);
293			cmd_size += sizeof(struct host_cmd_tlv) +
294				    bss_cfg->wpa_cfg.length;
295			tlv += sizeof(struct host_cmd_tlv) +
296			       bss_cfg->wpa_cfg.length;
297		}
298	}
299	if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
300	    (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
301		auth_type = (struct host_cmd_tlv_auth_type *)tlv;
302		auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
303		auth_type->tlv.len =
304			cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
305			sizeof(struct host_cmd_tlv));
306		auth_type->auth_type = (u8)bss_cfg->auth_mode;
307		cmd_size += sizeof(struct host_cmd_tlv_auth_type);
308		tlv += sizeof(struct host_cmd_tlv_auth_type);
309	}
310	if (bss_cfg->protocol) {
311		encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
312		encrypt_protocol->tlv.type =
313			cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
314		encrypt_protocol->tlv.len =
315			cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
316			- sizeof(struct host_cmd_tlv));
317		encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
318		cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
319		tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
320	}
321
322	cmd->size = cpu_to_le16(cmd_size);
323	return 0;
324}
325
326/* This function prepares the AP specific commands before sending them
327 * to the firmware.
328 * This is a generic function which calls specific command preparation
329 * routines based upon the command number.
330 */
331int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
332			    u16 cmd_action, u32 cmd_oid,
333			    void *data_buf, void *cmd_buf)
334{
335	struct host_cmd_ds_command *cmd = cmd_buf;
336
337	switch (cmd_no) {
338	case HostCmd_CMD_UAP_SYS_CONFIG:
339		if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, data_buf))
340			return -1;
341		break;
342	case HostCmd_CMD_UAP_BSS_START:
343	case HostCmd_CMD_UAP_BSS_STOP:
344		cmd->command = cpu_to_le16(cmd_no);
345		cmd->size = cpu_to_le16(S_DS_GEN);
346		break;
347	default:
348		dev_err(priv->adapter->dev,
349			"PREP_CMD: unknown cmd %#x\n", cmd_no);
350		return -1;
351	}
352
353	return 0;
354}
355
356/* This function sets the RF channel for AP.
357 *
358 * This function populates channel information in AP config structure
359 * and sends command to configure channel information in AP.
360 */
361int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
362{
363	struct mwifiex_uap_bss_param *bss_cfg;
364	struct wiphy *wiphy = priv->wdev->wiphy;
365
366	bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
367	if (!bss_cfg)
368		return -ENOMEM;
369
370	bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
371	bss_cfg->channel = channel;
372
373	if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
374				   HostCmd_ACT_GEN_SET, 0, bss_cfg)) {
375		wiphy_err(wiphy, "Failed to set the uAP channel\n");
376		kfree(bss_cfg);
377		return -1;
378	}
379
380	kfree(bss_cfg);
381	return 0;
382}
383