xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/marvell/mwifiex/join.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * NXP Wireless LAN device driver: association and ad-hoc start/join
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 2011-2020 NXP
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This software file (the "File") is distributed by NXP
7*4882a593Smuzhiyun  * under the terms of the GNU General Public License Version 2, June 1991
8*4882a593Smuzhiyun  * (the "License").  You may use, redistribute and/or modify this File in
9*4882a593Smuzhiyun  * accordance with the terms and conditions of the License, a copy of which
10*4882a593Smuzhiyun  * is available by writing to the Free Software Foundation, Inc.,
11*4882a593Smuzhiyun  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12*4882a593Smuzhiyun  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15*4882a593Smuzhiyun  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16*4882a593Smuzhiyun  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
17*4882a593Smuzhiyun  * this warranty disclaimer.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "decl.h"
21*4882a593Smuzhiyun #include "ioctl.h"
22*4882a593Smuzhiyun #include "util.h"
23*4882a593Smuzhiyun #include "fw.h"
24*4882a593Smuzhiyun #include "main.h"
25*4882a593Smuzhiyun #include "wmm.h"
26*4882a593Smuzhiyun #include "11n.h"
27*4882a593Smuzhiyun #include "11ac.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define CAPINFO_MASK    (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * Append a generic IE as a pass through TLV to a TLV buffer.
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * This function is called from the network join command preparation routine.
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * If the IE buffer has been setup by the application, this routine appends
37*4882a593Smuzhiyun  * the buffer as a pass through TLV type to the request.
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun static int
mwifiex_cmd_append_generic_ie(struct mwifiex_private * priv,u8 ** buffer)40*4882a593Smuzhiyun mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	int ret_len = 0;
43*4882a593Smuzhiyun 	struct mwifiex_ie_types_header ie_header;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	/* Null Checks */
46*4882a593Smuzhiyun 	if (!buffer)
47*4882a593Smuzhiyun 		return 0;
48*4882a593Smuzhiyun 	if (!(*buffer))
49*4882a593Smuzhiyun 		return 0;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	/*
52*4882a593Smuzhiyun 	 * If there is a generic ie buffer setup, append it to the return
53*4882a593Smuzhiyun 	 *   parameter buffer pointer.
54*4882a593Smuzhiyun 	 */
55*4882a593Smuzhiyun 	if (priv->gen_ie_buf_len) {
56*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO,
57*4882a593Smuzhiyun 			    "info: %s: append generic ie len %d to %p\n",
58*4882a593Smuzhiyun 			    __func__, priv->gen_ie_buf_len, *buffer);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 		/* Wrap the generic IE buffer with a pass through TLV type */
61*4882a593Smuzhiyun 		ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
62*4882a593Smuzhiyun 		ie_header.len = cpu_to_le16(priv->gen_ie_buf_len);
63*4882a593Smuzhiyun 		memcpy(*buffer, &ie_header, sizeof(ie_header));
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		/* Increment the return size and the return buffer pointer
66*4882a593Smuzhiyun 		   param */
67*4882a593Smuzhiyun 		*buffer += sizeof(ie_header);
68*4882a593Smuzhiyun 		ret_len += sizeof(ie_header);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 		/* Copy the generic IE buffer to the output buffer, advance
71*4882a593Smuzhiyun 		   pointer */
72*4882a593Smuzhiyun 		memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 		/* Increment the return size and the return buffer pointer
75*4882a593Smuzhiyun 		   param */
76*4882a593Smuzhiyun 		*buffer += priv->gen_ie_buf_len;
77*4882a593Smuzhiyun 		ret_len += priv->gen_ie_buf_len;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		/* Reset the generic IE buffer */
80*4882a593Smuzhiyun 		priv->gen_ie_buf_len = 0;
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/* return the length appended to the buffer */
84*4882a593Smuzhiyun 	return ret_len;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /*
88*4882a593Smuzhiyun  * Append TSF tracking info from the scan table for the target AP.
89*4882a593Smuzhiyun  *
90*4882a593Smuzhiyun  * This function is called from the network join command preparation routine.
91*4882a593Smuzhiyun  *
92*4882a593Smuzhiyun  * The TSF table TSF sent to the firmware contains two TSF values:
93*4882a593Smuzhiyun  *      - The TSF of the target AP from its previous beacon/probe response
94*4882a593Smuzhiyun  *      - The TSF timestamp of our local MAC at the time we observed the
95*4882a593Smuzhiyun  *        beacon/probe response.
96*4882a593Smuzhiyun  *
97*4882a593Smuzhiyun  * The firmware uses the timestamp values to set an initial TSF value
98*4882a593Smuzhiyun  * in the MAC for the new association after a reassociation attempt.
99*4882a593Smuzhiyun  */
100*4882a593Smuzhiyun static int
mwifiex_cmd_append_tsf_tlv(struct mwifiex_private * priv,u8 ** buffer,struct mwifiex_bssdescriptor * bss_desc)101*4882a593Smuzhiyun mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
102*4882a593Smuzhiyun 			   struct mwifiex_bssdescriptor *bss_desc)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	struct mwifiex_ie_types_tsf_timestamp tsf_tlv;
105*4882a593Smuzhiyun 	__le64 tsf_val;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	/* Null Checks */
108*4882a593Smuzhiyun 	if (buffer == NULL)
109*4882a593Smuzhiyun 		return 0;
110*4882a593Smuzhiyun 	if (*buffer == NULL)
111*4882a593Smuzhiyun 		return 0;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp));
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
116*4882a593Smuzhiyun 	tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val));
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header));
119*4882a593Smuzhiyun 	*buffer += sizeof(tsf_tlv.header);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* TSF at the time when beacon/probe_response was received */
122*4882a593Smuzhiyun 	tsf_val = cpu_to_le64(bss_desc->fw_tsf);
123*4882a593Smuzhiyun 	memcpy(*buffer, &tsf_val, sizeof(tsf_val));
124*4882a593Smuzhiyun 	*buffer += sizeof(tsf_val);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	tsf_val = cpu_to_le64(bss_desc->timestamp);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
129*4882a593Smuzhiyun 		    "info: %s: TSF offset calc: %016llx - %016llx\n",
130*4882a593Smuzhiyun 		    __func__, bss_desc->timestamp, bss_desc->fw_tsf);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	memcpy(*buffer, &tsf_val, sizeof(tsf_val));
133*4882a593Smuzhiyun 	*buffer += sizeof(tsf_val);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun  * This function finds out the common rates between rate1 and rate2.
140*4882a593Smuzhiyun  *
141*4882a593Smuzhiyun  * It will fill common rates in rate1 as output if found.
142*4882a593Smuzhiyun  *
143*4882a593Smuzhiyun  * NOTE: Setting the MSB of the basic rates needs to be taken
144*4882a593Smuzhiyun  * care of, either before or after calling this function.
145*4882a593Smuzhiyun  */
mwifiex_get_common_rates(struct mwifiex_private * priv,u8 * rate1,u32 rate1_size,u8 * rate2,u32 rate2_size)146*4882a593Smuzhiyun static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
147*4882a593Smuzhiyun 				    u32 rate1_size, u8 *rate2, u32 rate2_size)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	int ret;
150*4882a593Smuzhiyun 	u8 *ptr = rate1, *tmp;
151*4882a593Smuzhiyun 	u32 i, j;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	tmp = kmemdup(rate1, rate1_size, GFP_KERNEL);
154*4882a593Smuzhiyun 	if (!tmp) {
155*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR, "failed to alloc tmp buf\n");
156*4882a593Smuzhiyun 		return -ENOMEM;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	memset(rate1, 0, rate1_size);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	for (i = 0; i < rate2_size && rate2[i]; i++) {
162*4882a593Smuzhiyun 		for (j = 0; j < rate1_size && tmp[j]; j++) {
163*4882a593Smuzhiyun 			/* Check common rate, excluding the bit for
164*4882a593Smuzhiyun 			   basic rate */
165*4882a593Smuzhiyun 			if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
166*4882a593Smuzhiyun 				*rate1++ = tmp[j];
167*4882a593Smuzhiyun 				break;
168*4882a593Smuzhiyun 			}
169*4882a593Smuzhiyun 		}
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n",
173*4882a593Smuzhiyun 		    priv->data_rate);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (!priv->is_data_rate_auto) {
176*4882a593Smuzhiyun 		while (*ptr) {
177*4882a593Smuzhiyun 			if ((*ptr & 0x7f) == priv->data_rate) {
178*4882a593Smuzhiyun 				ret = 0;
179*4882a593Smuzhiyun 				goto done;
180*4882a593Smuzhiyun 			}
181*4882a593Smuzhiyun 			ptr++;
182*4882a593Smuzhiyun 		}
183*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR,
184*4882a593Smuzhiyun 			    "previously set fixed data rate %#x\t"
185*4882a593Smuzhiyun 			    "is not compatible with the network\n",
186*4882a593Smuzhiyun 			    priv->data_rate);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		ret = -1;
189*4882a593Smuzhiyun 		goto done;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	ret = 0;
193*4882a593Smuzhiyun done:
194*4882a593Smuzhiyun 	kfree(tmp);
195*4882a593Smuzhiyun 	return ret;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun /*
199*4882a593Smuzhiyun  * This function creates the intersection of the rates supported by a
200*4882a593Smuzhiyun  * target BSS and our adapter settings for use in an assoc/join command.
201*4882a593Smuzhiyun  */
202*4882a593Smuzhiyun static int
mwifiex_setup_rates_from_bssdesc(struct mwifiex_private * priv,struct mwifiex_bssdescriptor * bss_desc,u8 * out_rates,u32 * out_rates_size)203*4882a593Smuzhiyun mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
204*4882a593Smuzhiyun 				 struct mwifiex_bssdescriptor *bss_desc,
205*4882a593Smuzhiyun 				 u8 *out_rates, u32 *out_rates_size)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	u8 card_rates[MWIFIEX_SUPPORTED_RATES];
208*4882a593Smuzhiyun 	u32 card_rates_size;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* Copy AP supported rates */
211*4882a593Smuzhiyun 	memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
212*4882a593Smuzhiyun 	/* Get the STA supported rates */
213*4882a593Smuzhiyun 	card_rates_size = mwifiex_get_active_data_rates(priv, card_rates);
214*4882a593Smuzhiyun 	/* Get the common rates between AP and STA supported rates */
215*4882a593Smuzhiyun 	if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
216*4882a593Smuzhiyun 				     card_rates, card_rates_size)) {
217*4882a593Smuzhiyun 		*out_rates_size = 0;
218*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR,
219*4882a593Smuzhiyun 			    "%s: cannot get common rates\n",
220*4882a593Smuzhiyun 			    __func__);
221*4882a593Smuzhiyun 		return -1;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	*out_rates_size =
225*4882a593Smuzhiyun 		min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun /*
231*4882a593Smuzhiyun  * This function appends a WPS IE. It is called from the network join command
232*4882a593Smuzhiyun  * preparation routine.
233*4882a593Smuzhiyun  *
234*4882a593Smuzhiyun  * If the IE buffer has been setup by the application, this routine appends
235*4882a593Smuzhiyun  * the buffer as a WPS TLV type to the request.
236*4882a593Smuzhiyun  */
237*4882a593Smuzhiyun static int
mwifiex_cmd_append_wps_ie(struct mwifiex_private * priv,u8 ** buffer)238*4882a593Smuzhiyun mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	int retLen = 0;
241*4882a593Smuzhiyun 	struct mwifiex_ie_types_header ie_header;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (!buffer || !*buffer)
244*4882a593Smuzhiyun 		return 0;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/*
247*4882a593Smuzhiyun 	 * If there is a wps ie buffer setup, append it to the return
248*4882a593Smuzhiyun 	 * parameter buffer pointer.
249*4882a593Smuzhiyun 	 */
250*4882a593Smuzhiyun 	if (priv->wps_ie_len) {
251*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, CMD,
252*4882a593Smuzhiyun 			    "cmd: append wps ie %d to %p\n",
253*4882a593Smuzhiyun 			    priv->wps_ie_len, *buffer);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 		/* Wrap the generic IE buffer with a pass through TLV type */
256*4882a593Smuzhiyun 		ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
257*4882a593Smuzhiyun 		ie_header.len = cpu_to_le16(priv->wps_ie_len);
258*4882a593Smuzhiyun 		memcpy(*buffer, &ie_header, sizeof(ie_header));
259*4882a593Smuzhiyun 		*buffer += sizeof(ie_header);
260*4882a593Smuzhiyun 		retLen += sizeof(ie_header);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		memcpy(*buffer, priv->wps_ie, priv->wps_ie_len);
263*4882a593Smuzhiyun 		*buffer += priv->wps_ie_len;
264*4882a593Smuzhiyun 		retLen += priv->wps_ie_len;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	kfree(priv->wps_ie);
269*4882a593Smuzhiyun 	priv->wps_ie_len = 0;
270*4882a593Smuzhiyun 	return retLen;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun /*
274*4882a593Smuzhiyun  * This function appends a WAPI IE.
275*4882a593Smuzhiyun  *
276*4882a593Smuzhiyun  * This function is called from the network join command preparation routine.
277*4882a593Smuzhiyun  *
278*4882a593Smuzhiyun  * If the IE buffer has been setup by the application, this routine appends
279*4882a593Smuzhiyun  * the buffer as a WAPI TLV type to the request.
280*4882a593Smuzhiyun  */
281*4882a593Smuzhiyun static int
mwifiex_cmd_append_wapi_ie(struct mwifiex_private * priv,u8 ** buffer)282*4882a593Smuzhiyun mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	int retLen = 0;
285*4882a593Smuzhiyun 	struct mwifiex_ie_types_header ie_header;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* Null Checks */
288*4882a593Smuzhiyun 	if (buffer == NULL)
289*4882a593Smuzhiyun 		return 0;
290*4882a593Smuzhiyun 	if (*buffer == NULL)
291*4882a593Smuzhiyun 		return 0;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/*
294*4882a593Smuzhiyun 	 * If there is a wapi ie buffer setup, append it to the return
295*4882a593Smuzhiyun 	 *   parameter buffer pointer.
296*4882a593Smuzhiyun 	 */
297*4882a593Smuzhiyun 	if (priv->wapi_ie_len) {
298*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, CMD,
299*4882a593Smuzhiyun 			    "cmd: append wapi ie %d to %p\n",
300*4882a593Smuzhiyun 			    priv->wapi_ie_len, *buffer);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 		/* Wrap the generic IE buffer with a pass through TLV type */
303*4882a593Smuzhiyun 		ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
304*4882a593Smuzhiyun 		ie_header.len = cpu_to_le16(priv->wapi_ie_len);
305*4882a593Smuzhiyun 		memcpy(*buffer, &ie_header, sizeof(ie_header));
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		/* Increment the return size and the return buffer pointer
308*4882a593Smuzhiyun 		   param */
309*4882a593Smuzhiyun 		*buffer += sizeof(ie_header);
310*4882a593Smuzhiyun 		retLen += sizeof(ie_header);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 		/* Copy the wapi IE buffer to the output buffer, advance
313*4882a593Smuzhiyun 		   pointer */
314*4882a593Smuzhiyun 		memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 		/* Increment the return size and the return buffer pointer
317*4882a593Smuzhiyun 		   param */
318*4882a593Smuzhiyun 		*buffer += priv->wapi_ie_len;
319*4882a593Smuzhiyun 		retLen += priv->wapi_ie_len;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 	/* return the length appended to the buffer */
323*4882a593Smuzhiyun 	return retLen;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun /*
327*4882a593Smuzhiyun  * This function appends rsn ie tlv for wpa/wpa2 security modes.
328*4882a593Smuzhiyun  * It is called from the network join command preparation routine.
329*4882a593Smuzhiyun  */
mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private * priv,u8 ** buffer)330*4882a593Smuzhiyun static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv,
331*4882a593Smuzhiyun 					  u8 **buffer)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv;
334*4882a593Smuzhiyun 	int rsn_ie_len;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (!buffer || !(*buffer))
337*4882a593Smuzhiyun 		return 0;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer);
340*4882a593Smuzhiyun 	rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]);
341*4882a593Smuzhiyun 	rsn_ie_tlv->header.type = cpu_to_le16(
342*4882a593Smuzhiyun 				 le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF);
343*4882a593Smuzhiyun 	rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]);
344*4882a593Smuzhiyun 	rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len)
345*4882a593Smuzhiyun 							 & 0x00FF);
346*4882a593Smuzhiyun 	if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2))
347*4882a593Smuzhiyun 		memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2],
348*4882a593Smuzhiyun 		       le16_to_cpu(rsn_ie_tlv->header.len));
349*4882a593Smuzhiyun 	else
350*4882a593Smuzhiyun 		return -1;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	rsn_ie_len = sizeof(rsn_ie_tlv->header) +
353*4882a593Smuzhiyun 					le16_to_cpu(rsn_ie_tlv->header.len);
354*4882a593Smuzhiyun 	*buffer += rsn_ie_len;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	return rsn_ie_len;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun /*
360*4882a593Smuzhiyun  * This function prepares command for association.
361*4882a593Smuzhiyun  *
362*4882a593Smuzhiyun  * This sets the following parameters -
363*4882a593Smuzhiyun  *      - Peer MAC address
364*4882a593Smuzhiyun  *      - Listen interval
365*4882a593Smuzhiyun  *      - Beacon interval
366*4882a593Smuzhiyun  *      - Capability information
367*4882a593Smuzhiyun  *
368*4882a593Smuzhiyun  * ...and the following TLVs, as required -
369*4882a593Smuzhiyun  *      - SSID TLV
370*4882a593Smuzhiyun  *      - PHY TLV
371*4882a593Smuzhiyun  *      - SS TLV
372*4882a593Smuzhiyun  *      - Rates TLV
373*4882a593Smuzhiyun  *      - Authentication TLV
374*4882a593Smuzhiyun  *      - Channel TLV
375*4882a593Smuzhiyun  *      - WPA/WPA2 IE
376*4882a593Smuzhiyun  *      - 11n TLV
377*4882a593Smuzhiyun  *      - Vendor specific TLV
378*4882a593Smuzhiyun  *      - WMM TLV
379*4882a593Smuzhiyun  *      - WAPI IE
380*4882a593Smuzhiyun  *      - Generic IE
381*4882a593Smuzhiyun  *      - TSF TLV
382*4882a593Smuzhiyun  *
383*4882a593Smuzhiyun  * Preparation also includes -
384*4882a593Smuzhiyun  *      - Setting command ID and proper size
385*4882a593Smuzhiyun  *      - Ensuring correct endian-ness
386*4882a593Smuzhiyun  */
mwifiex_cmd_802_11_associate(struct mwifiex_private * priv,struct host_cmd_ds_command * cmd,struct mwifiex_bssdescriptor * bss_desc)387*4882a593Smuzhiyun int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
388*4882a593Smuzhiyun 				 struct host_cmd_ds_command *cmd,
389*4882a593Smuzhiyun 				 struct mwifiex_bssdescriptor *bss_desc)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun 	struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate;
392*4882a593Smuzhiyun 	struct mwifiex_ie_types_ssid_param_set *ssid_tlv;
393*4882a593Smuzhiyun 	struct mwifiex_ie_types_phy_param_set *phy_tlv;
394*4882a593Smuzhiyun 	struct mwifiex_ie_types_ss_param_set *ss_tlv;
395*4882a593Smuzhiyun 	struct mwifiex_ie_types_rates_param_set *rates_tlv;
396*4882a593Smuzhiyun 	struct mwifiex_ie_types_auth_type *auth_tlv;
397*4882a593Smuzhiyun 	struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
398*4882a593Smuzhiyun 	u8 rates[MWIFIEX_SUPPORTED_RATES];
399*4882a593Smuzhiyun 	u32 rates_size;
400*4882a593Smuzhiyun 	u16 tmp_cap;
401*4882a593Smuzhiyun 	u8 *pos;
402*4882a593Smuzhiyun 	int rsn_ie_len = 0;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	pos = (u8 *) assoc;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	/* Save so we know which BSS Desc to use in the response handler */
409*4882a593Smuzhiyun 	priv->attempted_bss_desc = bss_desc;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	memcpy(assoc->peer_sta_addr,
412*4882a593Smuzhiyun 	       bss_desc->mac_address, sizeof(assoc->peer_sta_addr));
413*4882a593Smuzhiyun 	pos += sizeof(assoc->peer_sta_addr);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	/* Set the listen interval */
416*4882a593Smuzhiyun 	assoc->listen_interval = cpu_to_le16(priv->listen_interval);
417*4882a593Smuzhiyun 	/* Set the beacon period */
418*4882a593Smuzhiyun 	assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	pos += sizeof(assoc->cap_info_bitmap);
421*4882a593Smuzhiyun 	pos += sizeof(assoc->listen_interval);
422*4882a593Smuzhiyun 	pos += sizeof(assoc->beacon_period);
423*4882a593Smuzhiyun 	pos += sizeof(assoc->dtim_period);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos;
426*4882a593Smuzhiyun 	ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID);
427*4882a593Smuzhiyun 	ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len);
428*4882a593Smuzhiyun 	memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid,
429*4882a593Smuzhiyun 	       le16_to_cpu(ssid_tlv->header.len));
430*4882a593Smuzhiyun 	pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
433*4882a593Smuzhiyun 	phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
434*4882a593Smuzhiyun 	phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
435*4882a593Smuzhiyun 	memcpy(&phy_tlv->fh_ds.ds_param_set,
436*4882a593Smuzhiyun 	       &bss_desc->phy_param_set.ds_param_set.current_chan,
437*4882a593Smuzhiyun 	       sizeof(phy_tlv->fh_ds.ds_param_set));
438*4882a593Smuzhiyun 	pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
441*4882a593Smuzhiyun 	ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
442*4882a593Smuzhiyun 	ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
443*4882a593Smuzhiyun 	pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* Get the common rates supported between the driver and the BSS Desc */
446*4882a593Smuzhiyun 	if (mwifiex_setup_rates_from_bssdesc
447*4882a593Smuzhiyun 	    (priv, bss_desc, rates, &rates_size))
448*4882a593Smuzhiyun 		return -1;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	/* Save the data rates into Current BSS state structure */
451*4882a593Smuzhiyun 	priv->curr_bss_params.num_of_rates = rates_size;
452*4882a593Smuzhiyun 	memcpy(&priv->curr_bss_params.data_rates, rates, rates_size);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	/* Setup the Rates TLV in the association command */
455*4882a593Smuzhiyun 	rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos;
456*4882a593Smuzhiyun 	rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
457*4882a593Smuzhiyun 	rates_tlv->header.len = cpu_to_le16((u16) rates_size);
458*4882a593Smuzhiyun 	memcpy(rates_tlv->rates, rates, rates_size);
459*4882a593Smuzhiyun 	pos += sizeof(rates_tlv->header) + rates_size;
460*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n",
461*4882a593Smuzhiyun 		    rates_size);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/* Add the Authentication type to be used for Auth frames */
464*4882a593Smuzhiyun 	auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
465*4882a593Smuzhiyun 	auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
466*4882a593Smuzhiyun 	auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
467*4882a593Smuzhiyun 	if (priv->sec_info.wep_enabled)
468*4882a593Smuzhiyun 		auth_tlv->auth_type = cpu_to_le16(
469*4882a593Smuzhiyun 				(u16) priv->sec_info.authentication_mode);
470*4882a593Smuzhiyun 	else
471*4882a593Smuzhiyun 		auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	if (IS_SUPPORT_MULTI_BANDS(priv->adapter) &&
476*4882a593Smuzhiyun 	    !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) &&
477*4882a593Smuzhiyun 	    (!bss_desc->disable_11n) &&
478*4882a593Smuzhiyun 	    (priv->adapter->config_bands & BAND_GN ||
479*4882a593Smuzhiyun 	     priv->adapter->config_bands & BAND_AN) &&
480*4882a593Smuzhiyun 	    (bss_desc->bcn_ht_cap)
481*4882a593Smuzhiyun 	    )
482*4882a593Smuzhiyun 		) {
483*4882a593Smuzhiyun 		/* Append a channel TLV for the channel the attempted AP was
484*4882a593Smuzhiyun 		   found on */
485*4882a593Smuzhiyun 		chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
486*4882a593Smuzhiyun 		chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
487*4882a593Smuzhiyun 		chan_tlv->header.len =
488*4882a593Smuzhiyun 			cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 		memset(chan_tlv->chan_scan_param, 0x00,
491*4882a593Smuzhiyun 		       sizeof(struct mwifiex_chan_scan_param_set));
492*4882a593Smuzhiyun 		chan_tlv->chan_scan_param[0].chan_number =
493*4882a593Smuzhiyun 			(bss_desc->phy_param_set.ds_param_set.current_chan);
494*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n",
495*4882a593Smuzhiyun 			    chan_tlv->chan_scan_param[0].chan_number);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 		chan_tlv->chan_scan_param[0].radio_type =
498*4882a593Smuzhiyun 			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n",
501*4882a593Smuzhiyun 			    chan_tlv->chan_scan_param[0].radio_type);
502*4882a593Smuzhiyun 		pos += sizeof(chan_tlv->header) +
503*4882a593Smuzhiyun 			sizeof(struct mwifiex_chan_scan_param_set);
504*4882a593Smuzhiyun 	}
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	if (!priv->wps.session_enable) {
507*4882a593Smuzhiyun 		if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
508*4882a593Smuzhiyun 			rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 		if (rsn_ie_len == -1)
511*4882a593Smuzhiyun 			return -1;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) &&
515*4882a593Smuzhiyun 	    (!bss_desc->disable_11n) &&
516*4882a593Smuzhiyun 	    (priv->adapter->config_bands & BAND_GN ||
517*4882a593Smuzhiyun 	     priv->adapter->config_bands & BAND_AN))
518*4882a593Smuzhiyun 		mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
521*4882a593Smuzhiyun 	    !bss_desc->disable_11n && !bss_desc->disable_11ac &&
522*4882a593Smuzhiyun 	    priv->adapter->config_bands & BAND_AAC)
523*4882a593Smuzhiyun 		mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	/* Append vendor specific IE TLV */
526*4882a593Smuzhiyun 	mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie,
529*4882a593Smuzhiyun 					    bss_desc->bcn_ht_cap);
530*4882a593Smuzhiyun 	if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
531*4882a593Smuzhiyun 		mwifiex_cmd_append_wapi_ie(priv, &pos);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (priv->wps.session_enable && priv->wps_ie_len)
534*4882a593Smuzhiyun 		mwifiex_cmd_append_wps_ie(priv, &pos);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	mwifiex_cmd_append_generic_ie(priv, &pos);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	mwifiex_11h_process_join(priv, &pos, bss_desc);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* Set the Capability info at last */
545*4882a593Smuzhiyun 	tmp_cap = bss_desc->cap_info_bitmap;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	if (priv->adapter->config_bands == BAND_B)
548*4882a593Smuzhiyun 		tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	tmp_cap &= CAPINFO_MASK;
551*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
552*4882a593Smuzhiyun 		    "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
553*4882a593Smuzhiyun 		    tmp_cap, CAPINFO_MASK);
554*4882a593Smuzhiyun 	assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
assoc_failure_reason_to_str(u16 cap_info)559*4882a593Smuzhiyun static const char *assoc_failure_reason_to_str(u16 cap_info)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	switch (cap_info) {
562*4882a593Smuzhiyun 	case CONNECT_ERR_AUTH_ERR_STA_FAILURE:
563*4882a593Smuzhiyun 		return "CONNECT_ERR_AUTH_ERR_STA_FAILURE";
564*4882a593Smuzhiyun 	case CONNECT_ERR_AUTH_MSG_UNHANDLED:
565*4882a593Smuzhiyun 		return "CONNECT_ERR_AUTH_MSG_UNHANDLED";
566*4882a593Smuzhiyun 	case CONNECT_ERR_ASSOC_ERR_TIMEOUT:
567*4882a593Smuzhiyun 		return "CONNECT_ERR_ASSOC_ERR_TIMEOUT";
568*4882a593Smuzhiyun 	case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED:
569*4882a593Smuzhiyun 		return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED";
570*4882a593Smuzhiyun 	case CONNECT_ERR_STA_FAILURE:
571*4882a593Smuzhiyun 		return "CONNECT_ERR_STA_FAILURE";
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	return "Unknown connect failure";
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun /*
577*4882a593Smuzhiyun  * Association firmware command response handler
578*4882a593Smuzhiyun  *
579*4882a593Smuzhiyun  * The response buffer for the association command has the following
580*4882a593Smuzhiyun  * memory layout.
581*4882a593Smuzhiyun  *
582*4882a593Smuzhiyun  * For cases where an association response was not received (indicated
583*4882a593Smuzhiyun  * by the CapInfo and AId field):
584*4882a593Smuzhiyun  *
585*4882a593Smuzhiyun  *     .------------------------------------------------------------.
586*4882a593Smuzhiyun  *     |  Header(4 * sizeof(t_u16)):  Standard command response hdr |
587*4882a593Smuzhiyun  *     .------------------------------------------------------------.
588*4882a593Smuzhiyun  *     |  cap_info/Error Return(t_u16):                             |
589*4882a593Smuzhiyun  *     |           0xFFFF(-1): Internal error                       |
590*4882a593Smuzhiyun  *     |           0xFFFE(-2): Authentication unhandled message     |
591*4882a593Smuzhiyun  *     |           0xFFFD(-3): Authentication refused               |
592*4882a593Smuzhiyun  *     |           0xFFFC(-4): Timeout waiting for AP response      |
593*4882a593Smuzhiyun  *     .------------------------------------------------------------.
594*4882a593Smuzhiyun  *     |  status_code(t_u16):                                       |
595*4882a593Smuzhiyun  *     |        If cap_info is -1:                                  |
596*4882a593Smuzhiyun  *     |           An internal firmware failure prevented the       |
597*4882a593Smuzhiyun  *     |           command from being processed.  The status_code   |
598*4882a593Smuzhiyun  *     |           will be set to 1.                                |
599*4882a593Smuzhiyun  *     |                                                            |
600*4882a593Smuzhiyun  *     |        If cap_info is -2:                                  |
601*4882a593Smuzhiyun  *     |           An authentication frame was received but was     |
602*4882a593Smuzhiyun  *     |           not handled by the firmware.  IEEE Status        |
603*4882a593Smuzhiyun  *     |           code for the failure is returned.                |
604*4882a593Smuzhiyun  *     |                                                            |
605*4882a593Smuzhiyun  *     |        If cap_info is -3:                                  |
606*4882a593Smuzhiyun  *     |           An authentication frame was received and the     |
607*4882a593Smuzhiyun  *     |           status_code is the IEEE Status reported in the   |
608*4882a593Smuzhiyun  *     |           response.                                        |
609*4882a593Smuzhiyun  *     |                                                            |
610*4882a593Smuzhiyun  *     |        If cap_info is -4:                                  |
611*4882a593Smuzhiyun  *     |           (1) Association response timeout                 |
612*4882a593Smuzhiyun  *     |           (2) Authentication response timeout              |
613*4882a593Smuzhiyun  *     .------------------------------------------------------------.
614*4882a593Smuzhiyun  *     |  a_id(t_u16): 0xFFFF                                       |
615*4882a593Smuzhiyun  *     .------------------------------------------------------------.
616*4882a593Smuzhiyun  *
617*4882a593Smuzhiyun  *
618*4882a593Smuzhiyun  * For cases where an association response was received, the IEEE
619*4882a593Smuzhiyun  * standard association response frame is returned:
620*4882a593Smuzhiyun  *
621*4882a593Smuzhiyun  *     .------------------------------------------------------------.
622*4882a593Smuzhiyun  *     |  Header(4 * sizeof(t_u16)):  Standard command response hdr |
623*4882a593Smuzhiyun  *     .------------------------------------------------------------.
624*4882a593Smuzhiyun  *     |  cap_info(t_u16): IEEE Capability                          |
625*4882a593Smuzhiyun  *     .------------------------------------------------------------.
626*4882a593Smuzhiyun  *     |  status_code(t_u16): IEEE Status Code                      |
627*4882a593Smuzhiyun  *     .------------------------------------------------------------.
628*4882a593Smuzhiyun  *     |  a_id(t_u16): IEEE Association ID                          |
629*4882a593Smuzhiyun  *     .------------------------------------------------------------.
630*4882a593Smuzhiyun  *     |  IEEE IEs(variable): Any received IEs comprising the       |
631*4882a593Smuzhiyun  *     |                      remaining portion of a received       |
632*4882a593Smuzhiyun  *     |                      association response frame.           |
633*4882a593Smuzhiyun  *     .------------------------------------------------------------.
634*4882a593Smuzhiyun  *
635*4882a593Smuzhiyun  * For simplistic handling, the status_code field can be used to determine
636*4882a593Smuzhiyun  * an association success (0) or failure (non-zero).
637*4882a593Smuzhiyun  */
mwifiex_ret_802_11_associate(struct mwifiex_private * priv,struct host_cmd_ds_command * resp)638*4882a593Smuzhiyun int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
639*4882a593Smuzhiyun 			     struct host_cmd_ds_command *resp)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	struct mwifiex_adapter *adapter = priv->adapter;
642*4882a593Smuzhiyun 	int ret = 0;
643*4882a593Smuzhiyun 	struct ieee_types_assoc_rsp *assoc_rsp;
644*4882a593Smuzhiyun 	struct mwifiex_bssdescriptor *bss_desc;
645*4882a593Smuzhiyun 	bool enable_data = true;
646*4882a593Smuzhiyun 	u16 cap_info, status_code, aid;
647*4882a593Smuzhiyun 	const u8 *ie_ptr;
648*4882a593Smuzhiyun 	struct ieee80211_ht_operation *assoc_resp_ht_oper;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	if (!priv->attempted_bss_desc) {
651*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR,
652*4882a593Smuzhiyun 			    "ASSOC_RESP: failed, association terminated by host\n");
653*4882a593Smuzhiyun 		goto done;
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
659*4882a593Smuzhiyun 	status_code = le16_to_cpu(assoc_rsp->status_code);
660*4882a593Smuzhiyun 	aid = le16_to_cpu(assoc_rsp->a_id);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
663*4882a593Smuzhiyun 		dev_err(priv->adapter->dev,
664*4882a593Smuzhiyun 			"invalid AID value 0x%x; bits 15:14 not set\n",
665*4882a593Smuzhiyun 			aid);
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	aid &= ~(BIT(15) | BIT(14));
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
670*4882a593Smuzhiyun 				   sizeof(priv->assoc_rsp_buf));
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	assoc_rsp->a_id = cpu_to_le16(aid);
673*4882a593Smuzhiyun 	memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	if (status_code) {
676*4882a593Smuzhiyun 		priv->adapter->dbg.num_cmd_assoc_failure++;
677*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR,
678*4882a593Smuzhiyun 			    "ASSOC_RESP: failed,\t"
679*4882a593Smuzhiyun 			    "status code=%d err=%#x a_id=%#x\n",
680*4882a593Smuzhiyun 			    status_code, cap_info,
681*4882a593Smuzhiyun 			    le16_to_cpu(assoc_rsp->a_id));
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n",
684*4882a593Smuzhiyun 			    assoc_failure_reason_to_str(cap_info));
685*4882a593Smuzhiyun 		if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) {
686*4882a593Smuzhiyun 			if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) {
687*4882a593Smuzhiyun 				ret = WLAN_STATUS_AUTH_TIMEOUT;
688*4882a593Smuzhiyun 				mwifiex_dbg(priv->adapter, ERROR,
689*4882a593Smuzhiyun 					    "ASSOC_RESP: AUTH timeout\n");
690*4882a593Smuzhiyun 			} else {
691*4882a593Smuzhiyun 				ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
692*4882a593Smuzhiyun 				mwifiex_dbg(priv->adapter, ERROR,
693*4882a593Smuzhiyun 					    "ASSOC_RESP: UNSPECIFIED failure\n");
694*4882a593Smuzhiyun 			}
695*4882a593Smuzhiyun 		} else {
696*4882a593Smuzhiyun 			ret = status_code;
697*4882a593Smuzhiyun 		}
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 		goto done;
700*4882a593Smuzhiyun 	}
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	/* Send a Media Connected event, according to the Spec */
703*4882a593Smuzhiyun 	priv->media_connected = true;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	priv->adapter->ps_state = PS_STATE_AWAKE;
706*4882a593Smuzhiyun 	priv->adapter->pps_uapsd_mode = false;
707*4882a593Smuzhiyun 	priv->adapter->tx_lock_flag = false;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	/* Set the attempted BSSID Index to current */
710*4882a593Smuzhiyun 	bss_desc = priv->attempted_bss_desc;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n",
713*4882a593Smuzhiyun 		    bss_desc->ssid.ssid);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	/* Make a copy of current BSSID descriptor */
716*4882a593Smuzhiyun 	memcpy(&priv->curr_bss_params.bss_descriptor,
717*4882a593Smuzhiyun 	       bss_desc, sizeof(struct mwifiex_bssdescriptor));
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	/* Update curr_bss_params */
720*4882a593Smuzhiyun 	priv->curr_bss_params.bss_descriptor.channel
721*4882a593Smuzhiyun 		= bss_desc->phy_param_set.ds_param_set.current_chan;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	priv->curr_bss_params.band = (u8) bss_desc->bss_band;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
726*4882a593Smuzhiyun 		priv->curr_bss_params.wmm_enabled = true;
727*4882a593Smuzhiyun 	else
728*4882a593Smuzhiyun 		priv->curr_bss_params.wmm_enabled = false;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	if ((priv->wmm_required || bss_desc->bcn_ht_cap) &&
731*4882a593Smuzhiyun 	    priv->curr_bss_params.wmm_enabled)
732*4882a593Smuzhiyun 		priv->wmm_enabled = true;
733*4882a593Smuzhiyun 	else
734*4882a593Smuzhiyun 		priv->wmm_enabled = false;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	priv->curr_bss_params.wmm_uapsd_enabled = false;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	if (priv->wmm_enabled)
739*4882a593Smuzhiyun 		priv->curr_bss_params.wmm_uapsd_enabled
740*4882a593Smuzhiyun 			= ((bss_desc->wmm_ie.qos_info_bitmap &
741*4882a593Smuzhiyun 				IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/* Store the bandwidth information from assoc response */
744*4882a593Smuzhiyun 	ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer,
745*4882a593Smuzhiyun 				  priv->assoc_rsp_size
746*4882a593Smuzhiyun 				  - sizeof(struct ieee_types_assoc_rsp));
747*4882a593Smuzhiyun 	if (ie_ptr) {
748*4882a593Smuzhiyun 		assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr
749*4882a593Smuzhiyun 					+ sizeof(struct ieee_types_header));
750*4882a593Smuzhiyun 		priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param;
751*4882a593Smuzhiyun 		priv->ht_param_present = true;
752*4882a593Smuzhiyun 	} else {
753*4882a593Smuzhiyun 		priv->ht_param_present = false;
754*4882a593Smuzhiyun 	}
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
757*4882a593Smuzhiyun 		    "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
758*4882a593Smuzhiyun 		    priv->curr_pkt_filter);
759*4882a593Smuzhiyun 	if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
760*4882a593Smuzhiyun 		priv->wpa_is_gtk_set = false;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	if (priv->wmm_enabled) {
763*4882a593Smuzhiyun 		/* Don't re-enable carrier until we get the WMM_GET_STATUS
764*4882a593Smuzhiyun 		   event */
765*4882a593Smuzhiyun 		enable_data = false;
766*4882a593Smuzhiyun 	} else {
767*4882a593Smuzhiyun 		/* Since WMM is not enabled, setup the queues with the
768*4882a593Smuzhiyun 		   defaults */
769*4882a593Smuzhiyun 		mwifiex_wmm_setup_queue_priorities(priv, NULL);
770*4882a593Smuzhiyun 		mwifiex_wmm_setup_ac_downgrade(priv);
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	if (enable_data)
774*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO,
775*4882a593Smuzhiyun 			    "info: post association, re-enabling data flow\n");
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	/* Reset SNR/NF/RSSI values */
778*4882a593Smuzhiyun 	priv->data_rssi_last = 0;
779*4882a593Smuzhiyun 	priv->data_nf_last = 0;
780*4882a593Smuzhiyun 	priv->data_rssi_avg = 0;
781*4882a593Smuzhiyun 	priv->data_nf_avg = 0;
782*4882a593Smuzhiyun 	priv->bcn_rssi_last = 0;
783*4882a593Smuzhiyun 	priv->bcn_nf_last = 0;
784*4882a593Smuzhiyun 	priv->bcn_rssi_avg = 0;
785*4882a593Smuzhiyun 	priv->bcn_nf_avg = 0;
786*4882a593Smuzhiyun 	priv->rxpd_rate = 0;
787*4882a593Smuzhiyun 	priv->rxpd_htinfo = 0;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	mwifiex_save_curr_bcn(priv);
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	priv->adapter->dbg.num_cmd_assoc_success++;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n");
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	/* Add the ra_list here for infra mode as there will be only 1 ra
796*4882a593Smuzhiyun 	   always */
797*4882a593Smuzhiyun 	mwifiex_ralist_add(priv,
798*4882a593Smuzhiyun 			   priv->curr_bss_params.bss_descriptor.mac_address);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	if (!netif_carrier_ok(priv->netdev))
801*4882a593Smuzhiyun 		netif_carrier_on(priv->netdev);
802*4882a593Smuzhiyun 	mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
805*4882a593Smuzhiyun 		priv->scan_block = true;
806*4882a593Smuzhiyun 	else
807*4882a593Smuzhiyun 		priv->port_open = true;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun done:
810*4882a593Smuzhiyun 	/* Need to indicate IOCTL complete */
811*4882a593Smuzhiyun 	if (adapter->curr_cmd->wait_q_enabled) {
812*4882a593Smuzhiyun 		if (ret)
813*4882a593Smuzhiyun 			adapter->cmd_wait_q.status = -1;
814*4882a593Smuzhiyun 		else
815*4882a593Smuzhiyun 			adapter->cmd_wait_q.status = 0;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	return ret;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun /*
822*4882a593Smuzhiyun  * This function prepares command for ad-hoc start.
823*4882a593Smuzhiyun  *
824*4882a593Smuzhiyun  * Driver will fill up SSID, BSS mode, IBSS parameters, physical
825*4882a593Smuzhiyun  * parameters, probe delay, and capability information. Firmware
826*4882a593Smuzhiyun  * will fill up beacon period, basic rates and operational rates.
827*4882a593Smuzhiyun  *
828*4882a593Smuzhiyun  * In addition, the following TLVs are added -
829*4882a593Smuzhiyun  *      - Channel TLV
830*4882a593Smuzhiyun  *      - Vendor specific IE
831*4882a593Smuzhiyun  *      - WPA/WPA2 IE
832*4882a593Smuzhiyun  *      - HT Capabilities IE
833*4882a593Smuzhiyun  *      - HT Information IE
834*4882a593Smuzhiyun  *
835*4882a593Smuzhiyun  * Preparation also includes -
836*4882a593Smuzhiyun  *      - Setting command ID and proper size
837*4882a593Smuzhiyun  *      - Ensuring correct endian-ness
838*4882a593Smuzhiyun  */
839*4882a593Smuzhiyun int
mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private * priv,struct host_cmd_ds_command * cmd,struct cfg80211_ssid * req_ssid)840*4882a593Smuzhiyun mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
841*4882a593Smuzhiyun 				struct host_cmd_ds_command *cmd,
842*4882a593Smuzhiyun 				struct cfg80211_ssid *req_ssid)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	int rsn_ie_len = 0;
845*4882a593Smuzhiyun 	struct mwifiex_adapter *adapter = priv->adapter;
846*4882a593Smuzhiyun 	struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start =
847*4882a593Smuzhiyun 		&cmd->params.adhoc_start;
848*4882a593Smuzhiyun 	struct mwifiex_bssdescriptor *bss_desc;
849*4882a593Smuzhiyun 	u32 cmd_append_size = 0;
850*4882a593Smuzhiyun 	u32 i;
851*4882a593Smuzhiyun 	u16 tmp_cap;
852*4882a593Smuzhiyun 	struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
853*4882a593Smuzhiyun 	u8 radio_type;
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	struct mwifiex_ie_types_htcap *ht_cap;
856*4882a593Smuzhiyun 	struct mwifiex_ie_types_htinfo *ht_info;
857*4882a593Smuzhiyun 	u8 *pos = (u8 *) adhoc_start +
858*4882a593Smuzhiyun 			sizeof(struct host_cmd_ds_802_11_ad_hoc_start);
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	if (!adapter)
861*4882a593Smuzhiyun 		return -1;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	bss_desc = &priv->curr_bss_params.bss_descriptor;
866*4882a593Smuzhiyun 	priv->attempted_bss_desc = bss_desc;
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	/*
869*4882a593Smuzhiyun 	 * Fill in the parameters for 2 data structures:
870*4882a593Smuzhiyun 	 *   1. struct host_cmd_ds_802_11_ad_hoc_start command
871*4882a593Smuzhiyun 	 *   2. bss_desc
872*4882a593Smuzhiyun 	 * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
873*4882a593Smuzhiyun 	 * probe delay, and Cap info.
874*4882a593Smuzhiyun 	 * Firmware will fill up beacon period, Basic rates
875*4882a593Smuzhiyun 	 * and operational rates.
876*4882a593Smuzhiyun 	 */
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	if (req_ssid->ssid_len > IEEE80211_MAX_SSID_LEN)
881*4882a593Smuzhiyun 		req_ssid->ssid_len = IEEE80211_MAX_SSID_LEN;
882*4882a593Smuzhiyun 	memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len);
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
885*4882a593Smuzhiyun 		    adhoc_start->ssid);
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
888*4882a593Smuzhiyun 	memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len);
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	bss_desc->ssid.ssid_len = req_ssid->ssid_len;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	/* Set the BSS mode */
893*4882a593Smuzhiyun 	adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
894*4882a593Smuzhiyun 	bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
895*4882a593Smuzhiyun 	adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period);
896*4882a593Smuzhiyun 	bss_desc->beacon_period = priv->beacon_period;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	/* Set Physical param set */
899*4882a593Smuzhiyun /* Parameter IE Id */
900*4882a593Smuzhiyun #define DS_PARA_IE_ID   3
901*4882a593Smuzhiyun /* Parameter IE length */
902*4882a593Smuzhiyun #define DS_PARA_IE_LEN  1
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
905*4882a593Smuzhiyun 	adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band,
908*4882a593Smuzhiyun 			     (u16) priv->adhoc_channel, 0)) {
909*4882a593Smuzhiyun 		struct mwifiex_chan_freq_power *cfp;
910*4882a593Smuzhiyun 		cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band,
911*4882a593Smuzhiyun 				      FIRST_VALID_CHANNEL, 0);
912*4882a593Smuzhiyun 		if (cfp)
913*4882a593Smuzhiyun 			priv->adhoc_channel = (u8) cfp->channel;
914*4882a593Smuzhiyun 	}
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	if (!priv->adhoc_channel) {
917*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR,
918*4882a593Smuzhiyun 			    "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
919*4882a593Smuzhiyun 		return -1;
920*4882a593Smuzhiyun 	}
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	mwifiex_dbg(adapter, INFO,
923*4882a593Smuzhiyun 		    "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
924*4882a593Smuzhiyun 		    priv->adhoc_channel);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
927*4882a593Smuzhiyun 	priv->curr_bss_params.band = adapter->adhoc_start_band;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	bss_desc->channel = priv->adhoc_channel;
930*4882a593Smuzhiyun 	adhoc_start->phy_param_set.ds_param_set.current_chan =
931*4882a593Smuzhiyun 		priv->adhoc_channel;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set,
934*4882a593Smuzhiyun 	       sizeof(union ieee_types_phy_param_set));
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	/* Set IBSS param set */
937*4882a593Smuzhiyun /* IBSS parameter IE Id */
938*4882a593Smuzhiyun #define IBSS_PARA_IE_ID   6
939*4882a593Smuzhiyun /* IBSS parameter IE length */
940*4882a593Smuzhiyun #define IBSS_PARA_IE_LEN  2
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
943*4882a593Smuzhiyun 	adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
944*4882a593Smuzhiyun 	adhoc_start->ss_param_set.ibss_param_set.atim_window
945*4882a593Smuzhiyun 					= cpu_to_le16(priv->atim_window);
946*4882a593Smuzhiyun 	memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set,
947*4882a593Smuzhiyun 	       sizeof(union ieee_types_ss_param_set));
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	/* Set Capability info */
950*4882a593Smuzhiyun 	bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS;
951*4882a593Smuzhiyun 	tmp_cap = WLAN_CAPABILITY_IBSS;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	/* Set up privacy in bss_desc */
954*4882a593Smuzhiyun 	if (priv->sec_info.encryption_mode) {
955*4882a593Smuzhiyun 		/* Ad-Hoc capability privacy on */
956*4882a593Smuzhiyun 		mwifiex_dbg(adapter, INFO,
957*4882a593Smuzhiyun 			    "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
958*4882a593Smuzhiyun 		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
959*4882a593Smuzhiyun 		tmp_cap |= WLAN_CAPABILITY_PRIVACY;
960*4882a593Smuzhiyun 	} else {
961*4882a593Smuzhiyun 		mwifiex_dbg(adapter, INFO,
962*4882a593Smuzhiyun 			    "info: ADHOC_S_CMD: wep_status NOT set,\t"
963*4882a593Smuzhiyun 			    "setting privacy to ACCEPT ALL\n");
964*4882a593Smuzhiyun 		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
965*4882a593Smuzhiyun 	}
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate));
968*4882a593Smuzhiyun 	mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
969*4882a593Smuzhiyun 	if ((adapter->adhoc_start_band & BAND_G) &&
970*4882a593Smuzhiyun 	    (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
971*4882a593Smuzhiyun 		if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
972*4882a593Smuzhiyun 				     HostCmd_ACT_GEN_SET, 0,
973*4882a593Smuzhiyun 				     &priv->curr_pkt_filter, false)) {
974*4882a593Smuzhiyun 			mwifiex_dbg(adapter, ERROR,
975*4882a593Smuzhiyun 				    "ADHOC_S_CMD: G Protection config failed\n");
976*4882a593Smuzhiyun 			return -1;
977*4882a593Smuzhiyun 		}
978*4882a593Smuzhiyun 	}
979*4882a593Smuzhiyun 	/* Find the last non zero */
980*4882a593Smuzhiyun 	for (i = 0; i < sizeof(adhoc_start->data_rate); i++)
981*4882a593Smuzhiyun 		if (!adhoc_start->data_rate[i])
982*4882a593Smuzhiyun 			break;
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	priv->curr_bss_params.num_of_rates = i;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	/* Copy the ad-hoc creating rates into Current BSS rate structure */
987*4882a593Smuzhiyun 	memcpy(&priv->curr_bss_params.data_rates,
988*4882a593Smuzhiyun 	       &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n",
991*4882a593Smuzhiyun 		    adhoc_start->data_rate);
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 	mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	if (IS_SUPPORT_MULTI_BANDS(adapter)) {
996*4882a593Smuzhiyun 		/* Append a channel TLV */
997*4882a593Smuzhiyun 		chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
998*4882a593Smuzhiyun 		chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
999*4882a593Smuzhiyun 		chan_tlv->header.len =
1000*4882a593Smuzhiyun 			cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 		memset(chan_tlv->chan_scan_param, 0x00,
1003*4882a593Smuzhiyun 		       sizeof(struct mwifiex_chan_scan_param_set));
1004*4882a593Smuzhiyun 		chan_tlv->chan_scan_param[0].chan_number =
1005*4882a593Smuzhiyun 			(u8) priv->curr_bss_params.bss_descriptor.channel;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 		mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n",
1008*4882a593Smuzhiyun 			    chan_tlv->chan_scan_param[0].chan_number);
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 		chan_tlv->chan_scan_param[0].radio_type
1011*4882a593Smuzhiyun 		       = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
1012*4882a593Smuzhiyun 		if (adapter->adhoc_start_band & BAND_GN ||
1013*4882a593Smuzhiyun 		    adapter->adhoc_start_band & BAND_AN) {
1014*4882a593Smuzhiyun 			if (adapter->sec_chan_offset ==
1015*4882a593Smuzhiyun 					    IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
1016*4882a593Smuzhiyun 				chan_tlv->chan_scan_param[0].radio_type |=
1017*4882a593Smuzhiyun 					(IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4);
1018*4882a593Smuzhiyun 			else if (adapter->sec_chan_offset ==
1019*4882a593Smuzhiyun 					    IEEE80211_HT_PARAM_CHA_SEC_BELOW)
1020*4882a593Smuzhiyun 				chan_tlv->chan_scan_param[0].radio_type |=
1021*4882a593Smuzhiyun 					(IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4);
1022*4882a593Smuzhiyun 		}
1023*4882a593Smuzhiyun 		mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n",
1024*4882a593Smuzhiyun 			    chan_tlv->chan_scan_param[0].radio_type);
1025*4882a593Smuzhiyun 		pos += sizeof(chan_tlv->header) +
1026*4882a593Smuzhiyun 			sizeof(struct mwifiex_chan_scan_param_set);
1027*4882a593Smuzhiyun 		cmd_append_size +=
1028*4882a593Smuzhiyun 			sizeof(chan_tlv->header) +
1029*4882a593Smuzhiyun 			sizeof(struct mwifiex_chan_scan_param_set);
1030*4882a593Smuzhiyun 	}
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	/* Append vendor specific IE TLV */
1033*4882a593Smuzhiyun 	cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
1034*4882a593Smuzhiyun 				MWIFIEX_VSIE_MASK_ADHOC, &pos);
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	if (priv->sec_info.wpa_enabled) {
1037*4882a593Smuzhiyun 		rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
1038*4882a593Smuzhiyun 		if (rsn_ie_len == -1)
1039*4882a593Smuzhiyun 			return -1;
1040*4882a593Smuzhiyun 		cmd_append_size += rsn_ie_len;
1041*4882a593Smuzhiyun 	}
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	if (adapter->adhoc_11n_enabled) {
1044*4882a593Smuzhiyun 		/* Fill HT CAPABILITY */
1045*4882a593Smuzhiyun 		ht_cap = (struct mwifiex_ie_types_htcap *) pos;
1046*4882a593Smuzhiyun 		memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
1047*4882a593Smuzhiyun 		ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1048*4882a593Smuzhiyun 		ht_cap->header.len =
1049*4882a593Smuzhiyun 		       cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1050*4882a593Smuzhiyun 		radio_type = mwifiex_band_to_radio_type(
1051*4882a593Smuzhiyun 					priv->adapter->config_bands);
1052*4882a593Smuzhiyun 		mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 		if (adapter->sec_chan_offset ==
1055*4882a593Smuzhiyun 					IEEE80211_HT_PARAM_CHA_SEC_NONE) {
1056*4882a593Smuzhiyun 			u16 tmp_ht_cap;
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 			tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info);
1059*4882a593Smuzhiyun 			tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
1060*4882a593Smuzhiyun 			tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40;
1061*4882a593Smuzhiyun 			ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap);
1062*4882a593Smuzhiyun 		}
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 		pos += sizeof(struct mwifiex_ie_types_htcap);
1065*4882a593Smuzhiyun 		cmd_append_size += sizeof(struct mwifiex_ie_types_htcap);
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 		/* Fill HT INFORMATION */
1068*4882a593Smuzhiyun 		ht_info = (struct mwifiex_ie_types_htinfo *) pos;
1069*4882a593Smuzhiyun 		memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo));
1070*4882a593Smuzhiyun 		ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION);
1071*4882a593Smuzhiyun 		ht_info->header.len =
1072*4882a593Smuzhiyun 			cpu_to_le16(sizeof(struct ieee80211_ht_operation));
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 		ht_info->ht_oper.primary_chan =
1075*4882a593Smuzhiyun 			(u8) priv->curr_bss_params.bss_descriptor.channel;
1076*4882a593Smuzhiyun 		if (adapter->sec_chan_offset) {
1077*4882a593Smuzhiyun 			ht_info->ht_oper.ht_param = adapter->sec_chan_offset;
1078*4882a593Smuzhiyun 			ht_info->ht_oper.ht_param |=
1079*4882a593Smuzhiyun 					IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
1080*4882a593Smuzhiyun 		}
1081*4882a593Smuzhiyun 		ht_info->ht_oper.operation_mode =
1082*4882a593Smuzhiyun 		     cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
1083*4882a593Smuzhiyun 		ht_info->ht_oper.basic_set[0] = 0xff;
1084*4882a593Smuzhiyun 		pos += sizeof(struct mwifiex_ie_types_htinfo);
1085*4882a593Smuzhiyun 		cmd_append_size +=
1086*4882a593Smuzhiyun 				sizeof(struct mwifiex_ie_types_htinfo);
1087*4882a593Smuzhiyun 	}
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	cmd->size =
1090*4882a593Smuzhiyun 		cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start)
1091*4882a593Smuzhiyun 				  + S_DS_GEN + cmd_append_size));
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	if (adapter->adhoc_start_band == BAND_B)
1094*4882a593Smuzhiyun 		tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
1095*4882a593Smuzhiyun 	else
1096*4882a593Smuzhiyun 		tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap);
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	return 0;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun /*
1104*4882a593Smuzhiyun  * This function prepares command for ad-hoc join.
1105*4882a593Smuzhiyun  *
1106*4882a593Smuzhiyun  * Most of the parameters are set up by copying from the target BSS descriptor
1107*4882a593Smuzhiyun  * from the scan response.
1108*4882a593Smuzhiyun  *
1109*4882a593Smuzhiyun  * In addition, the following TLVs are added -
1110*4882a593Smuzhiyun  *      - Channel TLV
1111*4882a593Smuzhiyun  *      - Vendor specific IE
1112*4882a593Smuzhiyun  *      - WPA/WPA2 IE
1113*4882a593Smuzhiyun  *      - 11n IE
1114*4882a593Smuzhiyun  *
1115*4882a593Smuzhiyun  * Preparation also includes -
1116*4882a593Smuzhiyun  *      - Setting command ID and proper size
1117*4882a593Smuzhiyun  *      - Ensuring correct endian-ness
1118*4882a593Smuzhiyun  */
1119*4882a593Smuzhiyun int
mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private * priv,struct host_cmd_ds_command * cmd,struct mwifiex_bssdescriptor * bss_desc)1120*4882a593Smuzhiyun mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
1121*4882a593Smuzhiyun 			       struct host_cmd_ds_command *cmd,
1122*4882a593Smuzhiyun 			       struct mwifiex_bssdescriptor *bss_desc)
1123*4882a593Smuzhiyun {
1124*4882a593Smuzhiyun 	int rsn_ie_len = 0;
1125*4882a593Smuzhiyun 	struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
1126*4882a593Smuzhiyun 		&cmd->params.adhoc_join;
1127*4882a593Smuzhiyun 	struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
1128*4882a593Smuzhiyun 	u32 cmd_append_size = 0;
1129*4882a593Smuzhiyun 	u16 tmp_cap;
1130*4882a593Smuzhiyun 	u32 i, rates_size = 0;
1131*4882a593Smuzhiyun 	u16 curr_pkt_filter;
1132*4882a593Smuzhiyun 	u8 *pos =
1133*4882a593Smuzhiyun 		(u8 *) adhoc_join +
1134*4882a593Smuzhiyun 		sizeof(struct host_cmd_ds_802_11_ad_hoc_join);
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun /* Use G protection */
1137*4882a593Smuzhiyun #define USE_G_PROTECTION        0x02
1138*4882a593Smuzhiyun 	if (bss_desc->erp_flags & USE_G_PROTECTION) {
1139*4882a593Smuzhiyun 		curr_pkt_filter =
1140*4882a593Smuzhiyun 			priv->
1141*4882a593Smuzhiyun 			curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 		if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1144*4882a593Smuzhiyun 				     HostCmd_ACT_GEN_SET, 0,
1145*4882a593Smuzhiyun 				     &curr_pkt_filter, false)) {
1146*4882a593Smuzhiyun 			mwifiex_dbg(priv->adapter, ERROR,
1147*4882a593Smuzhiyun 				    "ADHOC_J_CMD: G Protection config failed\n");
1148*4882a593Smuzhiyun 			return -1;
1149*4882a593Smuzhiyun 		}
1150*4882a593Smuzhiyun 	}
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	priv->attempted_bss_desc = bss_desc;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	adhoc_join->bss_descriptor.beacon_period
1159*4882a593Smuzhiyun 		= cpu_to_le16(bss_desc->beacon_period);
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	memcpy(&adhoc_join->bss_descriptor.bssid,
1162*4882a593Smuzhiyun 	       &bss_desc->mac_address, ETH_ALEN);
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	memcpy(&adhoc_join->bss_descriptor.ssid,
1165*4882a593Smuzhiyun 	       &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len);
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 	memcpy(&adhoc_join->bss_descriptor.phy_param_set,
1168*4882a593Smuzhiyun 	       &bss_desc->phy_param_set,
1169*4882a593Smuzhiyun 	       sizeof(union ieee_types_phy_param_set));
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	memcpy(&adhoc_join->bss_descriptor.ss_param_set,
1172*4882a593Smuzhiyun 	       &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set));
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	tmp_cap = bss_desc->cap_info_bitmap;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	tmp_cap &= CAPINFO_MASK;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
1179*4882a593Smuzhiyun 		    "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
1180*4882a593Smuzhiyun 		    tmp_cap, CAPINFO_MASK);
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	/* Information on BSSID descriptor passed to FW */
1183*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
1184*4882a593Smuzhiyun 		    "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n",
1185*4882a593Smuzhiyun 		    adhoc_join->bss_descriptor.bssid,
1186*4882a593Smuzhiyun 		    adhoc_join->bss_descriptor.ssid);
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	for (i = 0; i < MWIFIEX_SUPPORTED_RATES &&
1189*4882a593Smuzhiyun 		    bss_desc->supported_rates[i]; i++)
1190*4882a593Smuzhiyun 		;
1191*4882a593Smuzhiyun 	rates_size = i;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	/* Copy Data Rates from the Rates recorded in scan response */
1194*4882a593Smuzhiyun 	memset(adhoc_join->bss_descriptor.data_rates, 0,
1195*4882a593Smuzhiyun 	       sizeof(adhoc_join->bss_descriptor.data_rates));
1196*4882a593Smuzhiyun 	memcpy(adhoc_join->bss_descriptor.data_rates,
1197*4882a593Smuzhiyun 	       bss_desc->supported_rates, rates_size);
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	/* Copy the adhoc join rates into Current BSS state structure */
1200*4882a593Smuzhiyun 	priv->curr_bss_params.num_of_rates = rates_size;
1201*4882a593Smuzhiyun 	memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates,
1202*4882a593Smuzhiyun 	       rates_size);
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	/* Copy the channel information */
1205*4882a593Smuzhiyun 	priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
1206*4882a593Smuzhiyun 	priv->curr_bss_params.band = (u8) bss_desc->bss_band;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled)
1209*4882a593Smuzhiyun 		tmp_cap |= WLAN_CAPABILITY_PRIVACY;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
1212*4882a593Smuzhiyun 		/* Append a channel TLV */
1213*4882a593Smuzhiyun 		chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
1214*4882a593Smuzhiyun 		chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
1215*4882a593Smuzhiyun 		chan_tlv->header.len =
1216*4882a593Smuzhiyun 			cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 		memset(chan_tlv->chan_scan_param, 0x00,
1219*4882a593Smuzhiyun 		       sizeof(struct mwifiex_chan_scan_param_set));
1220*4882a593Smuzhiyun 		chan_tlv->chan_scan_param[0].chan_number =
1221*4882a593Smuzhiyun 			(bss_desc->phy_param_set.ds_param_set.current_chan);
1222*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n",
1223*4882a593Smuzhiyun 			    chan_tlv->chan_scan_param[0].chan_number);
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 		chan_tlv->chan_scan_param[0].radio_type =
1226*4882a593Smuzhiyun 			mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n",
1229*4882a593Smuzhiyun 			    chan_tlv->chan_scan_param[0].radio_type);
1230*4882a593Smuzhiyun 		pos += sizeof(chan_tlv->header) +
1231*4882a593Smuzhiyun 				sizeof(struct mwifiex_chan_scan_param_set);
1232*4882a593Smuzhiyun 		cmd_append_size += sizeof(chan_tlv->header) +
1233*4882a593Smuzhiyun 				sizeof(struct mwifiex_chan_scan_param_set);
1234*4882a593Smuzhiyun 	}
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	if (priv->sec_info.wpa_enabled)
1237*4882a593Smuzhiyun 		rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
1238*4882a593Smuzhiyun 	if (rsn_ie_len == -1)
1239*4882a593Smuzhiyun 		return -1;
1240*4882a593Smuzhiyun 	cmd_append_size += rsn_ie_len;
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
1243*4882a593Smuzhiyun 		cmd_append_size += mwifiex_cmd_append_11n_tlv(priv,
1244*4882a593Smuzhiyun 			bss_desc, &pos);
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	/* Append vendor specific IE TLV */
1247*4882a593Smuzhiyun 	cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
1248*4882a593Smuzhiyun 			MWIFIEX_VSIE_MASK_ADHOC, &pos);
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	cmd->size = cpu_to_le16
1251*4882a593Smuzhiyun 		((u16) (sizeof(struct host_cmd_ds_802_11_ad_hoc_join)
1252*4882a593Smuzhiyun 			+ S_DS_GEN + cmd_append_size));
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 	adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	return 0;
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun /*
1260*4882a593Smuzhiyun  * This function handles the command response of ad-hoc start and
1261*4882a593Smuzhiyun  * ad-hoc join.
1262*4882a593Smuzhiyun  *
1263*4882a593Smuzhiyun  * The function generates a device-connected event to notify
1264*4882a593Smuzhiyun  * the applications, in case of successful ad-hoc start/join, and
1265*4882a593Smuzhiyun  * saves the beacon buffer.
1266*4882a593Smuzhiyun  */
mwifiex_ret_802_11_ad_hoc(struct mwifiex_private * priv,struct host_cmd_ds_command * resp)1267*4882a593Smuzhiyun int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
1268*4882a593Smuzhiyun 			      struct host_cmd_ds_command *resp)
1269*4882a593Smuzhiyun {
1270*4882a593Smuzhiyun 	int ret = 0;
1271*4882a593Smuzhiyun 	struct mwifiex_adapter *adapter = priv->adapter;
1272*4882a593Smuzhiyun 	struct host_cmd_ds_802_11_ad_hoc_start_result *start_result =
1273*4882a593Smuzhiyun 				&resp->params.start_result;
1274*4882a593Smuzhiyun 	struct host_cmd_ds_802_11_ad_hoc_join_result *join_result =
1275*4882a593Smuzhiyun 				&resp->params.join_result;
1276*4882a593Smuzhiyun 	struct mwifiex_bssdescriptor *bss_desc;
1277*4882a593Smuzhiyun 	u16 cmd = le16_to_cpu(resp->command);
1278*4882a593Smuzhiyun 	u8 result;
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun 	if (!priv->attempted_bss_desc) {
1281*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR,
1282*4882a593Smuzhiyun 			    "ADHOC_RESP: failed, association terminated by host\n");
1283*4882a593Smuzhiyun 		goto done;
1284*4882a593Smuzhiyun 	}
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	if (cmd == HostCmd_CMD_802_11_AD_HOC_START)
1287*4882a593Smuzhiyun 		result = start_result->result;
1288*4882a593Smuzhiyun 	else
1289*4882a593Smuzhiyun 		result = join_result->result;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	bss_desc = priv->attempted_bss_desc;
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	/* Join result code 0 --> SUCCESS */
1294*4882a593Smuzhiyun 	if (result) {
1295*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n");
1296*4882a593Smuzhiyun 		if (priv->media_connected)
1297*4882a593Smuzhiyun 			mwifiex_reset_connect_state(priv, result, true);
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 		memset(&priv->curr_bss_params.bss_descriptor,
1300*4882a593Smuzhiyun 		       0x00, sizeof(struct mwifiex_bssdescriptor));
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 		ret = -1;
1303*4882a593Smuzhiyun 		goto done;
1304*4882a593Smuzhiyun 	}
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	/* Send a Media Connected event, according to the Spec */
1307*4882a593Smuzhiyun 	priv->media_connected = true;
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
1310*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n",
1311*4882a593Smuzhiyun 			    bss_desc->ssid.ssid);
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 		/* Update the created network descriptor with the new BSSID */
1314*4882a593Smuzhiyun 		memcpy(bss_desc->mac_address,
1315*4882a593Smuzhiyun 		       start_result->bssid, ETH_ALEN);
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 		priv->adhoc_state = ADHOC_STARTED;
1318*4882a593Smuzhiyun 	} else {
1319*4882a593Smuzhiyun 		/*
1320*4882a593Smuzhiyun 		 * Now the join cmd should be successful.
1321*4882a593Smuzhiyun 		 * If BSSID has changed use SSID to compare instead of BSSID
1322*4882a593Smuzhiyun 		 */
1323*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO,
1324*4882a593Smuzhiyun 			    "info: ADHOC_J_RESP %s\n",
1325*4882a593Smuzhiyun 			    bss_desc->ssid.ssid);
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 		/*
1328*4882a593Smuzhiyun 		 * Make a copy of current BSSID descriptor, only needed for
1329*4882a593Smuzhiyun 		 * join since the current descriptor is already being used
1330*4882a593Smuzhiyun 		 * for adhoc start
1331*4882a593Smuzhiyun 		 */
1332*4882a593Smuzhiyun 		memcpy(&priv->curr_bss_params.bss_descriptor,
1333*4882a593Smuzhiyun 		       bss_desc, sizeof(struct mwifiex_bssdescriptor));
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 		priv->adhoc_state = ADHOC_JOINED;
1336*4882a593Smuzhiyun 	}
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n",
1339*4882a593Smuzhiyun 		    priv->adhoc_channel);
1340*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n",
1341*4882a593Smuzhiyun 		    priv->curr_bss_params.bss_descriptor.mac_address);
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun 	if (!netif_carrier_ok(priv->netdev))
1344*4882a593Smuzhiyun 		netif_carrier_on(priv->netdev);
1345*4882a593Smuzhiyun 	mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	mwifiex_save_curr_bcn(priv);
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun done:
1350*4882a593Smuzhiyun 	/* Need to indicate IOCTL complete */
1351*4882a593Smuzhiyun 	if (adapter->curr_cmd->wait_q_enabled) {
1352*4882a593Smuzhiyun 		if (ret)
1353*4882a593Smuzhiyun 			adapter->cmd_wait_q.status = -1;
1354*4882a593Smuzhiyun 		else
1355*4882a593Smuzhiyun 			adapter->cmd_wait_q.status = 0;
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	}
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	return ret;
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun /*
1363*4882a593Smuzhiyun  * This function associates to a specific BSS discovered in a scan.
1364*4882a593Smuzhiyun  *
1365*4882a593Smuzhiyun  * It clears any past association response stored for application
1366*4882a593Smuzhiyun  * retrieval and calls the command preparation routine to send the
1367*4882a593Smuzhiyun  * command to firmware.
1368*4882a593Smuzhiyun  */
mwifiex_associate(struct mwifiex_private * priv,struct mwifiex_bssdescriptor * bss_desc)1369*4882a593Smuzhiyun int mwifiex_associate(struct mwifiex_private *priv,
1370*4882a593Smuzhiyun 		      struct mwifiex_bssdescriptor *bss_desc)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun 	/* Return error if the adapter is not STA role or table entry
1373*4882a593Smuzhiyun 	 * is not marked as infra.
1374*4882a593Smuzhiyun 	 */
1375*4882a593Smuzhiyun 	if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) ||
1376*4882a593Smuzhiyun 	    (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
1377*4882a593Smuzhiyun 		return -1;
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
1380*4882a593Smuzhiyun 	    !bss_desc->disable_11n && !bss_desc->disable_11ac &&
1381*4882a593Smuzhiyun 	    priv->adapter->config_bands & BAND_AAC)
1382*4882a593Smuzhiyun 		mwifiex_set_11ac_ba_params(priv);
1383*4882a593Smuzhiyun 	else
1384*4882a593Smuzhiyun 		mwifiex_set_ba_params(priv);
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun 	/* Clear any past association response stored for application
1387*4882a593Smuzhiyun 	   retrieval */
1388*4882a593Smuzhiyun 	priv->assoc_rsp_size = 0;
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
1391*4882a593Smuzhiyun 				HostCmd_ACT_GEN_SET, 0, bss_desc, true);
1392*4882a593Smuzhiyun }
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun /*
1395*4882a593Smuzhiyun  * This function starts an ad-hoc network.
1396*4882a593Smuzhiyun  *
1397*4882a593Smuzhiyun  * It calls the command preparation routine to send the command to firmware.
1398*4882a593Smuzhiyun  */
1399*4882a593Smuzhiyun int
mwifiex_adhoc_start(struct mwifiex_private * priv,struct cfg80211_ssid * adhoc_ssid)1400*4882a593Smuzhiyun mwifiex_adhoc_start(struct mwifiex_private *priv,
1401*4882a593Smuzhiyun 		    struct cfg80211_ssid *adhoc_ssid)
1402*4882a593Smuzhiyun {
1403*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n",
1404*4882a593Smuzhiyun 		    priv->adhoc_channel);
1405*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n",
1406*4882a593Smuzhiyun 		    priv->curr_bss_params.bss_descriptor.channel);
1407*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n",
1408*4882a593Smuzhiyun 		    priv->curr_bss_params.band);
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
1411*4882a593Smuzhiyun 	    priv->adapter->config_bands & BAND_AAC)
1412*4882a593Smuzhiyun 		mwifiex_set_11ac_ba_params(priv);
1413*4882a593Smuzhiyun 	else
1414*4882a593Smuzhiyun 		mwifiex_set_ba_params(priv);
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun 	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
1417*4882a593Smuzhiyun 				HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true);
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun /*
1421*4882a593Smuzhiyun  * This function joins an ad-hoc network found in a previous scan.
1422*4882a593Smuzhiyun  *
1423*4882a593Smuzhiyun  * It calls the command preparation routine to send the command to firmware,
1424*4882a593Smuzhiyun  * if already not connected to the requested SSID.
1425*4882a593Smuzhiyun  */
mwifiex_adhoc_join(struct mwifiex_private * priv,struct mwifiex_bssdescriptor * bss_desc)1426*4882a593Smuzhiyun int mwifiex_adhoc_join(struct mwifiex_private *priv,
1427*4882a593Smuzhiyun 		       struct mwifiex_bssdescriptor *bss_desc)
1428*4882a593Smuzhiyun {
1429*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
1430*4882a593Smuzhiyun 		    "info: adhoc join: curr_bss ssid =%s\n",
1431*4882a593Smuzhiyun 		    priv->curr_bss_params.bss_descriptor.ssid.ssid);
1432*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
1433*4882a593Smuzhiyun 		    "info: adhoc join: curr_bss ssid_len =%u\n",
1434*4882a593Smuzhiyun 		    priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
1435*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n",
1436*4882a593Smuzhiyun 		    bss_desc->ssid.ssid);
1437*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n",
1438*4882a593Smuzhiyun 		    bss_desc->ssid.ssid_len);
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun 	/* Check if the requested SSID is already joined */
1441*4882a593Smuzhiyun 	if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
1442*4882a593Smuzhiyun 	    !mwifiex_ssid_cmp(&bss_desc->ssid,
1443*4882a593Smuzhiyun 			      &priv->curr_bss_params.bss_descriptor.ssid) &&
1444*4882a593Smuzhiyun 	    (priv->curr_bss_params.bss_descriptor.bss_mode ==
1445*4882a593Smuzhiyun 							NL80211_IFTYPE_ADHOC)) {
1446*4882a593Smuzhiyun 		mwifiex_dbg(priv->adapter, INFO,
1447*4882a593Smuzhiyun 			    "info: ADHOC_J_CMD: new ad-hoc SSID\t"
1448*4882a593Smuzhiyun 			    "is the same as current; not attempting to re-join\n");
1449*4882a593Smuzhiyun 		return -1;
1450*4882a593Smuzhiyun 	}
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
1453*4882a593Smuzhiyun 	    !bss_desc->disable_11n && !bss_desc->disable_11ac &&
1454*4882a593Smuzhiyun 	    priv->adapter->config_bands & BAND_AAC)
1455*4882a593Smuzhiyun 		mwifiex_set_11ac_ba_params(priv);
1456*4882a593Smuzhiyun 	else
1457*4882a593Smuzhiyun 		mwifiex_set_ba_params(priv);
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
1460*4882a593Smuzhiyun 		    "info: curr_bss_params.channel = %d\n",
1461*4882a593Smuzhiyun 		    priv->curr_bss_params.bss_descriptor.channel);
1462*4882a593Smuzhiyun 	mwifiex_dbg(priv->adapter, INFO,
1463*4882a593Smuzhiyun 		    "info: curr_bss_params.band = %c\n",
1464*4882a593Smuzhiyun 		    priv->curr_bss_params.band);
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
1467*4882a593Smuzhiyun 				HostCmd_ACT_GEN_SET, 0, bss_desc, true);
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun /*
1471*4882a593Smuzhiyun  * This function deauthenticates/disconnects from infra network by sending
1472*4882a593Smuzhiyun  * deauthentication request.
1473*4882a593Smuzhiyun  */
mwifiex_deauthenticate_infra(struct mwifiex_private * priv,u8 * mac)1474*4882a593Smuzhiyun static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
1475*4882a593Smuzhiyun {
1476*4882a593Smuzhiyun 	u8 mac_address[ETH_ALEN];
1477*4882a593Smuzhiyun 	int ret;
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun 	if (!mac || is_zero_ether_addr(mac))
1480*4882a593Smuzhiyun 		memcpy(mac_address,
1481*4882a593Smuzhiyun 		       priv->curr_bss_params.bss_descriptor.mac_address,
1482*4882a593Smuzhiyun 		       ETH_ALEN);
1483*4882a593Smuzhiyun 	else
1484*4882a593Smuzhiyun 		memcpy(mac_address, mac, ETH_ALEN);
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun 	ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
1487*4882a593Smuzhiyun 			       HostCmd_ACT_GEN_SET, 0, mac_address, true);
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	return ret;
1490*4882a593Smuzhiyun }
1491*4882a593Smuzhiyun 
1492*4882a593Smuzhiyun /*
1493*4882a593Smuzhiyun  * This function deauthenticates/disconnects from a BSS.
1494*4882a593Smuzhiyun  *
1495*4882a593Smuzhiyun  * In case of infra made, it sends deauthentication request, and
1496*4882a593Smuzhiyun  * in case of ad-hoc mode, a stop network request is sent to the firmware.
1497*4882a593Smuzhiyun  * In AP mode, a command to stop bss is sent to firmware.
1498*4882a593Smuzhiyun  */
mwifiex_deauthenticate(struct mwifiex_private * priv,u8 * mac)1499*4882a593Smuzhiyun int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun 	int ret = 0;
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	if (!priv->media_connected)
1504*4882a593Smuzhiyun 		return 0;
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	switch (priv->bss_mode) {
1507*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
1508*4882a593Smuzhiyun 	case NL80211_IFTYPE_P2P_CLIENT:
1509*4882a593Smuzhiyun 		ret = mwifiex_deauthenticate_infra(priv, mac);
1510*4882a593Smuzhiyun 		if (ret)
1511*4882a593Smuzhiyun 			cfg80211_disconnected(priv->netdev, 0, NULL, 0,
1512*4882a593Smuzhiyun 					      true, GFP_KERNEL);
1513*4882a593Smuzhiyun 		break;
1514*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
1515*4882a593Smuzhiyun 		return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
1516*4882a593Smuzhiyun 					HostCmd_ACT_GEN_SET, 0, NULL, true);
1517*4882a593Smuzhiyun 	case NL80211_IFTYPE_AP:
1518*4882a593Smuzhiyun 		return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
1519*4882a593Smuzhiyun 					HostCmd_ACT_GEN_SET, 0, NULL, true);
1520*4882a593Smuzhiyun 	default:
1521*4882a593Smuzhiyun 		break;
1522*4882a593Smuzhiyun 	}
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun 	return ret;
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun /* This function deauthenticates/disconnects from all BSS. */
mwifiex_deauthenticate_all(struct mwifiex_adapter * adapter)1528*4882a593Smuzhiyun void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun 	struct mwifiex_private *priv;
1531*4882a593Smuzhiyun 	int i;
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	for (i = 0; i < adapter->priv_num; i++) {
1534*4882a593Smuzhiyun 		priv = adapter->priv[i];
1535*4882a593Smuzhiyun 		if (priv)
1536*4882a593Smuzhiyun 			mwifiex_deauthenticate(priv, NULL);
1537*4882a593Smuzhiyun 	}
1538*4882a593Smuzhiyun }
1539*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all);
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun /*
1542*4882a593Smuzhiyun  * This function converts band to radio type used in channel TLV.
1543*4882a593Smuzhiyun  */
1544*4882a593Smuzhiyun u8
mwifiex_band_to_radio_type(u8 band)1545*4882a593Smuzhiyun mwifiex_band_to_radio_type(u8 band)
1546*4882a593Smuzhiyun {
1547*4882a593Smuzhiyun 	switch (band) {
1548*4882a593Smuzhiyun 	case BAND_A:
1549*4882a593Smuzhiyun 	case BAND_AN:
1550*4882a593Smuzhiyun 	case BAND_A | BAND_AN:
1551*4882a593Smuzhiyun 	case BAND_A | BAND_AN | BAND_AAC:
1552*4882a593Smuzhiyun 		return HostCmd_SCAN_RADIO_TYPE_A;
1553*4882a593Smuzhiyun 	case BAND_B:
1554*4882a593Smuzhiyun 	case BAND_G:
1555*4882a593Smuzhiyun 	case BAND_B | BAND_G:
1556*4882a593Smuzhiyun 	default:
1557*4882a593Smuzhiyun 		return HostCmd_SCAN_RADIO_TYPE_BG;
1558*4882a593Smuzhiyun 	}
1559*4882a593Smuzhiyun }
1560