Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Marvell Wireless LAN device driver: station command response 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/*
 30 * This function handles the command response error case.
 31 *
 32 * For scan response error, the function cancels all the pending
 33 * scan commands and generates an event to inform the applications
 34 * of the scan completion.
 35 *
 36 * For Power Save command failure, we do not retry enter PS
 37 * command in case of Ad-hoc mode.
 38 *
 39 * For all other response errors, the current command buffer is freed
 40 * and returned to the free command queue.
 41 */
 42static void
 43mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
 44			      struct host_cmd_ds_command *resp)
 45{
 46	struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
 47	struct mwifiex_adapter *adapter = priv->adapter;
 48	struct host_cmd_ds_802_11_ps_mode_enh *pm;
 49	unsigned long flags;
 50
 51	dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
 52			resp->command, resp->result);
 53
 54	if (adapter->curr_cmd->wait_q_enabled)
 55		adapter->cmd_wait_q.status = -1;
 56
 57	switch (le16_to_cpu(resp->command)) {
 58	case HostCmd_CMD_802_11_PS_MODE_ENH:
 59		pm = &resp->params.psmode_enh;
 60		dev_err(adapter->dev, "PS_MODE_ENH cmd failed: "
 61					"result=0x%x action=0x%X\n",
 62				resp->result, le16_to_cpu(pm->action));
 63		/* We do not re-try enter-ps command in ad-hoc mode. */
 64		if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
 65			(le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
 66				priv->bss_mode == NL80211_IFTYPE_ADHOC)
 67			adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
 68
 69		break;
 70	case HostCmd_CMD_802_11_SCAN:
 71		/* Cancel all pending scan command */
 72		spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
 73		list_for_each_entry_safe(cmd_node, tmp_node,
 74					 &adapter->scan_pending_q, list) {
 75			list_del(&cmd_node->list);
 76			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
 77					       flags);
 78			mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
 79			spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
 80		}
 81		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
 82
 83		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
 84		adapter->scan_processing = false;
 85		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 86		if (priv->report_scan_result)
 87			priv->report_scan_result = false;
 88		if (priv->scan_pending_on_block) {
 89			priv->scan_pending_on_block = false;
 90			up(&priv->async_sem);
 91		}
 92		break;
 93
 94	case HostCmd_CMD_MAC_CONTROL:
 95		break;
 96
 97	default:
 98		break;
 99	}
