Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge
[cascardo/linux.git] / drivers / net / wireless / mwifiex / sta_cmd.c
1 /*
2  * Marvell Wireless LAN device driver: station command handling
3  *
4  * Copyright (C) 2011, Marvell International Ltd.
5  *
6  * This software file (the "File") is distributed by Marvell International
7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8  * (the "License").  You may use, redistribute and/or modify this File in
9  * accordance with the terms and conditions of the License, a copy of which
10  * is available by writing to the Free Software Foundation, Inc.,
11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13  *
14  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
17  * this warranty disclaimer.
18  */
19
20 #include "decl.h"
21 #include "ioctl.h"
22 #include "util.h"
23 #include "fw.h"
24 #include "main.h"
25 #include "wmm.h"
26 #include "11n.h"
27
28 /*
29  * This function prepares command to set/get RSSI information.
30  *
31  * Preparation includes -
32  *      - Setting command ID, action and proper size
33  *      - Setting data/beacon average factors
34  *      - Resetting SNR/NF/RSSI values in private structure
35  *      - Ensuring correct endian-ness
36  */
37 static int
38 mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv,
39                              struct host_cmd_ds_command *cmd, u16 cmd_action)
40 {
41         cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO);
42         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) +
43                                 S_DS_GEN);
44         cmd->params.rssi_info.action = cpu_to_le16(cmd_action);
45         cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor);
46         cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor);
47
48         /* Reset SNR/NF/RSSI values in private structure */
49         priv->data_rssi_last = 0;
50         priv->data_nf_last = 0;
51         priv->data_rssi_avg = 0;
52         priv->data_nf_avg = 0;
53         priv->bcn_rssi_last = 0;
54         priv->bcn_nf_last = 0;
55         priv->bcn_rssi_avg = 0;
56         priv->bcn_nf_avg = 0;
57
58         return 0;
59 }
60
61 /*
62  * This function prepares command to set MAC control.
63  *
64  * Preparation includes -
65  *      - Setting command ID, action and proper size
66  *      - Ensuring correct endian-ness
67  */
68 static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
69                                    struct host_cmd_ds_command *cmd,
70                                    u16 cmd_action, void *data_buf)
71 {
72         struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
73         u16 action = *((u16 *) data_buf);
74
75         if (cmd_action != HostCmd_ACT_GEN_SET) {
76                 dev_err(priv->adapter->dev,
77                         "mac_control: only support set cmd\n");
78                 return -1;
79         }
80
81         cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
82         cmd->size =
83                 cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN);
84         mac_ctrl->action = cpu_to_le16(action);
85
86         return 0;
87 }
88
89 /*
90  * This function prepares command to set/get SNMP MIB.
91  *
92  * Preparation includes -
93  *      - Setting command ID, action and proper size
94  *      - Setting SNMP MIB OID number and value
95  *        (as required)
96  *      - Ensuring correct endian-ness
97  *
98  * The following SNMP MIB OIDs are supported -
99  *      - FRAG_THRESH_I     : Fragmentation threshold
100  *      - RTS_THRESH_I      : RTS threshold
101  *      - SHORT_RETRY_LIM_I : Short retry limit
102  *      - DOT11D_I          : 11d support
103  */
104 static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
105                                        struct host_cmd_ds_command *cmd,
106                                        u16 cmd_action, u32 cmd_oid,
107                                        void *data_buf)
108 {
109         struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
110         u32 ul_temp;
111
112         dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
113         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
114         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
115                 - 1 + S_DS_GEN);
116
117         if (cmd_action == HostCmd_ACT_GEN_GET) {
118                 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET);
119                 snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE);
120                 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
121                         + MAX_SNMP_BUF_SIZE);
122         }
123
124         switch (cmd_oid) {
125         case FRAG_THRESH_I:
126                 snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I);
127                 if (cmd_action == HostCmd_ACT_GEN_SET) {
128                         snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
129                         snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
130                         ul_temp = *((u32 *) data_buf);
131                         *((__le16 *) (snmp_mib->value)) =
132                                 cpu_to_le16((u16) ul_temp);
133                         cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
134                                 + sizeof(u16));
135                 }
136                 break;
137         case RTS_THRESH_I:
138                 snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I);
139                 if (cmd_action == HostCmd_ACT_GEN_SET) {
140                         snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
141                         snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
142                         ul_temp = *((u32 *) data_buf);
143                         *(__le16 *) (snmp_mib->value) =
144                                 cpu_to_le16((u16) ul_temp);
145                         cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
146                                 + sizeof(u16));
147                 }
148                 break;
149
150         case SHORT_RETRY_LIM_I:
151                 snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I);
152                 if (cmd_action == HostCmd_ACT_GEN_SET) {
153                         snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
154                         snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
155                         ul_temp = (*(u32 *) data_buf);
156                         *((__le16 *) (snmp_mib->value)) =
157                                 cpu_to_le16((u16) ul_temp);
158                         cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
159                                 + sizeof(u16));
160                 }
161                 break;
162         case DOT11D_I:
163                 snmp_mib->oid = cpu_to_le16((u16) DOT11D_I);
164                 if (cmd_action == HostCmd_ACT_GEN_SET) {
165                         snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
166                         snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
167                         ul_temp = *(u32 *) data_buf;
168                         *((__le16 *) (snmp_mib->value)) =
169                                 cpu_to_le16((u16) ul_temp);
170                         cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
171                                 + sizeof(u16));
172                 }
173                 break;
174         default:
175                 break;
176         }
177         dev_dbg(priv->adapter->dev,
178                 "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
179                 " Value=0x%x\n",
180                cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
181                le16_to_cpu(*(__le16 *) snmp_mib->value));
182         return 0;
183 }
184
185 /*
186  * This function prepares command to get log.
187  *
188  * Preparation includes -
189  *      - Setting command ID and proper size
190  *      - Ensuring correct endian-ness
191  */
192 static int
193 mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd)
194 {
195         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
196         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
197                                 S_DS_GEN);
198         return 0;
199 }
200
201 /*
202  * This function prepares command to set/get Tx data rate configuration.
203  *
204  * Preparation includes -
205  *      - Setting command ID, action and proper size
206  *      - Setting configuration index, rate scope and rate drop pattern
207  *        parameters (as required)
208  *      - Ensuring correct endian-ness
209  */
210 static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
211                                    struct host_cmd_ds_command *cmd,
212                                    u16 cmd_action, void *data_buf)
213 {
214         struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
215         struct mwifiex_rate_scope *rate_scope;
216         struct mwifiex_rate_drop_pattern *rate_drop;
217         u16 *pbitmap_rates = (u16 *) data_buf;
218
219         u32 i;
220
221         cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
222
223         rate_cfg->action = cpu_to_le16(cmd_action);
224         rate_cfg->cfg_index = 0;
225
226         rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
227                       sizeof(struct host_cmd_ds_tx_rate_cfg));
228         rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
229         rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) -
230                         sizeof(struct mwifiex_ie_types_header));
231         if (pbitmap_rates != NULL) {
232                 rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
233                 rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
234                 for (i = 0;
235                      i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
236                      i++)
237                         rate_scope->ht_mcs_rate_bitmap[i] =
238                                 cpu_to_le16(pbitmap_rates[2 + i]);
239         } else {
240                 rate_scope->hr_dsss_rate_bitmap =
241                         cpu_to_le16(priv->bitmap_rates[0]);
242                 rate_scope->ofdm_rate_bitmap =
243                         cpu_to_le16(priv->bitmap_rates[1]);
244                 for (i = 0;
245                      i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
246                      i++)
247                         rate_scope->ht_mcs_rate_bitmap[i] =
248                                 cpu_to_le16(priv->bitmap_rates[2 + i]);
249         }
250
251         rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
252                         sizeof(struct mwifiex_rate_scope));
253         rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
254         rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
255         rate_drop->rate_drop_mode = 0;
256
257         cmd->size =
258                 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
259                             sizeof(struct mwifiex_rate_scope) +
260                             sizeof(struct mwifiex_rate_drop_pattern));
261
262         return 0;
263 }
264
265 /*
266  * This function prepares command to set/get Tx power configuration.
267  *
268  * Preparation includes -
269  *      - Setting command ID, action and proper size
270  *      - Setting Tx power mode, power group TLV
271  *        (as required)
272  *      - Ensuring correct endian-ness
273  */
274 static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
275                                     u16 cmd_action, void *data_buf)
276 {
277         struct mwifiex_types_power_group *pg_tlv = NULL;
278         struct host_cmd_ds_txpwr_cfg *txp = NULL;
279         struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
280
281         cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
282         cmd->size =
283                 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
284         switch (cmd_action) {
285         case HostCmd_ACT_GEN_SET:
286                 txp = (struct host_cmd_ds_txpwr_cfg *) data_buf;
287                 if (txp->mode) {
288                         pg_tlv = (struct mwifiex_types_power_group
289                                   *) ((unsigned long) data_buf +
290                                      sizeof(struct host_cmd_ds_txpwr_cfg));
291                         memmove(cmd_txp_cfg, data_buf,
292                                 sizeof(struct host_cmd_ds_txpwr_cfg) +
293                                 sizeof(struct mwifiex_types_power_group) +
294                                 pg_tlv->length);
295
296                         pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
297                                   cmd_txp_cfg +
298                                   sizeof(struct host_cmd_ds_txpwr_cfg));
299                         cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
300                                   sizeof(struct mwifiex_types_power_group) +
301                                   pg_tlv->length);
302                 } else {
303                         memmove(cmd_txp_cfg, data_buf,
304                                 sizeof(struct host_cmd_ds_txpwr_cfg));
305                 }
306                 cmd_txp_cfg->action = cpu_to_le16(cmd_action);
307                 break;
308         case HostCmd_ACT_GEN_GET:
309                 cmd_txp_cfg->action = cpu_to_le16(cmd_action);
310                 break;
311         }
312
313         return 0;
314 }
315
316 /*
317  * This function prepares command to set Host Sleep configuration.
318  *
319  * Preparation includes -
320  *      - Setting command ID and proper size
321  *      - Setting Host Sleep action, conditions, ARP filters
322  *        (as required)
323  *      - Ensuring correct endian-ness
324  */
325 static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
326                                      struct host_cmd_ds_command *cmd,
327                                      u16 cmd_action,
328                                      struct mwifiex_hs_config_param *data_buf)
329 {
330         struct mwifiex_adapter *adapter = priv->adapter;
331         struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
332         u16 hs_activate = false;
333
334         if (data_buf == NULL)
335                 /* New Activate command */
336                 hs_activate = true;
337         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
338
339         if (!hs_activate &&
340             (data_buf->conditions
341             != cpu_to_le32(HOST_SLEEP_CFG_CANCEL))
342             && ((adapter->arp_filter_size > 0)
343                 && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
344                 dev_dbg(adapter->dev,
345                         "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
346                        adapter->arp_filter_size);
347                 memcpy(((u8 *) hs_cfg) +
348                        sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
349                        adapter->arp_filter, adapter->arp_filter_size);
350                 cmd->size = cpu_to_le16(adapter->arp_filter_size +
351                                     sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
352                                     + S_DS_GEN);
353         } else {
354                 cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct
355                                            host_cmd_ds_802_11_hs_cfg_enh));
356         }
357         if (hs_activate) {
358                 hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
359                 hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
360         } else {
361                 hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
362                 hs_cfg->params.hs_config.conditions = data_buf->conditions;
363                 hs_cfg->params.hs_config.gpio = data_buf->gpio;
364                 hs_cfg->params.hs_config.gap = data_buf->gap;
365                 dev_dbg(adapter->dev,
366                         "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
367                        hs_cfg->params.hs_config.conditions,
368                        hs_cfg->params.hs_config.gpio,
369                        hs_cfg->params.hs_config.gap);
370         }
371
372         return 0;
373 }
374
375 /*
376  * This function prepares command to set/get MAC address.
377  *
378  * Preparation includes -
379  *      - Setting command ID, action and proper size
380  *      - Setting MAC address (for SET only)
381  *      - Ensuring correct endian-ness
382  */
383 static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
384                                           struct host_cmd_ds_command *cmd,
385                                           u16 cmd_action)
386 {
387         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
388         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
389                                 S_DS_GEN);
390         cmd->result = 0;
391
392         cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
393
394         if (cmd_action == HostCmd_ACT_GEN_SET)
395                 memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
396                        ETH_ALEN);
397         return 0;
398 }
399
400 /*
401  * This function prepares command to set MAC multicast address.
402  *
403  * Preparation includes -
404  *      - Setting command ID, action and proper size
405  *      - Setting MAC multicast address
406  *      - Ensuring correct endian-ness
407  */
408 static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd,
409                                          u16 cmd_action, void *data_buf)
410 {
411         struct mwifiex_multicast_list *mcast_list =
412                 (struct mwifiex_multicast_list *) data_buf;
413         struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
414
415         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
416                                 S_DS_GEN);
417         cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
418
419         mcast_addr->action = cpu_to_le16(cmd_action);
420         mcast_addr->num_of_adrs =
421                 cpu_to_le16((u16) mcast_list->num_multicast_addr);
422         memcpy(mcast_addr->mac_list, mcast_list->mac_list,
423                mcast_list->num_multicast_addr * ETH_ALEN);
424
425         return 0;
426 }
427
428 /*
429  * This function prepares command to deauthenticate.
430  *
431  * Preparation includes -
432  *      - Setting command ID and proper size
433  *      - Setting AP MAC address and reason code
434  *      - Ensuring correct endian-ness
435  */
436 static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
437                                              struct host_cmd_ds_command *cmd,
438                                              void *data_buf)
439 {
440         struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
441
442         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
443         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
444                                 + S_DS_GEN);
445
446         /* Set AP MAC address */
447         memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN);
448
449         dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
450
451         deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
452
453         return 0;
454 }
455
456 /*
457  * This function prepares command to stop Ad-Hoc network.
458  *
459  * Preparation includes -
460  *      - Setting command ID and proper size
461  *      - Ensuring correct endian-ness
462  */
463 static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd)
464 {
465         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
466         cmd->size = cpu_to_le16(S_DS_GEN);
467         return 0;
468 }
469
470 /*
471  * This function sets WEP key(s) to key parameter TLV(s).
472  *
473  * Multi-key parameter TLVs are supported, so we can send multiple
474  * WEP keys in a single buffer.
475  */
476 static int
477 mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
478                             struct mwifiex_ie_type_key_param_set *key_param_set,
479                             u16 *key_param_len)
480 {
481         int cur_key_param_len = 0;
482         u8 i;
483
484         /* Multi-key_param_set TLV is supported */
485         for (i = 0; i < NUM_WEP_KEYS; i++) {
486                 if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
487                     (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
488                         key_param_set->type =
489                                 cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
490 /* Key_param_set WEP fixed length */
491 #define KEYPARAMSET_WEP_FIXED_LEN 8
492                         key_param_set->length = cpu_to_le16((u16)
493                                         (priv->wep_key[i].
494                                          key_length +
495                                          KEYPARAMSET_WEP_FIXED_LEN));
496                         key_param_set->key_type_id =
497                                 cpu_to_le16(KEY_TYPE_ID_WEP);
498                         key_param_set->key_info =
499                                 cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
500                                             KEY_MCAST);
501                         key_param_set->key_len =
502                                 cpu_to_le16(priv->wep_key[i].key_length);
503                         /* Set WEP key index */
504                         key_param_set->key[0] = i;
505                         /* Set default Tx key flag */
506                         if (i ==
507                             (priv->
508                              wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
509                                 key_param_set->key[1] = 1;
510                         else
511                                 key_param_set->key[1] = 0;
512                         memmove(&key_param_set->key[2],
513                                 priv->wep_key[i].key_material,
514                                 priv->wep_key[i].key_length);
515
516                         cur_key_param_len = priv->wep_key[i].key_length +
517                                 KEYPARAMSET_WEP_FIXED_LEN +
518                                 sizeof(struct mwifiex_ie_types_header);
519                         *key_param_len += (u16) cur_key_param_len;
520                         key_param_set =
521                                 (struct mwifiex_ie_type_key_param_set *)
522                                                 ((u8 *)key_param_set +
523                                                 cur_key_param_len);
524                 } else if (!priv->wep_key[i].key_length) {
525                         continue;
526                 } else {
527                         dev_err(priv->adapter->dev,
528                                 "key%d Length = %d is incorrect\n",
529                                (i + 1), priv->wep_key[i].key_length);
530                         return -1;
531                 }
532         }
533
534         return 0;
535 }
536
537 /*
538  * This function prepares command to set/get/reset network key(s).
539  *
540  * Preparation includes -
541  *      - Setting command ID, action and proper size
542  *      - Setting WEP keys, WAPI keys or WPA keys along with required
543  *        encryption (TKIP, AES) (as required)
544  *      - Ensuring correct endian-ness
545  */
546 static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
547                                            struct host_cmd_ds_command *cmd,
548                                            u16 cmd_action,
549                                            u32 cmd_oid, void *data_buf)
550 {
551         struct host_cmd_ds_802_11_key_material *key_material =
552                 &cmd->params.key_material;
553         struct mwifiex_ds_encrypt_key *enc_key =
554                 (struct mwifiex_ds_encrypt_key *) data_buf;
555         u16 key_param_len = 0;
556         int ret = 0;
557         const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
558
559         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
560         key_material->action = cpu_to_le16(cmd_action);
561
562         if (cmd_action == HostCmd_ACT_GEN_GET) {
563                 cmd->size =
564                         cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
565                 return ret;
566         }
567
568         if (!enc_key) {
569                 memset(&key_material->key_param_set, 0,
570                        (NUM_WEP_KEYS *
571                         sizeof(struct mwifiex_ie_type_key_param_set)));
572                 ret = mwifiex_set_keyparamset_wep(priv,
573                                                   &key_material->key_param_set,
574                                                   &key_param_len);
575                 cmd->size = cpu_to_le16(key_param_len +
576                                     sizeof(key_material->action) + S_DS_GEN);
577                 return ret;
578         } else
579                 memset(&key_material->key_param_set, 0,
580                        sizeof(struct mwifiex_ie_type_key_param_set));
581         if (enc_key->is_wapi_key) {
582                 dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
583                 key_material->key_param_set.key_type_id =
584                         cpu_to_le16(KEY_TYPE_ID_WAPI);
585                 if (cmd_oid == KEY_INFO_ENABLED)
586                         key_material->key_param_set.key_info =
587                                 cpu_to_le16(KEY_ENABLED);
588                 else
589                         key_material->key_param_set.key_info =
590                                 cpu_to_le16(!KEY_ENABLED);
591
592                 key_material->key_param_set.key[0] = enc_key->key_index;
593                 if (!priv->sec_info.wapi_key_on)
594                         key_material->key_param_set.key[1] = 1;
595                 else
596                         /* set 0 when re-key */
597                         key_material->key_param_set.key[1] = 0;
598
599                 if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
600                         /* WAPI pairwise key: unicast */
601                         key_material->key_param_set.key_info |=
602                                 cpu_to_le16(KEY_UNICAST);
603                 } else {        /* WAPI group key: multicast */
604                         key_material->key_param_set.key_info |=
605                                 cpu_to_le16(KEY_MCAST);
606                         priv->sec_info.wapi_key_on = true;
607                 }
608
609                 key_material->key_param_set.type =
610                         cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
611                 key_material->key_param_set.key_len =
612                         cpu_to_le16(WAPI_KEY_LEN);
613                 memcpy(&key_material->key_param_set.key[2],
614                        enc_key->key_material, enc_key->key_len);
615                 memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
616                        enc_key->wapi_rxpn, WAPI_RXPN_LEN);
617                 key_material->key_param_set.length =
618                         cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
619
620                 key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
621                                  sizeof(struct mwifiex_ie_types_header);
622                 cmd->size = cpu_to_le16(key_param_len +
623                                 sizeof(key_material->action) + S_DS_GEN);
624                 return ret;
625         }
626         if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
627                 dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
628                 key_material->key_param_set.key_type_id =
629                         cpu_to_le16(KEY_TYPE_ID_AES);
630                 if (cmd_oid == KEY_INFO_ENABLED)
631                         key_material->key_param_set.key_info =
632                                 cpu_to_le16(KEY_ENABLED);
633                 else
634                         key_material->key_param_set.key_info =
635                                 cpu_to_le16(!KEY_ENABLED);
636
637                 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
638                                 /* AES pairwise key: unicast */
639                         key_material->key_param_set.key_info |=
640                                 cpu_to_le16(KEY_UNICAST);
641                 else            /* AES group key: multicast */
642                         key_material->key_param_set.key_info |=
643                                 cpu_to_le16(KEY_MCAST);
644         } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
645                 dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
646                 key_material->key_param_set.key_type_id =
647                         cpu_to_le16(KEY_TYPE_ID_TKIP);
648                 key_material->key_param_set.key_info =
649                         cpu_to_le16(KEY_ENABLED);
650
651                 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
652                                 /* TKIP pairwise key: unicast */
653                         key_material->key_param_set.key_info |=
654                                 cpu_to_le16(KEY_UNICAST);
655                 else            /* TKIP group key: multicast */
656                         key_material->key_param_set.key_info |=
657                                 cpu_to_le16(KEY_MCAST);
658         }
659
660         if (key_material->key_param_set.key_type_id) {
661                 key_material->key_param_set.type =
662                         cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
663                 key_material->key_param_set.key_len =
664                         cpu_to_le16((u16) enc_key->key_len);
665                 memcpy(key_material->key_param_set.key, enc_key->key_material,
666                        enc_key->key_len);
667                 key_material->key_param_set.length =
668                         cpu_to_le16((u16) enc_key->key_len +
669                                     KEYPARAMSET_FIXED_LEN);
670
671                 key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
672                                       + sizeof(struct mwifiex_ie_types_header);
673
674                 cmd->size = cpu_to_le16(key_param_len +
675                                     sizeof(key_material->action) + S_DS_GEN);
676         }
677
678         return ret;
679 }
680
681 /*
682  * This function prepares command to set/get 11d domain information.
683  *
684  * Preparation includes -
685  *      - Setting command ID, action and proper size
686  *      - Setting domain information fields (for SET only)
687  *      - Ensuring correct endian-ness
688  */
689 static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
690                                            struct host_cmd_ds_command *cmd,
691                                            u16 cmd_action)
692 {
693         struct mwifiex_adapter *adapter = priv->adapter;
694         struct host_cmd_ds_802_11d_domain_info *domain_info =
695                 &cmd->params.domain_info;
696         struct mwifiex_ietypes_domain_param_set *domain =
697                 &domain_info->domain;
698         u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
699
700         dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
701
702         cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
703         domain_info->action = cpu_to_le16(cmd_action);
704         if (cmd_action == HostCmd_ACT_GEN_GET) {
705                 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
706                 return 0;
707         }
708
709         /* Set domain info fields */
710         domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
711         memcpy(domain->country_code, adapter->domain_reg.country_code,
712                         sizeof(domain->country_code));
713
714         domain->header.len = cpu_to_le16((no_of_triplet *
715                                 sizeof(struct ieee80211_country_ie_triplet)) +
716                                 sizeof(domain->country_code));
717
718         if (no_of_triplet) {
719                 memcpy(domain->triplet, adapter->domain_reg.triplet,
720                                 no_of_triplet *
721                                 sizeof(struct ieee80211_country_ie_triplet));
722
723                 cmd->size = cpu_to_le16(sizeof(domain_info->action) +
724                                 le16_to_cpu(domain->header.len) +
725                                 sizeof(struct mwifiex_ie_types_header)
726                                 + S_DS_GEN);
727         } else {
728                 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
729         }
730
731         return 0;
732 }
733
734 /*
735  * This function prepares command to set/get RF channel.
736  *
737  * Preparation includes -
738  *      - Setting command ID, action and proper size
739  *      - Setting RF type and current RF channel (for SET only)
740  *      - Ensuring correct endian-ness
741  */
742 static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv,
743                                          struct host_cmd_ds_command *cmd,
744                                          u16 cmd_action, void *data_buf)
745 {
746         struct host_cmd_ds_802_11_rf_channel *rf_chan =
747                 &cmd->params.rf_channel;
748         uint16_t rf_type = le16_to_cpu(rf_chan->rf_type);
749
750         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
751         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel)
752                                 + S_DS_GEN);
753
754         if (cmd_action == HostCmd_ACT_GEN_SET) {
755                 if ((priv->adapter->adhoc_start_band & BAND_A)
756                     || (priv->adapter->adhoc_start_band & BAND_AN))
757                         rf_chan->rf_type =
758                                 cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A);
759
760                 rf_type = le16_to_cpu(rf_chan->rf_type);
761                 SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset);
762                 rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf));
763         }
764         rf_chan->action = cpu_to_le16(cmd_action);
765         return 0;
766 }
767
768 /*
769  * This function prepares command to set/get IBSS coalescing status.
770  *
771  * Preparation includes -
772  *      - Setting command ID, action and proper size
773  *      - Setting status to enable or disable (for SET only)
774  *      - Ensuring correct endian-ness
775  */
776 static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
777                                               u16 cmd_action, void *data_buf)
778 {
779         struct host_cmd_ds_802_11_ibss_status *ibss_coal =
780                 &(cmd->params.ibss_coalescing);
781         u16 enable = 0;
782
783         cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
784         cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
785                                 S_DS_GEN);
786         cmd->result = 0;
787         ibss_coal->action = cpu_to_le16(cmd_action);
788
789         switch (cmd_action) {
790         case HostCmd_ACT_GEN_SET:
791                 if (data_buf != NULL)
792                         enable = *(u16 *) data_buf;
793                 ibss_coal->enable = cpu_to_le16(enable);
794                 break;
795
796                 /* In other case.. Nothing to do */
797         case HostCmd_ACT_GEN_GET:
798         default:
799                 break;
800         }
801
802         return 0;
803 }
804
805 /*
806  * This function prepares command to set/get register value.
807  *
808  * Preparation includes -
809  *      - Setting command ID, action and proper size
810  *      - Setting register offset (for both GET and SET) and
811  *        register value (for SET only)
812  *      - Ensuring correct endian-ness
813  *
814  * The following type of registers can be accessed with this function -
815  *      - MAC register
816  *      - BBP register
817  *      - RF register
818  *      - PMIC register
819  *      - CAU register
820  *      - EEPROM
821  */
822 static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
823                                   u16 cmd_action, void *data_buf)
824 {
825         struct mwifiex_ds_reg_rw *reg_rw;
826
827         reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
828         switch (le16_to_cpu(cmd->command)) {
829         case HostCmd_CMD_MAC_REG_ACCESS:
830         {
831                 struct host_cmd_ds_mac_reg_access *mac_reg;
832
833                 cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
834                 mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
835                         params.mac_reg;
836                 mac_reg->action = cpu_to_le16(cmd_action);
837                 mac_reg->offset =
838                         cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
839                 mac_reg->value = reg_rw->value;
840                 break;
841         }
842         case HostCmd_CMD_BBP_REG_ACCESS:
843         {
844                 struct host_cmd_ds_bbp_reg_access *bbp_reg;
845
846                 cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
847                 bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd->
848                         params.bbp_reg;
849                 bbp_reg->action = cpu_to_le16(cmd_action);
850                 bbp_reg->offset =
851                         cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
852                 bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
853                 break;
854         }
855         case HostCmd_CMD_RF_REG_ACCESS:
856         {
857                 struct host_cmd_ds_rf_reg_access *rf_reg;
858
859                 cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
860                 rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
861                         params.rf_reg;
862                 rf_reg->action = cpu_to_le16(cmd_action);
863                 rf_reg->offset =
864                         cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
865                 rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
866                 break;
867         }
868         case HostCmd_CMD_PMIC_REG_ACCESS:
869         {
870                 struct host_cmd_ds_pmic_reg_access *pmic_reg;
871
872                 cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
873                 pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
874                                 params.pmic_reg;
875                 pmic_reg->action = cpu_to_le16(cmd_action);
876                 pmic_reg->offset =
877                         cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
878                 pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
879                 break;
880         }
881         case HostCmd_CMD_CAU_REG_ACCESS:
882         {
883                 struct host_cmd_ds_rf_reg_access *cau_reg;
884
885                 cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
886                 cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
887                                 params.rf_reg;
888                 cau_reg->action = cpu_to_le16(cmd_action);
889                 cau_reg->offset =
890                         cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
891                 cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
892                 break;
893         }
894         case HostCmd_CMD_802_11_EEPROM_ACCESS:
895         {
896                 struct mwifiex_ds_read_eeprom *rd_eeprom =
897                         (struct mwifiex_ds_read_eeprom *) data_buf;
898                 struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
899                         (struct host_cmd_ds_802_11_eeprom_access *)
900                         &cmd->params.eeprom;
901
902                 cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
903                 cmd_eeprom->action = cpu_to_le16(cmd_action);
904                 cmd_eeprom->offset = rd_eeprom->offset;
905                 cmd_eeprom->byte_count = rd_eeprom->byte_count;
906                 cmd_eeprom->value = 0;
907                 break;
908         }
909         default:
910                 return -1;
911         }
912
913         return 0;
914 }
915
916 /*
917  * This function prepares the commands before sending them to the firmware.
918  *
919  * This is a generic function which calls specific command preparation
920  * routines based upon the command number.
921  */
922 int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
923                             u16 cmd_action, u32 cmd_oid,
924                             void *data_buf, void *cmd_buf)
925 {
926         struct host_cmd_ds_command *cmd_ptr =
927                 (struct host_cmd_ds_command *) cmd_buf;
928         int ret = 0;
929
930         /* Prepare command */
931         switch (cmd_no) {
932         case HostCmd_CMD_GET_HW_SPEC:
933                 ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
934                 break;
935         case HostCmd_CMD_MAC_CONTROL:
936                 ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
937                                               data_buf);
938                 break;
939         case HostCmd_CMD_802_11_MAC_ADDRESS:
940                 ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
941                                                      cmd_action);
942                 break;
943         case HostCmd_CMD_MAC_MULTICAST_ADR:
944                 ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
945                                                     data_buf);
946                 break;
947         case HostCmd_CMD_TX_RATE_CFG:
948                 ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
949                                               data_buf);
950                 break;
951         case HostCmd_CMD_TXPWR_CFG:
952                 ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
953                                                data_buf);
954                 break;
955         case HostCmd_CMD_802_11_PS_MODE_ENH:
956                 ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
957                                                  (uint16_t)cmd_oid, data_buf);
958                 break;
959         case HostCmd_CMD_802_11_HS_CFG_ENH:
960                 ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
961                                 (struct mwifiex_hs_config_param *) data_buf);
962                 break;
963         case HostCmd_CMD_802_11_SCAN:
964                 ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
965                 break;
966         case HostCmd_CMD_802_11_BG_SCAN_QUERY:
967                 ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
968                 break;
969         case HostCmd_CMD_802_11_ASSOCIATE:
970                 ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
971                 break;
972         case HostCmd_CMD_802_11_DEAUTHENTICATE:
973                 ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
974                                                         data_buf);
975                 break;
976         case HostCmd_CMD_802_11_AD_HOC_START:
977                 ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
978                                                       data_buf);
979                 break;
980         case HostCmd_CMD_802_11_GET_LOG:
981                 ret = mwifiex_cmd_802_11_get_log(cmd_ptr);
982                 break;
983         case HostCmd_CMD_802_11_AD_HOC_JOIN:
984                 ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
985                                                      data_buf);
986                 break;
987         case HostCmd_CMD_802_11_AD_HOC_STOP:
988                 ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr);
989                 break;
990         case HostCmd_CMD_RSSI_INFO:
991                 ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
992                 break;
993         case HostCmd_CMD_802_11_SNMP_MIB:
994                 ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
995                                                   cmd_oid, data_buf);
996                 break;
997         case HostCmd_CMD_802_11_TX_RATE_QUERY:
998                 cmd_ptr->command =
999                         cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
1000                 cmd_ptr->size =
1001                         cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
1002                                     S_DS_GEN);
1003                 priv->tx_rate = 0;
1004                 ret = 0;
1005                 break;
1006         case HostCmd_CMD_VERSION_EXT:
1007                 cmd_ptr->command = cpu_to_le16(cmd_no);
1008                 cmd_ptr->params.verext.version_str_sel =
1009                         (u8) (*((u32 *) data_buf));
1010                 memcpy(&cmd_ptr->params, data_buf,
1011                        sizeof(struct host_cmd_ds_version_ext));
1012                 cmd_ptr->size =
1013                         cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
1014                                     S_DS_GEN);
1015                 ret = 0;
1016                 break;
1017         case HostCmd_CMD_802_11_RF_CHANNEL:
1018                 ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action,
1019                                                     data_buf);
1020                 break;
1021         case HostCmd_CMD_FUNC_INIT:
1022                 if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
1023                         priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
1024                 cmd_ptr->command = cpu_to_le16(cmd_no);
1025                 cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1026                 break;
1027         case HostCmd_CMD_FUNC_SHUTDOWN:
1028                 priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
1029                 cmd_ptr->command = cpu_to_le16(cmd_no);
1030                 cmd_ptr->size = cpu_to_le16(S_DS_GEN);
1031                 break;
1032         case HostCmd_CMD_11N_ADDBA_REQ:
1033                 ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf);
1034                 break;
1035         case HostCmd_CMD_11N_DELBA:
1036                 ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf);
1037                 break;
1038         case HostCmd_CMD_11N_ADDBA_RSP:
1039                 ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
1040                 break;
1041         case HostCmd_CMD_802_11_KEY_MATERIAL:
1042                 ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
1043                                                 cmd_action, cmd_oid,
1044                                                 data_buf);
1045                 break;
1046         case HostCmd_CMD_802_11D_DOMAIN_INFO:
1047                 ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
1048                                                 cmd_action);
1049                 break;
1050         case HostCmd_CMD_RECONFIGURE_TX_BUFF:
1051                 ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
1052                                                data_buf);
1053                 break;
1054         case HostCmd_CMD_AMSDU_AGGR_CTRL:
1055                 ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
1056                                                   data_buf);
1057                 break;
1058         case HostCmd_CMD_11N_CFG:
1059                 ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action,
1060                                           data_buf);
1061                 break;
1062         case HostCmd_CMD_WMM_GET_STATUS:
1063                 dev_dbg(priv->adapter->dev,
1064                         "cmd: WMM: WMM_GET_STATUS cmd sent\n");
1065                 cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
1066                 cmd_ptr->size =
1067                         cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
1068                                     S_DS_GEN);
1069                 ret = 0;
1070                 break;
1071         case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
1072                 ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
1073                                                          data_buf);
1074                 break;
1075         case HostCmd_CMD_MAC_REG_ACCESS:
1076         case HostCmd_CMD_BBP_REG_ACCESS:
1077         case HostCmd_CMD_RF_REG_ACCESS:
1078         case HostCmd_CMD_PMIC_REG_ACCESS:
1079         case HostCmd_CMD_CAU_REG_ACCESS:
1080         case HostCmd_CMD_802_11_EEPROM_ACCESS:
1081                 ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
1082                 break;
1083         case HostCmd_CMD_SET_BSS_MODE:
1084                 cmd_ptr->command = cpu_to_le16(cmd_no);
1085                 if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
1086                         cmd_ptr->params.bss_mode.con_type =
1087                                 CONNECTION_TYPE_ADHOC;
1088                 else if (priv->bss_mode == NL80211_IFTYPE_STATION)
1089                         cmd_ptr->params.bss_mode.con_type =
1090                                 CONNECTION_TYPE_INFRA;
1091                 cmd_ptr->size = cpu_to_le16(sizeof(struct
1092                                 host_cmd_ds_set_bss_mode) + S_DS_GEN);
1093                 ret = 0;
1094                 break;
1095         default:
1096                 dev_err(priv->adapter->dev,
1097                         "PREP_CMD: unknown cmd- %#x\n", cmd_no);
1098                 ret = -1;
1099                 break;
1100         }
1101         return ret;
1102 }
1103
1104 /*
1105  * This function issues commands to initialize firmware.
1106  *
1107  * This is called after firmware download to bring the card to
1108  * working state.
1109  *
1110  * The following commands are issued sequentially -
1111  *      - Function init (for first interface only)
1112  *      - Read MAC address (for first interface only)
1113  *      - Reconfigure Tx buffer size (for first interface only)
1114  *      - Enable auto deep sleep (for first interface only)
1115  *      - Get Tx rate
1116  *      - Get Tx power
1117  *      - Set IBSS coalescing status
1118  *      - Set AMSDU aggregation control
1119  *      - Set 11d control
1120  *      - Set MAC control (this must be the last command to initialize firmware)
1121  */
1122 int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
1123 {
1124         int ret = 0;
1125         u16 enable = true;
1126         struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
1127         struct mwifiex_ds_auto_ds auto_ds;
1128         enum state_11d_t state_11d;
1129
1130         if (first_sta) {
1131
1132                 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
1133                                              HostCmd_ACT_GEN_SET, 0, NULL);
1134                 if (ret)
1135                         return -1;
1136                 /* Read MAC address from HW */
1137                 ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC,
1138                                              HostCmd_ACT_GEN_GET, 0, NULL);
1139                 if (ret)
1140                         return -1;
1141
1142                 /* Reconfigure tx buf size */
1143                 ret = mwifiex_send_cmd_async(priv,
1144                                              HostCmd_CMD_RECONFIGURE_TX_BUFF,
1145                                              HostCmd_ACT_GEN_SET, 0,
1146                                              &priv->adapter->tx_buf_size);
1147                 if (ret)
1148                         return -1;
1149
1150                 /* Enable IEEE PS by default */
1151                 priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
1152                 ret = mwifiex_send_cmd_async(priv,
1153                                              HostCmd_CMD_802_11_PS_MODE_ENH,
1154                                              EN_AUTO_PS, BITMAP_STA_PS, NULL);
1155                 if (ret)
1156                         return -1;
1157         }
1158
1159         /* get tx rate */
1160         ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG,
1161                                      HostCmd_ACT_GEN_GET, 0, NULL);
1162         if (ret)
1163                 return -1;
1164         priv->data_rate = 0;
1165
1166         /* get tx power */
1167         ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG,
1168                                      HostCmd_ACT_GEN_GET, 0, NULL);
1169         if (ret)
1170                 return -1;
1171
1172         /* set ibss coalescing_status */
1173         ret = mwifiex_send_cmd_async(priv,
1174                                      HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
1175                                      HostCmd_ACT_GEN_SET, 0, &enable);
1176         if (ret)
1177                 return -1;
1178
1179         memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
1180         amsdu_aggr_ctrl.enable = true;
1181         /* Send request to firmware */
1182         ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
1183                                      HostCmd_ACT_GEN_SET, 0,
1184                                      (void *) &amsdu_aggr_ctrl);
1185         if (ret)
1186                 return -1;
1187         /* MAC Control must be the last command in init_fw */
1188         /* set MAC Control */
1189         ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
1190                                      HostCmd_ACT_GEN_SET, 0,
1191                                      &priv->curr_pkt_filter);
1192         if (ret)
1193                 return -1;
1194
1195         if (first_sta) {
1196                 /* Enable auto deep sleep */
1197                 auto_ds.auto_ds = DEEP_SLEEP_ON;
1198                 auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
1199                 ret = mwifiex_send_cmd_async(priv,
1200                                              HostCmd_CMD_802_11_PS_MODE_ENH,
1201                                              EN_AUTO_PS, BITMAP_AUTO_DS,
1202                                              &auto_ds);
1203                 if (ret)
1204                         return -1;
1205         }
1206
1207         /* Send cmd to FW to enable/disable 11D function */
1208         state_11d = ENABLE_11D;
1209         ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
1210                                      HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
1211         if (ret)
1212                 dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
1213
1214         /* set last_init_cmd */
1215         priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB;
1216         ret = -EINPROGRESS;
1217
1218         return ret;
1219 }