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