100	/* Handling errors here */
101	mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
102
103	spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
104	adapter->curr_cmd = NULL;
105	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
106}
107
108/*
109 * This function handles the command response of get RSSI info.
110 *
111 * Handling includes changing the header fields into CPU format
112 * and saving the following parameters in driver -
113 *      - Last data and beacon RSSI value
114 *      - Average data and beacon RSSI value
115 *      - Last data and beacon NF value
116 *      - Average data and beacon NF value
117 *
118 * The parameters are send to the application as well, along with
119 * calculated SNR values.
120 */
121static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
122					struct host_cmd_ds_command *resp,
123					struct mwifiex_ds_get_signal *signal)
124{
125	struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
126		&resp->params.rssi_info_rsp;
127
128	priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
129	priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
130
131	priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
132	priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
133
134	priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
135	priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
136
137	priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
138	priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
139
140	/* Need to indicate IOCTL complete */
141	if (signal) {
142		memset(signal, 0, sizeof(*signal));
143
144		signal->selector = ALL_RSSI_INFO_MASK;
145
146		/* RSSI */
147		signal->bcn_rssi_last = priv->bcn_rssi_last;
148		signal->bcn_rssi_avg = priv->bcn_rssi_avg;
149		signal->data_rssi_last = priv->data_rssi_last;
150		signal->data_rssi_avg = priv->data_rssi_avg;
151
152		/* SNR */
153		signal->bcn_snr_last =
154			CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
155		signal->bcn_snr_avg =
156			CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
157		signal->data_snr_last =
158			CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
159		signal->data_snr_avg =
160			CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
161
162		/* NF */
163		signal->bcn_nf_last = priv->bcn_nf_last;
164		signal->bcn_nf_avg = priv->bcn_nf_avg;
165		signal->data_nf_last = priv->data_nf_last;
166		signal->data_nf_avg = priv->data_nf_avg;
167	}
168
169	return 0;
170}
171
172/*
173 * This function handles the command response of set/get SNMP
174 * MIB parameters.
175 *
176 * Handling includes changing the header fields into CPU format
177 * and saving the parameter in driver.
178 *
179 * The following parameters are supported -
180 *      - Fragmentation threshold
181 *      - RTS threshold
182 *      - Short retry limit
183 */
184static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
185				       struct host_cmd_ds_command *resp,
186				       u32 *data_buf)
187{
188	struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
189	u16 oid = le16_to_cpu(smib->oid);
190	u16 query_type = le16_to_cpu(smib->query_type);
191	u32 ul_temp;
192
193	dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
194			" query_type = %#x, buf size = %#x\n",
195			oid, query_type, le16_to_cpu(smib->buf_size));
196	if (query_type == HostCmd_ACT_GEN_GET) {
197		ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
198		if (data_buf)
199			*data_buf = ul_temp;
200		switch (oid) {
201		case FRAG_THRESH_I:
202			dev_dbg(priv->adapter->dev,
203				"info: SNMP_RESP: FragThsd =%u\n", ul_temp);
204			break;
205		case RTS_THRESH_I:
206			dev_dbg(priv->adapter->dev,
207				"info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
208			break;
209		case SHORT_RETRY_LIM_I:
210			dev_dbg(priv->adapter->dev,
211				"info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
212			break;
213		default:
214			break;
215		}
216	}
217
218	return 0;
219}
220
221/*
222 * This function handles the command response of get log request
223 *
224 * Handling includes changing the header fields into CPU format
225 * and sending the received parameters to application.
226 */
227static int mwifiex_ret_get_log(struct mwifiex_private *priv,
228			       struct host_cmd_ds_command *resp,
229			       struct mwifiex_ds_get_stats *stats)
230{
231	struct host_cmd_ds_802_11_get_log *get_log =
232		(struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
233
234	if (stats) {
235		stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
236		stats->failed = le32_to_cpu(get_log->failed);
237		stats->retry = le32_to_cpu(get_log->retry);
238		stats->multi_retry = le32_to_cpu(get_log->multi_retry);
239		stats->frame_dup = le32_to_cpu(get_log->frame_dup);
240		stats->rts_success = le32_to_cpu(get_log->rts_success);
241		stats->rts_failure = le32_to_cpu(get_log->rts_failure);
242		stats->ack_failure = le32_to_cpu(get_log->ack_failure);
243		stats->rx_frag = le32_to_cpu(get_log->rx_frag);
244		stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
245		stats->fcs_error = le32_to_cpu(get_log->fcs_error);
246		stats->tx_frame = le32_to_cpu(get_log->tx_frame);
247		stats->wep_icv_error[0] =
248			le32_to_cpu(get_log->wep_icv_err_cnt[0]);
249		stats->wep_icv_error[1] =
250			le32_to_cpu(get_log->wep_icv_err_cnt[1]);
251		stats->wep_icv_error[2] =
252			le32_to_cpu(get_log->wep_icv_err_cnt[2]);
253		stats->wep_icv_error[3] =
254			le32_to_cpu(get_log->wep_icv_err_cnt[3]);
255	}
256
257	return 0;
258}
259
260/*
261 * This function handles the command response of set/get Tx rate
262 * configurations.
263 *
264 * Handling includes changing the header fields into CPU format
265 * and saving the following parameters in driver -
266 *      - DSSS rate bitmap
267 *      - OFDM rate bitmap
268 *      - HT MCS rate bitmaps
269 *
270 * Based on the new rate bitmaps, the function re-evaluates if
271 * auto data rate has been activated. If not, it sends another
272 * query to the firmware to get the current Tx data rate and updates
273 * the driver value.
274 */
275static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
276				   struct host_cmd_ds_command *resp,
277				   struct mwifiex_rate_cfg *ds_rate)
278{
279	struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
280	struct mwifiex_rate_scope *rate_scope;
281	struct mwifiex_ie_types_header *head;
282	u16 tlv, tlv_buf_len;
283	u8 *tlv_buf;
284	u32 i;
285	int ret = 0;
286
287	tlv_buf = (u8 *) ((u8 *) rate_cfg) +
288			sizeof(struct host_cmd_ds_tx_rate_cfg);
289	tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
290
291	while (tlv_buf && tlv_buf_len > 0) {
292		tlv = (*tlv_buf);
293		tlv = tlv | (*(tlv_buf + 1) << 8);
294
295		switch (tlv) {
296		case TLV_TYPE_RATE_SCOPE:
297			rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
298			priv->bitmap_rates[0] =
299				le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
300			priv->bitmap_rates[1] =
301				le16_to_cpu(rate_scope->ofdm_rate_bitmap);
302			for (i = 0;
303			     i <
304			     sizeof(rate_scope->ht_mcs_rate_bitmap) /
305			     sizeof(u16); i++)
306				priv->bitmap_rates[2 + i] =
307					le16_to_cpu(rate_scope->
308						    ht_mcs_rate_bitmap[i]);
309			break;
310			/* Add RATE_DROP tlv here */
311		}
312
313		head = (struct mwifiex_ie_types_header *) tlv_buf;
314		tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
315		tlv_buf_len -= le16_to_cpu(head->len);
316	}
317
318	priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
319
320	if (priv->is_data_rate_auto)
321		priv->data_rate = 0;
322	else
323		ret = mwifiex_send_cmd_async(priv,
324					  HostCmd_CMD_802_11_TX_RATE_QUERY,
325					  HostCmd_ACT_GEN_GET, 0, NULL);
326
327	if (ds_rate) {
328		if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) {
329			if (priv->is_data_rate_auto) {
330				ds_rate->is_rate_auto = 1;
331			} else {
332				ds_rate->rate = mwifiex_get_rate_index(priv->
333							       bitmap_rates,
334							       sizeof(priv->
335							       bitmap_rates));
336				if (ds_rate->rate >=
337				    MWIFIEX_RATE_BITMAP_OFDM0
338				    && ds_rate->rate <=
339				    MWIFIEX_RATE_BITMAP_OFDM7)
340					ds_rate->rate -=
341						(MWIFIEX_RATE_BITMAP_OFDM0 -
342						 MWIFIEX_RATE_INDEX_OFDM0);
343				if (ds_rate->rate >=
344				    MWIFIEX_RATE_BITMAP_MCS0
345				    && ds_rate->rate <=
346				    MWIFIEX_RATE_BITMAP_MCS127)
347					ds_rate->rate -=
348						(MWIFIEX_RATE_BITMAP_MCS0 -
349						 MWIFIEX_RATE_INDEX_MCS0);
350			}
351		}
352	}
353
354	return ret;
355}
356
357/*
358 * This function handles the command response of get Tx power level.
359 *
360 * Handling includes saving the maximum and minimum Tx power levels
361 * in driver, as well as sending the values to user.
362 */
363static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
364{
365	int length, max_power = -1, min_power = -1;
366	struct mwifiex_types_power_group *pg_tlv_hdr;
367	struct mwifiex_power_group *pg;
368
369	if (data_buf) {
370		pg_tlv_hdr =
371			(struct mwifiex_types_power_group *) ((u8 *) data_buf
372					+ sizeof(struct host_cmd_ds_txpwr_cfg));
373		pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr +
374				sizeof(struct mwifiex_types_power_group));
375		length = pg_tlv_hdr->length;
376		if (length > 0) {
377			max_power = pg->power_max;
378			min_power = pg->power_min;
379			length -= sizeof(struct mwifiex_power_group);
380		}
381		while (length) {
382			pg++;
383			if (max_power < pg->power_max)
384				max_power = pg->power_max;
385
386			if (min_power > pg->power_min)
387				min_power = pg->power_min;
388
389			length -= sizeof(struct mwifiex_power_group);
390		}
391		if (pg_tlv_hdr->length > 0) {
392			priv->min_tx_power_level = (u8) min_power;
393			priv->max_tx_power_level = (u8) max_power;
394		}
395	} else {
396		return -1;
397	}
398
399	return 0;
400}
401
402/*
403 * This function handles the command response of set/get Tx power
404 * configurations.
405 *
406 * Handling includes changing the header fields into CPU format
407 * and saving the current Tx power level in driver.
408 */
409static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
410				    struct host_cmd_ds_command *resp)
411{
412	struct mwifiex_adapter *adapter = priv->adapter;
413	struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
414	struct mwifiex_types_power_group *pg_tlv_hdr;
415	struct mwifiex_power_group *pg;
416	u16 action = le16_to_cpu(txp_cfg->action);
417
418	switch (action) {
419	case HostCmd_ACT_GEN_GET:
420		{
421			pg_tlv_hdr =
422				(struct mwifiex_types_power_group *) ((u8 *)
423						txp_cfg +
424						sizeof
425						(struct
426						 host_cmd_ds_txpwr_cfg));
427			pg = (struct mwifiex_power_group *) ((u8 *)
428						pg_tlv_hdr +
429						sizeof(struct
430						mwifiex_types_power_group));
431			if (adapter->hw_status ==
432			    MWIFIEX_HW_STATUS_INITIALIZING)
433				mwifiex_get_power_level(priv, txp_cfg);
434			priv->tx_power_level = (u16) pg->power_min;
435			break;
436		}
437	case HostCmd_ACT_GEN_SET:
438		if (le32_to_cpu(txp_cfg->mode)) {
439			pg_tlv_hdr =
440				(struct mwifiex_types_power_group *) ((u8 *)
441						txp_cfg +
442						sizeof
443						(struct
444						 host_cmd_ds_txpwr_cfg));
445			pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr
446						+
447						sizeof(struct
448						mwifiex_types_power_group));
449			if (pg->power_max == pg->power_min)
450				priv->tx_power_level = (u16) pg->power_min;
451		}
452		break;
453	default:
454		dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
455				action);
456		return 0;
457	}
458	dev_dbg(adapter->dev,
459		"info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
460	       priv->tx_power_level, priv->max_tx_power_level,
461	       priv->min_tx_power_level);
462
463	return 0;
464}
465
466/*
467 * This function handles the command response of set/get MAC address.
468 *
469 * Handling includes saving the MAC address in driver.
470 */
471static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
472					  struct host_cmd_ds_command *resp)
473{
474	struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
475		&resp->params.mac_addr;
476
477	memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
478
479	dev_dbg(priv->adapter->dev,
480		"info: set mac address: %pM\n", priv->curr_addr);
481
482	return 0;
483}
484
485/*
486 * This function handles the command response of set/get MAC multicast
487 * address.
488 */
489static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
490					 struct host_cmd_ds_command *resp)
491{
492	return 0;
493}
494
495/*
496 * This function handles the command response of get Tx rate query.
497 *
498 * Handling includes changing the header fields into CPU format
499 * and saving the Tx rate and HT information parameters in driver.
500 *
501 * Both rate configuration and current data rate can be retrieved
502 * with this request.
503 */
504static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
505					    struct host_cmd_ds_command *resp)
506{
507	priv->tx_rate = resp->params.tx_rate.tx_rate;
508	priv->tx_htinfo = resp->params.tx_rate.ht_info;
509	if (!priv->is_data_rate_auto)
510		priv->data_rate =
511			mwifiex_index_to_data_rate(priv->tx_rate,
512						   priv->tx_htinfo);
513
514	return 0;
515}
516
517/*
518 * This function handles the command response of a deauthenticate
519 * command.
520 *
521 * If the deauthenticated MAC matches the current BSS MAC, the connection
522 * state is reset.
523 */
524static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
525					     struct host_cmd_ds_command *resp)
526{
527	struct mwifiex_adapter *adapter = priv->adapter;
528
529	adapter->dbg.num_cmd_deauth++;
530	if (!memcmp(resp->params.deauth.mac_addr,
531		    &priv->curr_bss_params.bss_descriptor.mac_address,
532		    sizeof(resp->params.deauth.mac_addr)))
533		mwifiex_reset_connect_state(priv);
534
535	return 0;
536}
537
538/*
539 * This function handles the command response of ad-hoc stop.
540 *
541 * The function resets the connection state in driver.
542 */
543static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
544					  struct host_cmd_ds_command *resp)
545{
546	mwifiex_reset_connect_state(priv);
547	return 0;
548}
549
550/*
551 * This function handles the command response of set/get key material.
552 *
553 * Handling includes updating the driver parameters to reflect the
554 * changes.
555 */
556static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
557					   struct host_cmd_ds_command *resp)
558{
559	struct host_cmd_ds_802_11_key_material *key =
560		&resp->params.key_material;
561
562	if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
563		if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
564			dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
565			priv->wpa_is_gtk_set = true;
566			priv->scan_block = false;
567		}
568	}
569
570	memset(priv->aes_key.key_param_set.key, 0,
571	       sizeof(key->key_param_set.key));
572	priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
573	memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
574	       le16_to_cpu(priv->aes_key.key_param_set.key_len));
575
576	return 0;
577}
578
579/*
580 * This function handles the command response of get 11d domain information.
581 */
582static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
583					   struct host_cmd_ds_command *resp)
584{
585	struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
586		&resp->params.domain_info_resp;
587	struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
588	u16 action = le16_to_cpu(domain_info->action);
589	u8 no_of_triplet;
590
591	no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
592					IEEE80211_COUNTRY_STRING_LEN) /
593				sizeof(struct ieee80211_country_ie_triplet));
594
595	dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
596			" no_of_triplet=%d\n", no_of_triplet);
597
598	if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
599		dev_warn(priv->adapter->dev,
600			"11D: invalid number of triplets %d "
601			"returned!!\n", no_of_triplet);
602		return -1;
603	}
604
605	switch (action) {
606	case HostCmd_ACT_GEN_SET:  /* Proc Set Action */
607		break;
608	case HostCmd_ACT_GEN_GET:
609		break;
610	default:
611		dev_err(priv->adapter->dev,
612			"11D: invalid action:%d\n", domain_info->action);
613		return -1;
614	}
615
616	return 0;
617}
618
619/*
620 * This function handles the command response of get RF channel.
621 *
622 * Handling includes changing the header fields into CPU format
623 * and saving the new channel in driver.
624 */
625static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
626					 struct host_cmd_ds_command *resp,
627					 u16 *data_buf)
628{
629	struct host_cmd_ds_802_11_rf_channel *rf_channel =
630		&resp->params.rf_channel;
631	u16 new_channel = le16_to_cpu(rf_channel->current_channel);
632
633	if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
634		dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
635		       priv->curr_bss_params.bss_descriptor.channel,
636		       new_channel);
637		/* Update the channel again */
638		priv->curr_bss_params.bss_descriptor.channel = new_channel;
639	}
640
641	if (data_buf)
642		*data_buf = new_channel;
643
644	return 0;
645}
646
647/*
648 * This function handles the command response of get extended version.
649 *
650 * Handling includes forming the extended version string and sending it
651 * to application.
652 */
653static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
654			       struct host_cmd_ds_command *resp,
655			       struct host_cmd_ds_version_ext *version_ext)
656{
657	struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
658
659	if (version_ext) {
660		version_ext->version_str_sel = ver_ext->version_str_sel;
661		memcpy(version_ext->version_str, ver_ext->version_str,
662		       sizeof(char) * 128);
663		memcpy(priv->version_str, ver_ext->version_str, 128);
664	}
665	return 0;
666}
667
668/*
669 * This function handles the command response of register access.
670 *
671 * The register value and offset are returned to the user. For EEPROM
672 * access, the byte count is also returned.
673 */
674static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
675				  void *data_buf)
676{
677	struct mwifiex_ds_reg_rw *reg_rw;
678	struct mwifiex_ds_read_eeprom *eeprom;
679
680	if (data_buf) {
681		reg_rw = data_buf;
682		eeprom = data_buf;
683		switch (type) {
684		case HostCmd_CMD_MAC_REG_ACCESS:
685			{
686				struct host_cmd_ds_mac_reg_access *reg;
687				reg = (struct host_cmd_ds_mac_reg_access *)
688					&resp->params.mac_reg;
689				reg_rw->offset = cpu_to_le32(
690					(u32) le16_to_cpu(reg->offset));
691				reg_rw->value = reg->value;
692				break;
693			}
694		case HostCmd_CMD_BBP_REG_ACCESS:
695			{
696				struct host_cmd_ds_bbp_reg_access *reg;
697				reg = (struct host_cmd_ds_bbp_reg_access *)
698					&resp->params.bbp_reg;
699				reg_rw->offset = cpu_to_le32(
700					(u32) le16_to_cpu(reg->offset));
701				reg_rw->value = cpu_to_le32((u32) reg->value);
702				break;
703			}
704
705		case HostCmd_CMD_RF_REG_ACCESS:
706			{
707				struct host_cmd_ds_rf_reg_access *reg;
708				reg = (struct host_cmd_ds_rf_reg_access *)
709					&resp->params.rf_reg;
710				reg_rw->offset = cpu_to_le32(
711					(u32) le16_to_cpu(reg->offset));
712				reg_rw->value = cpu_to_le32((u32) reg->value);
713				break;
714			}
715		case HostCmd_CMD_PMIC_REG_ACCESS:
716			{
717				struct host_cmd_ds_pmic_reg_access *reg;
718				reg = (struct host_cmd_ds_pmic_reg_access *)
719					&resp->params.pmic_reg;
720				reg_rw->offset = cpu_to_le32(
721					(u32) le16_to_cpu(reg->offset));
722				reg_rw->value = cpu_to_le32((u32) reg->value);
723				break;
724			}
725		case HostCmd_CMD_CAU_REG_ACCESS:
726			{
727				struct host_cmd_ds_rf_reg_access *reg;
728				reg = (struct host_cmd_ds_rf_reg_access *)
729					&resp->params.rf_reg;
730				reg_rw->offset = cpu_to_le32(
731					(u32) le16_to_cpu(reg->offset));
732				reg_rw->value = cpu_to_le32((u32) reg->value);
733				break;
734			}
735		case HostCmd_CMD_802_11_EEPROM_ACCESS:
736			{
737				struct host_cmd_ds_802_11_eeprom_access
738					*cmd_eeprom =
739					(struct host_cmd_ds_802_11_eeprom_access
740					 *) &resp->params.eeprom;
741				pr_debug("info: EEPROM read len=%x\n",
742				       cmd_eeprom->byte_count);
743				if (le16_to_cpu(eeprom->byte_count) <
744						le16_to_cpu(
745						cmd_eeprom->byte_count)) {
746					eeprom->byte_count = cpu_to_le16(0);
747					pr_debug("info: EEPROM read "
748							"length is too big\n");
749					return -1;
750				}
751				eeprom->offset = cmd_eeprom->offset;
752				eeprom->byte_count = cmd_eeprom->byte_count;
753				if (le16_to_cpu(eeprom->byte_count) > 0)
754					memcpy(&eeprom->value,
755					       &cmd_eeprom->value,
756					       le16_to_cpu(eeprom->byte_count));
757
758				break;
759			}
760		default:
761			return -1;
762		}
763	}
764	return 0;
765}
766
767/*
768 * This function handles the command response of get IBSS coalescing status.
769 *
770 * If the received BSSID is different than the current one, the current BSSID,
771 * beacon interval, ATIM window and ERP information are updated, along with
772 * changing the ad-hoc state accordingly.
773 */
774static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
775					      struct host_cmd_ds_command *resp)
776{
777	struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
778		&(resp->params.ibss_coalescing);
779	u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
780
781	if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
782		return 0;
783
784	dev_dbg(priv->adapter->dev,
785		"info: new BSSID %pM\n", ibss_coal_resp->bssid);
786
787	/* If rsp has NULL BSSID, Just return..... No Action */
788	if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
789		dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
790		return 0;
791	}
792
793	/* If BSSID is diff, modify current BSS parameters */
794	if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
795		   ibss_coal_resp->bssid, ETH_ALEN)) {
796		/* BSSID */
797		memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
798		       ibss_coal_resp->bssid, ETH_ALEN);
799
800		/* Beacon Interval */
801		priv->curr_bss_params.bss_descriptor.beacon_period
802			= le16_to_cpu(ibss_coal_resp->beacon_interval);
803
804		/* ERP Information */
805		priv->curr_bss_params.bss_descriptor.erp_flags =
806			(u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
807
808		priv->adhoc_state = ADHOC_COALESCED;
809	}
810
811	return 0;
812}
813
814/*
815 * This function handles the command responses.
816 *
817 * This is a generic function, which calls command specific
818 * response handlers based on the command ID.
819 */
820int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
821				struct host_cmd_ds_command *resp)
822{
823	int ret = 0;
824	struct mwifiex_adapter *adapter = priv->adapter;
825	void *data_buf = adapter->curr_cmd->data_buf;
826
827	/* If the command is not successful, cleanup and return failure */
828	if (resp->result != HostCmd_RESULT_OK) {
829		mwifiex_process_cmdresp_error(priv, resp);
830		return -1;
831	}
832	/* Command successful, handle response */
833	switch (cmdresp_no) {
834	case HostCmd_CMD_GET_HW_SPEC:
835		ret = mwifiex_ret_get_hw_spec(priv, resp);
836		break;
837	case HostCmd_CMD_MAC_CONTROL:
838		break;
839	case HostCmd_CMD_802_11_MAC_ADDRESS:
840		ret = mwifiex_ret_802_11_mac_address(priv, resp);
841		break;
842	case HostCmd_CMD_MAC_MULTICAST_ADR:
843		ret = mwifiex_ret_mac_multicast_adr(priv, resp);
844		break;
845	case HostCmd_CMD_TX_RATE_CFG:
846		ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
847		break;
848	case HostCmd_CMD_802_11_SCAN:
849		ret = mwifiex_ret_802_11_scan(priv, resp);
850		adapter->curr_cmd->wait_q_enabled = false;
851		break;
852	case HostCmd_CMD_802_11_BG_SCAN_QUERY:
853		ret = mwifiex_ret_802_11_scan(priv, resp);
854		dev_dbg(adapter->dev,
855			"info: CMD_RESP: BG_SCAN result is ready!\n");
856		break;
857	case HostCmd_CMD_TXPWR_CFG:
858		ret = mwifiex_ret_tx_power_cfg(priv, resp);
859		break;
860	case HostCmd_CMD_802_11_PS_MODE_ENH:
861		ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
862		break;
863	case HostCmd_CMD_802_11_HS_CFG_ENH:
864		ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
865		break;
866	case HostCmd_CMD_802_11_ASSOCIATE:
867		ret = mwifiex_ret_802_11_associate(priv, resp);
868		break;
869	case HostCmd_CMD_802_11_DEAUTHENTICATE:
870		ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
871		break;
872	case HostCmd_CMD_802_11_AD_HOC_START:
873	case HostCmd_CMD_802_11_AD_HOC_JOIN:
874		ret = mwifiex_ret_802_11_ad_hoc(priv, resp);
875		break;
876	case HostCmd_CMD_802_11_AD_HOC_STOP:
877		ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
878		break;
879	case HostCmd_CMD_802_11_GET_LOG:
880		ret = mwifiex_ret_get_log(priv, resp, data_buf);
881		break;
882	case HostCmd_CMD_RSSI_INFO:
883		ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
884		break;
885	case HostCmd_CMD_802_11_SNMP_MIB:
886		ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
887		break;
888	case HostCmd_CMD_802_11_TX_RATE_QUERY:
889		ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
890		break;
891	case HostCmd_CMD_802_11_RF_CHANNEL:
892		ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
893		break;
894	case HostCmd_CMD_VERSION_EXT:
895		ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
896		break;
897	case HostCmd_CMD_FUNC_INIT:
898	case HostCmd_CMD_FUNC_SHUTDOWN:
899		break;
900	case HostCmd_CMD_802_11_KEY_MATERIAL:
901		ret = mwifiex_ret_802_11_key_material(priv, resp);
902		break;
903	case HostCmd_CMD_802_11D_DOMAIN_INFO:
904		ret = mwifiex_ret_802_11d_domain_info(priv, resp);
905		break;
906	case HostCmd_CMD_11N_ADDBA_REQ:
907		ret = mwifiex_ret_11n_addba_req(priv, resp);
908		break;
909	case HostCmd_CMD_11N_DELBA:
910		ret = mwifiex_ret_11n_delba(priv, resp);
911		break;
912	case HostCmd_CMD_11N_ADDBA_RSP:
913		ret = mwifiex_ret_11n_addba_resp(priv, resp);
914		break;
915	case HostCmd_CMD_RECONFIGURE_TX_BUFF:
916		adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
917							     tx_buf.buff_size);
918		adapter->tx_buf_size = (adapter->tx_buf_size /
919						MWIFIEX_SDIO_BLOCK_SIZE) *
920						MWIFIEX_SDIO_BLOCK_SIZE;
921		adapter->curr_tx_buf_size = adapter->tx_buf_size;
922		dev_dbg(adapter->dev,
923			"cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
924		       adapter->max_tx_buf_size, adapter->tx_buf_size);
925
926		if (adapter->if_ops.update_mp_end_port)
927			adapter->if_ops.update_mp_end_port(adapter,
928					le16_to_cpu(resp->
929						params.
930						tx_buf.
931						mp_end_port));
932		break;
933	case HostCmd_CMD_AMSDU_AGGR_CTRL:
934		ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf);
935		break;
936	case HostCmd_CMD_WMM_GET_STATUS:
937		ret = mwifiex_ret_wmm_get_status(priv, resp);
938		break;
939	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
940		ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
941		break;
942	case HostCmd_CMD_MAC_REG_ACCESS:
943	case HostCmd_CMD_BBP_REG_ACCESS:
944	case HostCmd_CMD_RF_REG_ACCESS:
945	case HostCmd_CMD_PMIC_REG_ACCESS:
946	case HostCmd_CMD_CAU_REG_ACCESS:
947	case HostCmd_CMD_802_11_EEPROM_ACCESS:
948		ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
949		break;
950	case HostCmd_CMD_SET_BSS_MODE:
951		break;
952	case HostCmd_CMD_11N_CFG:
953		ret = mwifiex_ret_11n_cfg(resp, data_buf);
954		break;
955	default:
956		dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
957		       resp->command);
958		break;
959	}
960
961	return ret;
962}