sta_cmdresp.c 29 KB

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