Linux Audio

Check our new training course

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