blob: fd887da84239ef418d51a917760325ab6b887cce [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wma_mgmt.c
30 *
31 * This file contains STA/SAP/IBSS and protocol related functions.
32 */
33
34/* Header files */
35
36#include "wma.h"
37#include "wma_api.h"
38#include "cds_api.h"
39#include "wmi_unified_api.h"
40#include "wlan_qct_sys.h"
41#include "wni_api.h"
42#include "ani_global.h"
43#include "wmi_unified.h"
44#include "wni_cfg.h"
45#include "cfg_api.h"
46#include "ol_txrx_ctrl_api.h"
47#include "wlan_tgt_def_config.h"
48
49#include "cdf_nbuf.h"
50#include "cdf_types.h"
51#include "ol_txrx_api.h"
52#include "cdf_memory.h"
53#include "ol_txrx_types.h"
54#include "ol_txrx_peer_find.h"
55
56#include "wma_types.h"
57#include "lim_api.h"
58#include "lim_session_utils.h"
59
60#include "cds_utils.h"
61
62#if !defined(REMOVE_PKT_LOG)
63#include "pktlog_ac.h"
64#endif /* REMOVE_PKT_LOG */
65
66#include "dbglog_host.h"
67#include "csr_api.h"
68#include "ol_fw.h"
69#include "dfs.h"
70#include "wma_internal.h"
Chandrasekaran, Manishekar0d814c72015-11-05 10:42:48 +053071#include "cds_concurrency.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080072
73/**
74 * wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL
75 * @wma: wma handle
76 * @pdev: txrx pdev
77 * @vdev_id: vdev id
78 * @param_buf: SWBA parameters
79 *
80 * Return: none
81 */
82static void wma_send_bcn_buf_ll(tp_wma_handle wma,
83 ol_txrx_pdev_handle pdev,
84 uint8_t vdev_id,
85 WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf)
86{
87 wmi_bcn_send_from_host_cmd_fixed_param *cmd;
88 struct ieee80211_frame *wh;
89 struct beacon_info *bcn;
90 wmi_tim_info *tim_info = param_buf->tim_info;
91 uint8_t *bcn_payload;
92 wmi_buf_t wmi_buf;
93 CDF_STATUS ret;
94 struct beacon_tim_ie *tim_ie;
95 wmi_p2p_noa_info *p2p_noa_info = param_buf->p2p_noa_info;
96 struct p2p_sub_element_noa noa_ie;
97 uint8_t i;
98 int status;
99
100 bcn = wma->interfaces[vdev_id].beacon;
101 if (!bcn->buf) {
102 WMA_LOGE("%s: Invalid beacon buffer", __func__);
103 return;
104 }
105
106 wmi_buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd));
107 if (!wmi_buf) {
108 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
109 return;
110 }
111
112 cdf_spin_lock_bh(&bcn->lock);
113
114 bcn_payload = cdf_nbuf_data(bcn->buf);
115
116 tim_ie = (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]);
117
118 if (tim_info->tim_changed) {
119 if (tim_info->tim_num_ps_pending)
120 cdf_mem_copy(&tim_ie->tim_bitmap, tim_info->tim_bitmap,
121 WMA_TIM_SUPPORTED_PVB_LENGTH);
122 else
123 cdf_mem_zero(&tim_ie->tim_bitmap,
124 WMA_TIM_SUPPORTED_PVB_LENGTH);
125 /*
126 * Currently we support fixed number of
127 * peers as limited by HAL_NUM_STA.
128 * tim offset is always 0
129 */
130 tim_ie->tim_bitctl = 0;
131 }
132
133 /* Update DTIM Count */
134 if (tim_ie->dtim_count == 0)
135 tim_ie->dtim_count = tim_ie->dtim_period - 1;
136 else
137 tim_ie->dtim_count--;
138
139 /*
140 * DTIM count needs to be backedup so that
141 * when umac updates the beacon template
142 * current dtim count can be updated properly
143 */
144 bcn->dtim_count = tim_ie->dtim_count;
145
146 /* update state for buffered multicast frames on DTIM */
147 if (tim_info->tim_mcast && (tim_ie->dtim_count == 0 ||
148 tim_ie->dtim_period == 1))
149 tim_ie->tim_bitctl |= 1;
150 else
151 tim_ie->tim_bitctl &= ~1;
152
153 /* To avoid sw generated frame sequence the same as H/W generated frame,
154 * the value lower than min_sw_seq is reserved for HW generated frame */
155 if ((bcn->seq_no & IEEE80211_SEQ_MASK) < MIN_SW_SEQ)
156 bcn->seq_no = MIN_SW_SEQ;
157
158 wh = (struct ieee80211_frame *)bcn_payload;
159 *(uint16_t *) &wh->i_seq[0] = htole16(bcn->seq_no
160 << IEEE80211_SEQ_SEQ_SHIFT);
161 bcn->seq_no++;
162
163 if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) {
164 cdf_mem_zero(&noa_ie, sizeof(noa_ie));
165
166 noa_ie.index =
167 (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info);
168 noa_ie.oppPS =
169 (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info);
170 noa_ie.ctwindow =
171 (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info);
172 noa_ie.num_descriptors =
173 (uint8_t) WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info);
174 WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, "
175 "num_descriptors = %u", __func__, noa_ie.index,
176 noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors);
177 for (i = 0; i < noa_ie.num_descriptors; i++) {
178 noa_ie.noa_descriptors[i].type_count =
179 (uint8_t) p2p_noa_info->noa_descriptors[i].
180 type_count;
181 noa_ie.noa_descriptors[i].duration =
182 p2p_noa_info->noa_descriptors[i].duration;
183 noa_ie.noa_descriptors[i].interval =
184 p2p_noa_info->noa_descriptors[i].interval;
185 noa_ie.noa_descriptors[i].start_time =
186 p2p_noa_info->noa_descriptors[i].start_time;
187 WMA_LOGI("%s: NoA descriptor[%d] type_count %u, "
188 "duration %u, interval %u, start_time = %u",
189 __func__, i,
190 noa_ie.noa_descriptors[i].type_count,
191 noa_ie.noa_descriptors[i].duration,
192 noa_ie.noa_descriptors[i].interval,
193 noa_ie.noa_descriptors[i].start_time);
194 }
195 wma_update_noa(bcn, &noa_ie);
196
197 /* Send a msg to LIM to update the NoA IE in probe response
198 * frames transmitted by the host */
199 wma_update_probe_resp_noa(wma, &noa_ie);
200 }
201
202 if (bcn->dma_mapped) {
203 cdf_nbuf_unmap_single(pdev->osdev, bcn->buf, CDF_DMA_TO_DEVICE);
204 bcn->dma_mapped = 0;
205 }
206 ret = cdf_nbuf_map_single(pdev->osdev, bcn->buf, CDF_DMA_TO_DEVICE);
207 if (ret != CDF_STATUS_SUCCESS) {
208 cdf_nbuf_free(wmi_buf);
209 WMA_LOGE("%s: failed map beacon buf to DMA region", __func__);
210 cdf_spin_unlock_bh(&bcn->lock);
211 return;
212 }
213
214 bcn->dma_mapped = 1;
215 cmd = (wmi_bcn_send_from_host_cmd_fixed_param *) wmi_buf_data(wmi_buf);
216 WMITLV_SET_HDR(&cmd->tlv_header,
217 WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param,
218 WMITLV_GET_STRUCT_TLVLEN
219 (wmi_bcn_send_from_host_cmd_fixed_param));
220 cmd->vdev_id = vdev_id;
221 cmd->data_len = bcn->len;
222 cmd->frame_ctrl = *((A_UINT16 *) wh->i_fc);
223 cmd->frag_ptr = cdf_nbuf_get_frag_paddr_lo(bcn->buf, 0);
224
225 /* notify Firmware of DTM and mcast/bcast traffic */
226 if (tim_ie->dtim_count == 0) {
227 cmd->dtim_flag |= WMI_BCN_SEND_DTIM_ZERO;
228 /* deliver mcast/bcast traffic in next DTIM beacon */
229 if (tim_ie->tim_bitctl & 0x01)
230 cmd->dtim_flag |= WMI_BCN_SEND_DTIM_BITCTL_SET;
231 }
232
233 status = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, sizeof(*cmd),
234 WMI_PDEV_SEND_BCN_CMDID);
235
236 if (status != EOK) {
237 WMA_LOGE("Failed to send WMI_PDEV_SEND_BCN_CMDID command");
238 wmi_buf_free(wmi_buf);
239 }
240 cdf_spin_unlock_bh(&bcn->lock);
241}
242
243/**
244 * wma_beacon_swba_handler() - swba event handler
245 * @handle: wma handle
246 * @event: event data
247 * @len: data length
248 *
249 * SWBA event is alert event to Host requesting host to Queue a beacon
250 * for transmission use only in host beacon mode
251 *
252 * Return: 0 for success or error code
253 */
254int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len)
255{
256 tp_wma_handle wma = (tp_wma_handle) handle;
257 WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf;
258 wmi_host_swba_event_fixed_param *swba_event;
259 uint32_t vdev_map;
260 ol_txrx_pdev_handle pdev;
261 uint8_t vdev_id = 0;
262
263 param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) event;
264 if (!param_buf) {
265 WMA_LOGE("Invalid swba event buffer");
266 return -EINVAL;
267 }
268 swba_event = param_buf->fixed_param;
269 vdev_map = swba_event->vdev_map;
270
271 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
272 if (!pdev) {
273 WMA_LOGE("%s: pdev is NULL", __func__);
274 return -EINVAL;
275 }
276
277 for (; vdev_map; vdev_id++, vdev_map >>= 1) {
278 if (!(vdev_map & 0x1))
279 continue;
280 if (!ol_cfg_is_high_latency(pdev->ctrl_pdev))
281 wma_send_bcn_buf_ll(wma, pdev, vdev_id, param_buf);
282 break;
283 }
284 return 0;
285}
286
287/**
288 * wma_peer_sta_kickout_event_handler() - kickout event handler
289 * @handle: wma handle
290 * @event: event data
291 * @len: data length
292 *
293 * Kickout event is received from firmware on observing beacon miss
294 * It handles kickout event for different modes and indicate to
295 * upper layers.
296 *
297 * Return: 0 for success or error code
298 */
299int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len)
300{
301 tp_wma_handle wma = (tp_wma_handle) handle;
302 WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL;
303 wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL;
304 uint8_t vdev_id, peer_id, macaddr[IEEE80211_ADDR_LEN];
305 ol_txrx_peer_handle peer;
306 ol_txrx_pdev_handle pdev;
307 tpDeleteStaContext del_sta_ctx;
308 tpSirIbssPeerInactivityInd p_inactivity;
309
310 WMA_LOGD("%s: Enter", __func__);
311 param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event;
312 kickout_event = param_buf->fixed_param;
313 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
314 if (!pdev) {
315 WMA_LOGE("%s: pdev is NULL", __func__);
316 return -EINVAL;
317 }
318 WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr);
319 peer = ol_txrx_find_peer_by_addr(pdev, macaddr, &peer_id);
320 if (!peer) {
321 WMA_LOGE("PEER [%pM] not found", macaddr);
322 return -EINVAL;
323 }
324
325 if (ol_txrx_get_vdevid(peer, &vdev_id) != CDF_STATUS_SUCCESS) {
326 WMA_LOGE("Not able to find BSSID for peer [%pM]", macaddr);
327 return -EINVAL;
328 }
329
330 WMA_LOGA("%s: PEER:[%pM], ADDR:[%pN], INTERFACE:%d, peer_id:%d, reason:%d",
331 __func__, macaddr, wma->interfaces[vdev_id].addr, vdev_id,
332 peer_id, kickout_event->reason);
333
334 switch (kickout_event->reason) {
335 case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT:
336 p_inactivity = (tpSirIbssPeerInactivityInd)
337 cdf_mem_malloc(sizeof(tSirIbssPeerInactivityInd));
338 if (!p_inactivity) {
339 WMA_LOGE("CDF MEM Alloc Failed for tSirIbssPeerInactivity");
340 return -ENOMEM;
341 }
342
343 p_inactivity->staIdx = peer_id;
344 cdf_mem_copy(p_inactivity->peerAddr, macaddr,
345 IEEE80211_ADDR_LEN);
346 wma_send_msg(wma, WMA_IBSS_PEER_INACTIVITY_IND,
347 (void *)p_inactivity, 0);
348 goto exit_handler;
349 break;
350
351#ifdef FEATURE_WLAN_TDLS
352 case WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT:
353 del_sta_ctx = (tpDeleteStaContext)
354 cdf_mem_malloc(sizeof(tDeleteStaContext));
355 if (!del_sta_ctx) {
356 WMA_LOGE("%s: mem alloc failed for tDeleteStaContext for TDLS peer: %pM",
357 __func__, macaddr);
358 return -ENOMEM;
359 }
360
361 del_sta_ctx->staId = peer_id;
362 cdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN);
363 cdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].bssid,
364 IEEE80211_ADDR_LEN);
365 del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE;
366 wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND,
367 (void *)del_sta_ctx, 0);
368 goto exit_handler;
369 break;
370#endif /* FEATURE_WLAN_TDLS */
371
372 case WMI_PEER_STA_KICKOUT_REASON_XRETRY:
373 if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA &&
374 (wma->interfaces[vdev_id].sub_type == 0 ||
375 wma->interfaces[vdev_id].sub_type ==
376 WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) &&
377 cdf_mem_compare(wma->interfaces[vdev_id].bssid,
378 macaddr, IEEE80211_ADDR_LEN)) {
379 /*
380 * KICKOUT event is for current station-AP connection.
381 * Treat it like final beacon miss. Station may not have
382 * missed beacons but not able to transmit frames to AP
383 * for a long time. Must disconnect to get out of
384 * this sticky situation.
385 * In future implementation, roaming module will also
386 * handle this event and perform a scan.
387 */
388 WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_XRETRY event for STA",
389 __func__);
390 wma_beacon_miss_handler(wma, vdev_id);
391 goto exit_handler;
392 }
393 break;
394
395 case WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED:
396 /*
397 * Default legacy value used by original firmware implementation.
398 */
399 if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA &&
400 (wma->interfaces[vdev_id].sub_type == 0 ||
401 wma->interfaces[vdev_id].sub_type ==
402 WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) &&
403 cdf_mem_compare(wma->interfaces[vdev_id].bssid,
404 macaddr, IEEE80211_ADDR_LEN)) {
405 /*
406 * KICKOUT event is for current station-AP connection.
407 * Treat it like final beacon miss. Station may not have
408 * missed beacons but not able to transmit frames to AP
409 * for a long time. Must disconnect to get out of
410 * this sticky situation.
411 * In future implementation, roaming module will also
412 * handle this event and perform a scan.
413 */
414 WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA",
415 __func__);
416 wma_beacon_miss_handler(wma, vdev_id);
417 goto exit_handler;
418 }
419 break;
420
421 case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY:
mukul sharma72c8b222015-09-04 17:02:01 +0530422 /* Handle SA query kickout is same as inactivity kickout */
423 case WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT:
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424 default:
425 break;
426 }
427
428 /*
429 * default action is to send delete station context indication to LIM
430 */
431 del_sta_ctx =
432 (tpDeleteStaContext) cdf_mem_malloc(sizeof(tDeleteStaContext));
433 if (!del_sta_ctx) {
434 WMA_LOGE("CDF MEM Alloc Failed for tDeleteStaContext");
435 return -ENOMEM;
436 }
437
438 del_sta_ctx->staId = peer_id;
439 cdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN);
440 cdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].addr,
441 IEEE80211_ADDR_LEN);
442 del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE;
Kiran Kumar Lokere37d3aa22015-11-03 14:58:26 -0800443 del_sta_ctx->rssi = kickout_event->rssi + WMA_TGT_NOISE_FLOOR_DBM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444 wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx,
445 0);
446
447exit_handler:
448 WMA_LOGD("%s: Exit", __func__);
449 return 0;
450}
451
452/**
453 * wma_unified_bcntx_status_event_handler() - beacon tx status event handler
454 * @handle: wma handle
455 * @cmd_param_info: event data
456 * @len: data length
457 *
458 * WMI Handler for WMI_OFFLOAD_BCN_TX_STATUS_EVENTID event from firmware.
459 * This event is generated by FW when the beacon transmission is offloaded
460 * and the host performs beacon template modification using WMI_BCN_TMPL_CMDID
461 * The FW generates this event when the first successful beacon transmission
462 * after template update
463 *
464 * Return: 0 for success or error code
465 */
466int wma_unified_bcntx_status_event_handler(void *handle,
467 uint8_t *cmd_param_info,
468 uint32_t len)
469{
470 tp_wma_handle wma = (tp_wma_handle) handle;
471 WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *param_buf;
472 wmi_offload_bcn_tx_status_event_fixed_param *resp_event;
473 tSirFirstBeaconTxCompleteInd *beacon_tx_complete_ind;
474
475 param_buf =
476 (WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *) cmd_param_info;
477 if (!param_buf) {
478 WMA_LOGE("Invalid bcn tx response event buffer");
479 return -EINVAL;
480 }
481
482 resp_event = param_buf->fixed_param;
483
484 /* Check for valid handle to ensure session is not
485 * deleted in any race
486 */
487 if (!wma->interfaces[resp_event->vdev_id].handle) {
488 WMA_LOGE("%s: The session does not exist", __func__);
489 return -EINVAL;
490 }
491
492 /* Beacon Tx Indication supports only AP mode. Ignore in other modes */
493 if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == false) {
494 WMA_LOGI("%s: Beacon Tx Indication does not support type %d and sub_type %d",
495 __func__, wma->interfaces[resp_event->vdev_id].type,
496 wma->interfaces[resp_event->vdev_id].sub_type);
497 return 0;
498 }
499
500 beacon_tx_complete_ind = (tSirFirstBeaconTxCompleteInd *)
501 cdf_mem_malloc(sizeof(tSirFirstBeaconTxCompleteInd));
502 if (!beacon_tx_complete_ind) {
503 WMA_LOGE("%s: Failed to alloc beacon_tx_complete_ind",
504 __func__);
505 return -ENOMEM;
506 }
507
508 beacon_tx_complete_ind->messageType = WMA_DFS_BEACON_TX_SUCCESS_IND;
509 beacon_tx_complete_ind->length = sizeof(tSirFirstBeaconTxCompleteInd);
510 beacon_tx_complete_ind->bssIdx = resp_event->vdev_id;
511
512 wma_send_msg(wma, WMA_DFS_BEACON_TX_SUCCESS_IND,
513 (void *)beacon_tx_complete_ind, 0);
514 return 0;
515}
516
517/**
518 * wma_get_link_probe_timeout() - get link timeout based on sub type
519 * @mac: UMAC handler
520 * @sub_type: vdev syb type
521 * @max_inactive_time: return max inactive time
522 * @max_unresponsive_time: return max unresponsive time
523 *
524 * Return: none
525 */
526static inline void wma_get_link_probe_timeout(struct sAniSirGlobal *mac,
527 uint32_t sub_type,
528 uint32_t *max_inactive_time,
529 uint32_t *max_unresponsive_time)
530{
531 uint32_t keep_alive;
532 uint16_t lm_id, ka_id;
533
534 switch (sub_type) {
535 case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO:
536 lm_id = WNI_CFG_GO_LINK_MONITOR_TIMEOUT;
537 ka_id = WNI_CFG_GO_KEEP_ALIVE_TIMEOUT;
538 break;
539 default:
540 /*For softAp the subtype value will be zero */
541 lm_id = WNI_CFG_AP_LINK_MONITOR_TIMEOUT;
542 ka_id = WNI_CFG_AP_KEEP_ALIVE_TIMEOUT;
543 }
544
545 if (wlan_cfg_get_int(mac, lm_id, max_inactive_time) != eSIR_SUCCESS) {
546 WMA_LOGE("Failed to read link monitor for subtype %d",
547 sub_type);
548 *max_inactive_time = WMA_LINK_MONITOR_DEFAULT_TIME_SECS;
549 }
550
551 if (wlan_cfg_get_int(mac, ka_id, &keep_alive) != eSIR_SUCCESS) {
552 WMA_LOGE("Failed to read keep alive for subtype %d", sub_type);
553 keep_alive = WMA_KEEP_ALIVE_DEFAULT_TIME_SECS;
554 }
555 *max_unresponsive_time = *max_inactive_time + keep_alive;
556}
557
558/**
559 * wma_set_sap_keepalive() - set SAP keep alive parameters to fw
560 * @wma: wma handle
561 * @vdev_id: vdev id
562 *
563 * Return: none
564 */
565void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id)
566{
567 uint32_t min_inactive_time, max_inactive_time, max_unresponsive_time;
568 struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE);
569
570 if (NULL == mac) {
571 WMA_LOGE("%s: Failed to get mac", __func__);
572 return;
573 }
574
575 wma_get_link_probe_timeout(mac, wma->interfaces[vdev_id].sub_type,
576 &max_inactive_time, &max_unresponsive_time);
577
578 min_inactive_time = max_inactive_time / 2;
579
580 if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
581 vdev_id, WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
582 min_inactive_time))
583 WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME");
584
585 if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
586 vdev_id, WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
587 max_inactive_time))
588 WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME");
589
590 if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
591 vdev_id, WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
592 max_unresponsive_time))
593 WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME");
594
595 WMA_LOGD("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u"
596 " max_unresponsive_time: %u", __func__, vdev_id,
597 min_inactive_time, max_inactive_time, max_unresponsive_time);
598}
599
600/**
mukul sharma72c8b222015-09-04 17:02:01 +0530601 * wma_set_sta_sa_query_param() - set sta sa query parameters
602 * @wma: wma handle
603 * @vdev_id: vdev id
604
605 * This function sets sta query related parameters in fw.
606 *
607 * Return: none
608 */
609
610void wma_set_sta_sa_query_param(tp_wma_handle wma,
611 uint8_t vdev_id)
612{
613 struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE);
614 uint32_t max_retries, retry_interval;
615 wmi_buf_t buf;
616 WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param *cmd;
617 int len;
618
619 WMA_LOGD(FL("Enter:"));
620 len = sizeof(*cmd);
621 buf = wmi_buf_alloc(wma->wmi_handle, len);
622 if (!buf) {
623 WMA_LOGE(FL("wmi_buf_alloc failed"));
624 return;
625 }
626
627 cmd = (WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param *)wmi_buf_data(buf);
628 WMITLV_SET_HDR(&cmd->tlv_header,
629 WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param,
630 WMITLV_GET_STRUCT_TLVLEN
631 (WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param));
632
633 if (wlan_cfg_get_int
634 (mac, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES,
635 &max_retries) != eSIR_SUCCESS) {
636 max_retries = DEFAULT_STA_SA_QUERY_MAX_RETRIES_COUNT;
637 WMA_LOGE(FL("Failed to get value for WNI_CFG_PMF_SA_QUERY_MAX_RETRIES"));
638 }
639 if (wlan_cfg_get_int
640 (mac, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL,
641 &retry_interval) != eSIR_SUCCESS) {
642 retry_interval = DEFAULT_STA_SA_QUERY_RETRY_INTERVAL;
643 WMA_LOGE(FL("Failed to get value for WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL"));
644 }
645
646 cmd->vdev_id = vdev_id;
647 cmd->sa_query_max_retry_count = max_retries;
648 cmd->sa_query_retry_interval = retry_interval;
649
650 WMA_LOGD(FL("STA sa query: vdev_id:%d interval:%u retry count:%d"),
651 vdev_id, retry_interval, max_retries);
652
653 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
654 WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID)) {
655 WMA_LOGE(FL("Failed to offload STA SA Query"));
656 cdf_nbuf_free(buf);
657 }
658
659 WMA_LOGD(FL("Exit :"));
660 return;
661}
662
663/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800664 * wma_set_sta_keep_alive() - set sta keep alive parameters
665 * @wma: wma handle
666 * @vdev_id: vdev id
667 * @method: method for keep alive
668 * @timeperiod: time period
669 * @hostv4addr: host ipv4 address
670 * @destv4addr: dst ipv4 address
671 * @destmac: destination mac
672 *
673 * This function sets keep alive related parameters in fw.
674 *
675 * Return: none
676 */
677void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id,
678 uint32_t method, uint32_t timeperiod,
679 uint8_t *hostv4addr, uint8_t *destv4addr,
680 uint8_t *destmac)
681{
682 wmi_buf_t buf;
683 WMI_STA_KEEPALIVE_CMD_fixed_param *cmd;
684 WMI_STA_KEEPALVE_ARP_RESPONSE *arp_rsp;
685 uint8_t *buf_ptr;
686 int len;
687
688 WMA_LOGD("%s: Enter", __func__);
689
690 if (timeperiod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) {
691 WMA_LOGE("Invalid period %d Max limit %d", timeperiod,
692 WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX);
693 return;
694 }
695
696 len = sizeof(*cmd) + sizeof(*arp_rsp);
697 buf = wmi_buf_alloc(wma->wmi_handle, len);
698 if (!buf) {
699 WMA_LOGE("wmi_buf_alloc failed");
700 return;
701 }
702
703 cmd = (WMI_STA_KEEPALIVE_CMD_fixed_param *) wmi_buf_data(buf);
704 buf_ptr = (uint8_t *) cmd;
705 WMITLV_SET_HDR(&cmd->tlv_header,
706 WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param,
707 WMITLV_GET_STRUCT_TLVLEN
708 (WMI_STA_KEEPALIVE_CMD_fixed_param));
709 cmd->interval = timeperiod;
710 cmd->enable = (timeperiod) ? 1 : 0;
711 cmd->vdev_id = vdev_id;
712 WMA_LOGD("Keep Alive: vdev_id:%d interval:%u method:%d", vdev_id,
713 timeperiod, method);
714 arp_rsp = (WMI_STA_KEEPALVE_ARP_RESPONSE *) (buf_ptr + sizeof(*cmd));
715 WMITLV_SET_HDR(&arp_rsp->tlv_header,
716 WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE,
717 WMITLV_GET_STRUCT_TLVLEN(WMI_STA_KEEPALVE_ARP_RESPONSE));
718
719 if (method == SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP) {
Govind Singhe55e6992015-11-18 17:29:12 +0530720 if ((NULL == hostv4addr) ||
721 (NULL == destv4addr) ||
722 (NULL == destmac)) {
723 WMA_LOGE("%s: received null pointer, hostv4addr:%p "
724 "destv4addr:%p destmac:%p ", __func__,
725 hostv4addr, destv4addr, destmac);
726 cdf_nbuf_free(buf);
727 return;
728 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729 cmd->method = WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE;
730 cdf_mem_copy(&arp_rsp->sender_prot_addr, hostv4addr,
731 SIR_IPV4_ADDR_LEN);
732 cdf_mem_copy(&arp_rsp->target_prot_addr, destv4addr,
733 SIR_IPV4_ADDR_LEN);
734 WMI_CHAR_ARRAY_TO_MAC_ADDR(destmac, &arp_rsp->dest_mac_addr);
735 } else {
736 cmd->method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME;
737 }
738
739 if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
740 WMI_STA_KEEPALIVE_CMDID)) {
741 WMA_LOGE("Failed to set KeepAlive");
742 cdf_nbuf_free(buf);
743 }
744
745 WMA_LOGD("%s: Exit", __func__);
746 return;
747}
748
749/**
750 * wma_vdev_install_key_complete_event_handler() - install key complete handler
751 * @handle: wma handle
752 * @event: event data
753 * @len: data length
754 *
755 * This event is sent by fw once WPA/WPA2 keys are installed in fw.
756 *
757 * Return: 0 for success or error code
758 */
759int wma_vdev_install_key_complete_event_handler(void *handle,
760 uint8_t *event,
761 uint32_t len)
762{
763 WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *param_buf = NULL;
764 wmi_vdev_install_key_complete_event_fixed_param *key_fp = NULL;
765
766 if (!event) {
767 WMA_LOGE("%s: event param null", __func__);
768 return -EINVAL;
769 }
770
771 param_buf = (WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *) event;
772 if (!param_buf) {
773 WMA_LOGE("%s: received null buf from target", __func__);
774 return -EINVAL;
775 }
776
777 key_fp = param_buf->fixed_param;
778 if (!key_fp) {
779 WMA_LOGE("%s: received null event data from target", __func__);
780 return -EINVAL;
781 }
782 /*
783 * Do nothing for now. Completion of set key is already indicated to lim
784 */
785 WMA_LOGI("%s: WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID", __func__);
786 return 0;
787}
788/*
789 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
790 * 0 for no restriction
791 * 1 for 1/4 us - Our lower layer calculations limit our precision to 1 msec
792 * 2 for 1/2 us - Our lower layer calculations limit our precision to 1 msec
793 * 3 for 1 us
794 * 4 for 2 us
795 * 5 for 4 us
796 * 6 for 8 us
797 * 7 for 16 us
798 */
799static const uint8_t wma_mpdu_spacing[] = { 0, 1, 1, 1, 2, 4, 8, 16 };
800
801/**
802 * wma_parse_mpdudensity() - give mpdu spacing from mpdu density
803 * @mpdudensity: mpdu density
804 *
805 * Return: mpdu spacing or 0 for error
806 */
807static inline uint8_t wma_parse_mpdudensity(uint8_t mpdudensity)
808{
809 if (mpdudensity < sizeof(wma_mpdu_spacing))
810 return wma_mpdu_spacing[mpdudensity];
811 else
812 return 0;
813}
814
815/**
816 * wmi_unified_send_peer_assoc() - send peer assoc command to fw
817 * @wma: wma handle
818 * @nw_type: nw type
819 * @params: add sta params
820 *
821 * This function send peer assoc command to firmware with
822 * different parameters.
823 *
824 * Return: 0 for success or error code
825 */
826int32_t wmi_unified_send_peer_assoc(tp_wma_handle wma,
827 tSirNwType nw_type,
828 tpAddStaParams params)
829{
830 ol_txrx_pdev_handle pdev;
831 wmi_peer_assoc_complete_cmd_fixed_param *cmd;
832 wmi_buf_t buf;
833 int32_t len;
834 int32_t ret, max_rates, i;
835 uint8_t rx_stbc, tx_stbc;
836 uint8_t *rate_pos, *buf_ptr;
837 wmi_rate_set peer_legacy_rates, peer_ht_rates;
838 wmi_vht_rate_set *mcs;
839 uint32_t num_peer_legacy_rates;
840 uint32_t num_peer_ht_rates;
841 uint32_t num_peer_11b_rates = 0;
842 uint32_t num_peer_11a_rates = 0;
843 uint32_t phymode;
844 uint32_t peer_nss = 1;
845 struct wma_txrx_node *intr = NULL;
846
847 if (NULL == params) {
848 WMA_LOGE("%s: params is NULL", __func__);
849 return -EINVAL;
850 }
851 intr = &wma->interfaces[params->smesessionId];
852
853 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
854
855 if (NULL == pdev) {
856 WMA_LOGE("%s: Failed to get pdev", __func__);
857 return -EINVAL;
858 }
859
860 cdf_mem_zero(&peer_legacy_rates, sizeof(wmi_rate_set));
861 cdf_mem_zero(&peer_ht_rates, sizeof(wmi_rate_set));
862
863 phymode = wma_peer_phymode(nw_type, params->staType,
864 params->htCapable,
865 params->ch_width,
866 params->vhtCapable);
867
868 /* Legacy Rateset */
869 rate_pos = (uint8_t *) peer_legacy_rates.rates;
870 for (i = 0; i < SIR_NUM_11B_RATES; i++) {
871 if (!params->supportedRates.llbRates[i])
872 continue;
873 rate_pos[peer_legacy_rates.num_rates++] =
874 params->supportedRates.llbRates[i];
875 num_peer_11b_rates++;
876 }
877 for (i = 0; i < SIR_NUM_11A_RATES; i++) {
878 if (!params->supportedRates.llaRates[i])
879 continue;
880 rate_pos[peer_legacy_rates.num_rates++] =
881 params->supportedRates.llaRates[i];
882 num_peer_11a_rates++;
883 }
884
885 if ((phymode == MODE_11A && num_peer_11a_rates == 0) ||
886 (phymode == MODE_11B && num_peer_11b_rates == 0)) {
887 WMA_LOGW("%s: Invalid phy rates. phymode 0x%x, 11b_rates %d, 11a_rates %d",
888 __func__, phymode, num_peer_11b_rates, num_peer_11a_rates);
889 return -EINVAL;
890 }
891 /* Set the Legacy Rates to Word Aligned */
892 num_peer_legacy_rates = roundup(peer_legacy_rates.num_rates,
893 sizeof(uint32_t));
894
895 /* HT Rateset */
896 max_rates = sizeof(peer_ht_rates.rates) /
897 sizeof(peer_ht_rates.rates[0]);
898 rate_pos = (uint8_t *) peer_ht_rates.rates;
899 for (i = 0; i < MAX_SUPPORTED_RATES; i++) {
900 if (params->supportedRates.supportedMCSSet[i / 8] &
901 (1 << (i % 8))) {
902 rate_pos[peer_ht_rates.num_rates++] = i;
903 if (i >= 8) {
904 /* MCS8 or higher rate is present, must be 2x2 */
905 peer_nss = 2;
906 }
907 }
908 if (peer_ht_rates.num_rates == max_rates)
909 break;
910 }
911
912 if (params->htCapable && !peer_ht_rates.num_rates) {
913 uint8_t temp_ni_rates[8] = { 0x0, 0x1, 0x2, 0x3,
914 0x4, 0x5, 0x6, 0x7};
915 /*
916 * Workaround for EV 116382: The peer is marked HT but with
917 * supported rx mcs set is set to 0. 11n spec mandates MCS0-7
918 * for a HT STA. So forcing the supported rx mcs rate to
919 * MCS 0-7. This workaround will be removed once we get
920 * clarification from WFA regarding this STA behavior.
921 */
922
923 /* TODO: Do we really need this? */
924 WMA_LOGW("Peer is marked as HT capable but supported mcs rate is 0");
925 peer_ht_rates.num_rates = sizeof(temp_ni_rates);
926 cdf_mem_copy((uint8_t *) peer_ht_rates.rates, temp_ni_rates,
927 peer_ht_rates.num_rates);
928 }
929
930 /* Set the Peer HT Rates to Word Aligned */
931 num_peer_ht_rates = roundup(peer_ht_rates.num_rates, sizeof(uint32_t));
932
933 len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + /* Place holder for peer legacy rate array */
934 (num_peer_legacy_rates * sizeof(uint8_t)) + /* peer legacy rate array size */
935 WMI_TLV_HDR_SIZE + /* Place holder for peer Ht rate array */
936 (num_peer_ht_rates * sizeof(uint8_t)) + /* peer HT rate array size */
937 sizeof(wmi_vht_rate_set);
938
939 buf = wmi_buf_alloc(wma->wmi_handle, len);
940 if (!buf) {
941 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
942 return -ENOMEM;
943 }
944
945 buf_ptr = (uint8_t *) wmi_buf_data(buf);
946 cmd = (wmi_peer_assoc_complete_cmd_fixed_param *) buf_ptr;
947 WMITLV_SET_HDR(&cmd->tlv_header,
948 WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param,
949 WMITLV_GET_STRUCT_TLVLEN
950 (wmi_peer_assoc_complete_cmd_fixed_param));
951
952 /* in ap/ibss mode and for tdls peer, use mac address of the peer in
953 * the other end as the new peer address; in sta mode, use bss id to
954 * be the new peer address
955 */
956 if ((wma_is_vdev_in_ap_mode(wma, params->smesessionId))
957#ifdef QCA_IBSS_SUPPORT
958 || (wma_is_vdev_in_ibss_mode(wma, params->smesessionId))
959#endif /* QCA_IBSS_SUPPORT */
960#ifdef FEATURE_WLAN_TDLS
961 || (STA_ENTRY_TDLS_PEER == params->staType)
962#endif /* FEATURE_WLAN_TDLS */
963 )
964 WMI_CHAR_ARRAY_TO_MAC_ADDR(params->staMac, &cmd->peer_macaddr);
965 else
966 WMI_CHAR_ARRAY_TO_MAC_ADDR(params->bssId, &cmd->peer_macaddr);
967 cmd->vdev_id = params->smesessionId;
968 cmd->peer_new_assoc = 1;
969 cmd->peer_associd = params->assocId;
970
971 /*
972 * The target only needs a subset of the flags maintained in the host.
973 * Just populate those flags and send it down
974 */
975 cmd->peer_flags = 0;
976
977 if (params->wmmEnabled)
978 cmd->peer_flags |= WMI_PEER_QOS;
979
980 if (params->uAPSD) {
981 cmd->peer_flags |= WMI_PEER_APSD;
982 WMA_LOGD("Set WMI_PEER_APSD: uapsd Mask %d", params->uAPSD);
983 }
984
985 if (params->htCapable) {
986 cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_QOS);
987 cmd->peer_rate_caps |= WMI_RC_HT_FLAG;
988 }
989
990 if (params->ch_width) {
991 cmd->peer_flags |= WMI_PEER_40MHZ;
992 cmd->peer_rate_caps |= WMI_RC_CW40_FLAG;
993 if (params->fShortGI40Mhz)
994 cmd->peer_rate_caps |= WMI_RC_SGI_FLAG;
995 } else if (params->fShortGI20Mhz)
996 cmd->peer_rate_caps |= WMI_RC_SGI_FLAG;
997
998#ifdef WLAN_FEATURE_11AC
999 if (params->vhtCapable) {
1000 cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_VHT | WMI_PEER_QOS);
1001 cmd->peer_rate_caps |= WMI_RC_HT_FLAG;
1002 }
1003
1004 if (params->ch_width == CH_WIDTH_80MHZ)
1005 cmd->peer_flags |= WMI_PEER_80MHZ;
1006 else if (params->ch_width == CH_WIDTH_160MHZ)
1007 cmd->peer_flags |= WMI_PEER_160MHZ;
1008 else if (params->ch_width == CH_WIDTH_80P80MHZ)
1009 cmd->peer_flags |= WMI_PEER_160MHZ;
1010
1011 cmd->peer_vht_caps = params->vht_caps;
1012#endif /* WLAN_FEATURE_11AC */
1013
1014 if (params->rmfEnabled)
1015 cmd->peer_flags |= WMI_PEER_PMF;
1016
1017 rx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_RXSTBC) >>
1018 IEEE80211_HTCAP_C_RXSTBC_S;
1019 if (rx_stbc) {
1020 cmd->peer_flags |= WMI_PEER_STBC;
1021 cmd->peer_rate_caps |= (rx_stbc << WMI_RC_RX_STBC_FLAG_S);
1022 }
1023
1024 tx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_TXSTBC) >>
1025 IEEE80211_HTCAP_C_TXSTBC_S;
1026 if (tx_stbc) {
1027 cmd->peer_flags |= WMI_PEER_STBC;
1028 cmd->peer_rate_caps |= (tx_stbc << WMI_RC_TX_STBC_FLAG_S);
1029 }
1030
1031 if (params->htLdpcCapable || params->vhtLdpcCapable)
1032 cmd->peer_flags |= WMI_PEER_LDPC;
1033
1034 switch (params->mimoPS) {
1035 case eSIR_HT_MIMO_PS_STATIC:
1036 cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS;
1037 break;
1038 case eSIR_HT_MIMO_PS_DYNAMIC:
1039 cmd->peer_flags |= WMI_PEER_DYN_MIMOPS;
1040 break;
1041 case eSIR_HT_MIMO_PS_NO_LIMIT:
1042 cmd->peer_flags |= WMI_PEER_SPATIAL_MUX;
1043 break;
1044 default:
1045 break;
1046 }
1047
1048#ifdef FEATURE_WLAN_TDLS
1049 if (STA_ENTRY_TDLS_PEER == params->staType)
1050 cmd->peer_flags |= WMI_PEER_AUTH;
1051#endif /* FEATURE_WLAN_TDLS */
1052
1053 if (params->wpa_rsn
1054#ifdef FEATURE_WLAN_WAPI
1055 || params->encryptType == eSIR_ED_WPI
1056#endif /* FEATURE_WLAN_WAPI */
1057 )
1058 cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
1059 if (params->wpa_rsn >> 1)
1060 cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
1061
1062 ol_txrx_peer_state_update(pdev, params->bssId, ol_txrx_peer_state_auth);
1063
1064#ifdef FEATURE_WLAN_WAPI
1065 if (params->encryptType == eSIR_ED_WPI) {
1066 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
1067 params->smesessionId,
1068 WMI_VDEV_PARAM_DROP_UNENCRY,
1069 false);
1070 if (ret) {
1071 WMA_LOGE
1072 ("Set WMI_VDEV_PARAM_DROP_UNENCRY Param status:%d\n",
1073 ret);
1074 cdf_nbuf_free(buf);
1075 return ret;
1076 }
1077 }
1078#endif /* FEATURE_WLAN_WAPI */
1079
1080 cmd->peer_caps = params->capab_info;
1081 cmd->peer_listen_intval = params->listenInterval;
1082 cmd->peer_ht_caps = params->ht_caps;
1083 cmd->peer_max_mpdu = (1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
1084 params->maxAmpduSize)) - 1;
1085 cmd->peer_mpdu_density = wma_parse_mpdudensity(params->maxAmpduDensity);
1086
1087 if (params->supportedRates.supportedMCSSet[1] &&
1088 params->supportedRates.supportedMCSSet[2])
1089 cmd->peer_rate_caps |= WMI_RC_TS_FLAG;
1090 else if (params->supportedRates.supportedMCSSet[1])
1091 cmd->peer_rate_caps |= WMI_RC_DS_FLAG;
1092
1093 /* Update peer legacy rate information */
1094 buf_ptr += sizeof(*cmd);
1095 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, num_peer_legacy_rates);
1096 buf_ptr += WMI_TLV_HDR_SIZE;
1097 cmd->num_peer_legacy_rates = peer_legacy_rates.num_rates;
1098 cdf_mem_copy(buf_ptr, peer_legacy_rates.rates,
1099 peer_legacy_rates.num_rates);
1100
1101 /* Update peer HT rate information */
1102 buf_ptr += num_peer_legacy_rates;
1103 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, num_peer_ht_rates);
1104 buf_ptr += WMI_TLV_HDR_SIZE;
1105 cmd->num_peer_ht_rates = peer_ht_rates.num_rates;
1106 cdf_mem_copy(buf_ptr, peer_ht_rates.rates, peer_ht_rates.num_rates);
1107
1108 /* VHT Rates */
1109 buf_ptr += num_peer_ht_rates;
1110 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_wmi_vht_rate_set,
1111 WMITLV_GET_STRUCT_TLVLEN(wmi_vht_rate_set));
1112
1113 cmd->peer_nss = peer_nss;
Naveen Rawatb14cab32015-11-02 17:01:51 -08001114 /*
1115 * Because of DBS a vdev may come up in any of the two MACs with
1116 * different capabilities. STBC capab should be fetched for given
1117 * hard_mode->MAC_id combo. It is planned that firmware should provide
1118 * these dev capabilities. But for now number of tx streams can be used
1119 * to identify if Tx STBC needs to be disabled.
1120 */
1121 if (intr->tx_streams < 2) {
1122 cmd->peer_vht_caps &= ~(1 << SIR_MAC_VHT_CAP_TXSTBC);
1123 WMA_LOGD("Num tx_streams: %d, Disabled txSTBC",
1124 intr->tx_streams);
1125 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126 WMA_LOGD("peer_nss %d peer_ht_rates.num_rates %d ", cmd->peer_nss,
1127 peer_ht_rates.num_rates);
1128
1129 mcs = (wmi_vht_rate_set *) buf_ptr;
1130 if (params->vhtCapable) {
1131#define VHT2x2MCSMASK 0xc
1132 mcs->rx_max_rate = params->supportedRates.vhtRxHighestDataRate;
1133 mcs->rx_mcs_set = params->supportedRates.vhtRxMCSMap;
1134 mcs->tx_max_rate = params->supportedRates.vhtTxHighestDataRate;
1135 mcs->tx_mcs_set = params->supportedRates.vhtTxMCSMap;
1136
1137 if (params->vhtSupportedRxNss) {
1138 cmd->peer_nss = params->vhtSupportedRxNss;
1139 } else {
1140 cmd->peer_nss = ((mcs->rx_mcs_set & VHT2x2MCSMASK)
1141 == VHT2x2MCSMASK) ? 1 : 2;
1142 }
1143 }
1144
1145 /*
1146 * Limit nss to max number of rf chain supported by target
1147 * Otherwise Fw will crash
1148 */
1149 wma_update_txrx_chainmask(wma->num_rf_chains, &cmd->peer_nss);
1150
1151 intr->nss = cmd->peer_nss;
1152 cmd->peer_phymode = phymode;
1153 WMA_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x "
1154 "peer_caps %x listen_intval %d ht_caps %x max_mpdu %d "
1155 "nss %d phymode %d peer_mpdu_density %d encr_type %d "
1156 "cmd->peer_vht_caps %x", __func__,
1157 cmd->vdev_id, cmd->peer_associd, cmd->peer_flags,
1158 cmd->peer_rate_caps, cmd->peer_caps,
1159 cmd->peer_listen_intval, cmd->peer_ht_caps,
1160 cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode,
1161 cmd->peer_mpdu_density, params->encryptType,
1162 cmd->peer_vht_caps);
1163
1164 ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
1165 WMI_PEER_ASSOC_CMDID);
1166 if (ret != EOK) {
1167 WMA_LOGP("%s: Failed to send peer assoc command ret = %d",
1168 __func__, ret);
1169 cdf_nbuf_free(buf);
1170 }
1171 return ret;
1172}
1173
1174/**
1175 * wmi_unified_vdev_set_gtx_cfg_send() - set GTX params
1176 * @wmi_handle: wmi handle
1177 * @if_id: vdev id
1178 * @gtx_info: GTX config params
1179 *
1180 * This function set GTX related params in firmware.
1181 *
1182 * Return: 0 for success or error code
1183 */
1184int wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, uint32_t if_id,
1185 gtx_config_t *gtx_info)
1186{
1187 wmi_vdev_set_gtx_params_cmd_fixed_param *cmd;
1188 wmi_buf_t buf;
1189 int len = sizeof(wmi_vdev_set_gtx_params_cmd_fixed_param);
1190 buf = wmi_buf_alloc(wmi_handle, len);
1191 if (!buf) {
1192 WMA_LOGE("%s:wmi_buf_alloc failed", __FUNCTION__);
1193 return -ENOMEM;
1194 }
1195 cmd = (wmi_vdev_set_gtx_params_cmd_fixed_param *) wmi_buf_data(buf);
1196 WMITLV_SET_HDR(&cmd->tlv_header,
1197 WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param,
1198 WMITLV_GET_STRUCT_TLVLEN
1199 (wmi_vdev_set_gtx_params_cmd_fixed_param));
1200 cmd->vdev_id = if_id;
1201
1202 cmd->gtxRTMask[0] = gtx_info->gtxRTMask[0];
1203 cmd->gtxRTMask[1] = gtx_info->gtxRTMask[1];
1204 cmd->userGtxMask = gtx_info->gtxUsrcfg;
1205 cmd->gtxPERThreshold = gtx_info->gtxPERThreshold;
1206 cmd->gtxPERMargin = gtx_info->gtxPERMargin;
1207 cmd->gtxTPCstep = gtx_info->gtxTPCstep;
1208 cmd->gtxTPCMin = gtx_info->gtxTPCMin;
1209 cmd->gtxBWMask = gtx_info->gtxBWMask;
1210
1211 WMA_LOGD("Setting vdev%d GTX values:htmcs 0x%x, vhtmcs 0x%x, usermask 0x%x, \
1212 gtxPERThreshold %d, gtxPERMargin %d, gtxTPCstep %d, gtxTPCMin %d, \
1213 gtxBWMask 0x%x.", if_id, cmd->gtxRTMask[0], cmd->gtxRTMask[1],
1214 cmd->userGtxMask, cmd->gtxPERThreshold, cmd->gtxPERMargin,
1215 cmd->gtxTPCstep, cmd->gtxTPCMin, cmd->gtxBWMask);
1216 return wmi_unified_cmd_send(wmi_handle, buf, len,
1217 WMI_VDEV_SET_GTX_PARAMS_CMDID);
1218}
1219
1220/**
1221 * wma_update_protection_mode() - update protection mode
1222 * @wma: wma handle
1223 * @vdev_id: vdev id
1224 * @llbcoexist: protection mode info
1225 *
1226 * This function set protection mode(RTS/CTS) to fw for passed vdev id.
1227 *
1228 * Return: none
1229 */
1230void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id,
1231 uint8_t llbcoexist)
1232{
1233 int ret;
1234 enum ieee80211_protmode prot_mode;
1235
1236 prot_mode = llbcoexist ? IEEE80211_PROT_CTSONLY : IEEE80211_PROT_NONE;
1237
1238 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
1239 WMI_VDEV_PARAM_PROTECTION_MODE,
1240 prot_mode);
1241
1242 if (ret)
1243 WMA_LOGE("Failed to send wmi protection mode cmd");
1244 else
1245 WMA_LOGD("Updated protection mode %d to target", prot_mode);
1246}
1247
1248/**
1249 * wma_update_beacon_interval() - update beacon interval in fw
1250 * @wma: wma handle
1251 * @vdev_id: vdev id
1252 * @beaconInterval: becon interval
1253 *
1254 * Return: none
1255 */
1256static void
1257wma_update_beacon_interval(tp_wma_handle wma, uint8_t vdev_id,
1258 uint16_t beaconInterval)
1259{
1260 int ret;
1261
1262 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
1263 WMI_VDEV_PARAM_BEACON_INTERVAL,
1264 beaconInterval);
1265
1266 if (ret)
1267 WMA_LOGE("Failed to update beacon interval");
1268 else
1269 WMA_LOGI("Updated beacon interval %d for vdev %d",
1270 beaconInterval, vdev_id);
1271}
1272
1273/**
1274 * wma_process_update_beacon_params() - update beacon parameters to target
1275 * @wma: wma handle
1276 * @bcn_params: beacon parameters
1277 *
1278 * Return: none
1279 */
1280void
1281wma_process_update_beacon_params(tp_wma_handle wma,
1282 tUpdateBeaconParams *bcn_params)
1283{
1284 if (!bcn_params) {
1285 WMA_LOGE("bcn_params NULL");
1286 return;
1287 }
1288
1289 if (bcn_params->smeSessionId >= wma->max_bssid) {
1290 WMA_LOGE("Invalid vdev id %d", bcn_params->smeSessionId);
1291 return;
1292 }
1293
1294 if (bcn_params->paramChangeBitmap & PARAM_BCN_INTERVAL_CHANGED) {
1295 wma_update_beacon_interval(wma, bcn_params->smeSessionId,
1296 bcn_params->beaconInterval);
1297 }
1298
1299 if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED)
1300 wma_update_protection_mode(wma, bcn_params->smeSessionId,
1301 bcn_params->llbCoexist);
1302}
1303
1304/**
1305 * wma_update_cfg_params() - update cfg parameters to target
1306 * @wma: wma handle
1307 * @cfgParam: cfg parameter
1308 *
1309 * Return: none
1310 */
1311void wma_update_cfg_params(tp_wma_handle wma, tSirMsgQ *cfgParam)
1312{
1313 uint8_t vdev_id;
1314 uint32_t param_id;
1315 uint32_t cfg_val;
1316 int ret;
1317 /* get mac to acess CFG data base */
1318 struct sAniSirGlobal *pmac;
1319
1320 switch (cfgParam->bodyval) {
1321 case WNI_CFG_RTS_THRESHOLD:
1322 param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
1323 break;
1324 case WNI_CFG_FRAGMENTATION_THRESHOLD:
1325 param_id = WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD;
1326 break;
1327 default:
1328 WMA_LOGD("Unhandled cfg parameter %d", cfgParam->bodyval);
1329 return;
1330 }
1331
1332 pmac = cds_get_context(CDF_MODULE_ID_PE);
1333
1334 if (NULL == pmac) {
1335 WMA_LOGE("%s: Failed to get pmac", __func__);
1336 return;
1337 }
1338
1339 if (wlan_cfg_get_int(pmac, (uint16_t) cfgParam->bodyval,
1340 &cfg_val) != eSIR_SUCCESS) {
1341 WMA_LOGE("Failed to get value for CFG PARAMS %d. returning without updating",
1342 cfgParam->bodyval);
1343 return;
1344 }
1345
1346 for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) {
1347 if (wma->interfaces[vdev_id].handle != 0) {
1348 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
1349 vdev_id, param_id,
1350 cfg_val);
1351 if (ret)
1352 WMA_LOGE("Update cfg params failed for vdevId %d",
1353 vdev_id);
1354 }
1355 }
1356}
1357
1358/**
1359 * wma_read_cfg_wepkey() - fill key_info for WEP key
1360 * @wma_handle: wma handle
1361 * @key_info: key_info ptr
1362 * @def_key_idx: default key index
1363 * @num_keys: number of keys
1364 *
1365 * This function reads WEP keys from cfg and fills
1366 * up key_info.
1367 *
1368 * Return: none
1369 */
1370static void wma_read_cfg_wepkey(tp_wma_handle wma_handle,
1371 tSirKeys *key_info, uint32_t *def_key_idx,
1372 uint8_t *num_keys)
1373{
1374 tSirRetStatus status;
1375 uint32_t val = SIR_MAC_KEY_LENGTH;
1376 uint8_t i, j;
1377
1378 WMA_LOGD("Reading WEP keys from cfg");
1379 /* NOTE:def_key_idx is initialized to 0 by the caller */
1380 status = wlan_cfg_get_int(wma_handle->mac_context,
1381 WNI_CFG_WEP_DEFAULT_KEYID, def_key_idx);
1382 if (status != eSIR_SUCCESS)
1383 WMA_LOGE("Unable to read default id, defaulting to 0");
1384
1385 for (i = 0, j = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) {
1386 status = wlan_cfg_get_str(wma_handle->mac_context,
1387 (uint16_t) WNI_CFG_WEP_DEFAULT_KEY_1 +
1388 i, key_info[j].key, &val);
1389 if (status != eSIR_SUCCESS) {
1390 WMA_LOGE("WEP key is not configured at :%d", i);
1391 } else {
1392 key_info[j].keyId = i;
1393 key_info[j].keyLength = (uint16_t) val;
1394 j++;
1395 }
1396 }
1397 *num_keys = j;
1398}
1399
1400/**
1401 * wma_setup_install_key_cmd() - fill wmi buffer as per key parameters
1402 * @wma_handle: wma handle
1403 * @key_params: key parameters
1404 * @len: length
1405 * @mode: op mode
1406 *
1407 * This function setsup wmi buffer from information
1408 * passed in key_params.
1409 *
1410 * Return: filled wmi buffer ptr or NULL for error
1411 */
1412static wmi_buf_t wma_setup_install_key_cmd(tp_wma_handle wma_handle,
1413 struct wma_set_key_params
1414 *key_params, uint32_t *len,
1415 uint8_t mode)
1416{
1417 wmi_vdev_install_key_cmd_fixed_param *cmd;
1418 wmi_buf_t buf;
1419 uint8_t *buf_ptr;
1420 uint8_t *key_data;
1421#ifdef WLAN_FEATURE_11W
1422 struct wma_txrx_node *iface = NULL;
1423#endif /* WLAN_FEATURE_11W */
1424 if ((key_params->key_type == eSIR_ED_NONE &&
1425 key_params->key_len) || (key_params->key_type != eSIR_ED_NONE &&
1426 !key_params->key_len)) {
1427 WMA_LOGE("%s:Invalid set key request", __func__);
1428 return NULL;
1429 }
1430
1431 *len = sizeof(*cmd) + roundup(key_params->key_len, sizeof(uint32_t)) +
1432 WMI_TLV_HDR_SIZE;
1433
1434 buf = wmi_buf_alloc(wma_handle->wmi_handle, *len);
1435 if (!buf) {
1436 WMA_LOGE("Failed to allocate buffer to send set key cmd");
1437 return NULL;
1438 }
1439
1440 buf_ptr = (uint8_t *) wmi_buf_data(buf);
1441 cmd = (wmi_vdev_install_key_cmd_fixed_param *) buf_ptr;
1442 WMITLV_SET_HDR(&cmd->tlv_header,
1443 WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param,
1444 WMITLV_GET_STRUCT_TLVLEN
1445 (wmi_vdev_install_key_cmd_fixed_param));
1446 cmd->vdev_id = key_params->vdev_id;
1447 cmd->key_ix = key_params->key_idx;
1448 WMI_CHAR_ARRAY_TO_MAC_ADDR(key_params->peer_mac, &cmd->peer_macaddr);
1449 if (key_params->unicast)
1450 cmd->key_flags |= PAIRWISE_USAGE;
1451 else
1452 cmd->key_flags |= GROUP_USAGE;
1453
1454 switch (key_params->key_type) {
1455 case eSIR_ED_NONE:
1456 cmd->key_cipher = WMI_CIPHER_NONE;
1457 break;
1458 case eSIR_ED_WEP40:
1459 case eSIR_ED_WEP104:
1460 cmd->key_cipher = WMI_CIPHER_WEP;
1461 if (key_params->unicast &&
Ganesh Kondabattini59a4a952015-11-30 11:55:40 +05301462 cmd->key_ix == key_params->def_key_idx) {
1463 WMA_LOGD("STA Mode: cmd->key_flags |= TX_USAGE");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 cmd->key_flags |= TX_USAGE;
Ganesh Kondabattini59a4a952015-11-30 11:55:40 +05301465 } else if ((mode == wlan_op_mode_ap) &&
1466 (cmd->key_ix == key_params->def_key_idx)) {
1467 WMA_LOGD("AP Mode: cmd->key_flags |= TX_USAGE");
1468 cmd->key_flags |= TX_USAGE;
1469 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001470 break;
1471 case eSIR_ED_TKIP:
1472 cmd->key_txmic_len = WMA_TXMIC_LEN;
1473 cmd->key_rxmic_len = WMA_RXMIC_LEN;
1474 cmd->key_cipher = WMI_CIPHER_TKIP;
1475 break;
1476#ifdef FEATURE_WLAN_WAPI
1477#define WPI_IV_LEN 16
1478 case eSIR_ED_WPI:
1479 {
1480 /*initialize receive and transmit IV with default values */
1481 /* **Note: tx_iv must be sent in reverse** */
1482 unsigned char tx_iv[16] = { 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c,
1483 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c,
1484 0x36, 0x5c, 0x36, 0x5c};
1485 unsigned char rx_iv[16] = { 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36,
1486 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36,
1487 0x5c, 0x36, 0x5c, 0x37};
1488 if (mode == wlan_op_mode_ap) {
1489 /* Authenticator initializes the value of PN as
1490 * 0x5C365C365C365C365C365C365C365C36 for MCastkey Update
1491 */
1492 if (key_params->unicast)
1493 tx_iv[0] = 0x37;
1494
1495 rx_iv[WPI_IV_LEN - 1] = 0x36;
1496 } else {
1497 if (!key_params->unicast)
1498 rx_iv[WPI_IV_LEN - 1] = 0x36;
1499 }
1500
1501 cmd->key_txmic_len = WMA_TXMIC_LEN;
1502 cmd->key_rxmic_len = WMA_RXMIC_LEN;
1503
1504 cdf_mem_copy(&cmd->wpi_key_rsc_counter, &rx_iv,
1505 WPI_IV_LEN);
1506 cdf_mem_copy(&cmd->wpi_key_tsc_counter, &tx_iv,
1507 WPI_IV_LEN);
1508 cmd->key_cipher = WMI_CIPHER_WAPI;
1509 break;
1510 }
1511#endif /* FEATURE_WLAN_WAPI */
1512 case eSIR_ED_CCMP:
1513 cmd->key_cipher = WMI_CIPHER_AES_CCM;
1514 break;
1515#ifdef WLAN_FEATURE_11W
1516 case eSIR_ED_AES_128_CMAC:
1517 cmd->key_cipher = WMI_CIPHER_AES_CMAC;
1518 break;
1519#endif /* WLAN_FEATURE_11W */
1520 default:
1521 /* TODO: MFP ? */
1522 WMA_LOGE("%s:Invalid encryption type:%d", __func__,
1523 key_params->key_type);
1524 cdf_nbuf_free(buf);
1525 return NULL;
1526 }
1527
1528 buf_ptr += sizeof(wmi_vdev_install_key_cmd_fixed_param);
1529 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
1530 roundup(key_params->key_len, sizeof(uint32_t)));
1531 key_data = (A_UINT8 *) (buf_ptr + WMI_TLV_HDR_SIZE);
1532#ifdef BIG_ENDIAN_HOST
1533 {
1534 /* for big endian host, copy engine byte_swap is enabled
1535 * But the key data content is in network byte order
1536 * Need to byte swap the key data content - so when copy engine
1537 * does byte_swap - target gets key_data content in the correct
1538 * order.
1539 */
1540 int8_t i;
1541 uint32_t *destp, *srcp;
1542
1543 destp = (uint32_t *) key_data;
1544 srcp = (uint32_t *) key_params->key_data;
1545 for (i = 0;
1546 i < roundup(key_params->key_len, sizeof(uint32_t)) / 4;
1547 i++) {
1548 *destp = le32_to_cpu(*srcp);
1549 destp++;
1550 srcp++;
1551 }
1552 }
1553#else
1554 cdf_mem_copy((void *)key_data,
1555 (const void *)key_params->key_data, key_params->key_len);
1556#endif /* BIG_ENDIAN_HOST */
1557 cmd->key_len = key_params->key_len;
1558
1559#ifdef WLAN_FEATURE_11W
1560 if (key_params->key_type == eSIR_ED_AES_128_CMAC) {
1561 iface = &wma_handle->interfaces[key_params->vdev_id];
1562 if (iface) {
1563 iface->key.key_length = key_params->key_len;
1564 cdf_mem_copy(iface->key.key,
1565 (const void *)key_params->key_data,
1566 iface->key.key_length);
1567 if ((cmd->key_ix == WMA_IGTK_KEY_INDEX_4) ||
1568 (cmd->key_ix == WMA_IGTK_KEY_INDEX_5))
1569 cdf_mem_zero(iface->key.key_id[cmd->key_ix -
1570 WMA_IGTK_KEY_INDEX_4].ipn,
1571 CMAC_IPN_LEN);
1572 }
1573 }
1574#endif /* WLAN_FEATURE_11W */
1575
1576 WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d"
1577 " unicast %d peer_mac %pM def_key_idx %d", key_params->vdev_id,
1578 key_params->key_idx, key_params->key_type, key_params->key_len,
1579 key_params->unicast, key_params->peer_mac,
1580 key_params->def_key_idx);
1581
1582 return buf;
1583}
1584
1585/**
1586 * wma_set_bsskey() - set encryption key to fw.
1587 * @wma_handle: wma handle
1588 * @key_info: key info
1589 *
1590 * Return: none
1591 */
1592void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info)
1593{
1594 struct wma_set_key_params key_params;
1595 wmi_buf_t buf;
1596 int32_t status;
1597 uint32_t len = 0, i;
1598 uint32_t def_key_idx = 0;
1599 ol_txrx_vdev_handle txrx_vdev;
1600
1601 WMA_LOGD("BSS key setup");
1602 txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId);
1603 if (!txrx_vdev) {
1604 WMA_LOGE("%s:Invalid vdev handle", __func__);
1605 key_info->status = CDF_STATUS_E_FAILURE;
1606 goto out;
1607 }
1608
1609 /*
1610 * For IBSS, WMI expects the BSS key to be set per peer key
1611 * So cache the BSS key in the wma_handle and re-use it when the
1612 * STA key is been setup for a peer
1613 */
1614 if (wlan_op_mode_ibss == txrx_vdev->opmode) {
1615 key_info->status = CDF_STATUS_SUCCESS;
1616 if (wma_handle->ibss_started > 0)
1617 goto out;
1618 WMA_LOGD("Caching IBSS Key");
1619 cdf_mem_copy(&wma_handle->ibsskey_info, key_info,
1620 sizeof(tSetBssKeyParams));
1621 }
1622
1623 cdf_mem_set(&key_params, sizeof(key_params), 0);
1624 key_params.vdev_id = key_info->smesessionId;
1625 key_params.key_type = key_info->encType;
1626 key_params.singl_tid_rc = key_info->singleTidRc;
1627 key_params.unicast = false;
1628 if (txrx_vdev->opmode == wlan_op_mode_sta) {
1629 cdf_mem_copy(key_params.peer_mac,
1630 wma_handle->interfaces[key_info->smesessionId].bssid,
1631 IEEE80211_ADDR_LEN);
1632 } else {
1633 /* vdev mac address will be passed for all other modes */
1634 cdf_mem_copy(key_params.peer_mac, txrx_vdev->mac_addr.raw,
1635 IEEE80211_ADDR_LEN);
1636 WMA_LOGA("BSS Key setup with vdev_mac %pM\n",
1637 txrx_vdev->mac_addr.raw);
1638 }
1639
1640 if (key_info->numKeys == 0 &&
1641 (key_info->encType == eSIR_ED_WEP40 ||
1642 key_info->encType == eSIR_ED_WEP104)) {
1643 wma_read_cfg_wepkey(wma_handle, key_info->key,
1644 &def_key_idx, &key_info->numKeys);
1645 }
1646
1647 for (i = 0; i < key_info->numKeys; i++) {
1648 if (key_params.key_type != eSIR_ED_NONE &&
1649 !key_info->key[i].keyLength)
1650 continue;
1651 if (key_info->encType == eSIR_ED_WPI) {
1652 key_params.key_idx = key_info->key[i].keyId;
1653 key_params.def_key_idx = key_info->key[i].keyId;
1654 } else
1655 key_params.key_idx = key_info->key[i].keyId;
1656
1657 key_params.key_len = key_info->key[i].keyLength;
1658 if (key_info->encType == eSIR_ED_TKIP) {
1659 cdf_mem_copy(key_params.key_data,
1660 key_info->key[i].key, 16);
1661 cdf_mem_copy(&key_params.key_data[16],
1662 &key_info->key[i].key[24], 8);
1663 cdf_mem_copy(&key_params.key_data[24],
1664 &key_info->key[i].key[16], 8);
1665 } else
1666 cdf_mem_copy((void *)key_params.key_data,
1667 (const void *)key_info->key[i].key,
1668 key_info->key[i].keyLength);
1669
1670 WMA_LOGD("%s: bss key[%d] length %d", __func__, i,
1671 key_info->key[i].keyLength);
1672
1673 buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len,
1674 txrx_vdev->opmode);
1675 if (!buf) {
1676 WMA_LOGE("%s:Failed to setup install key buf",
1677 __func__);
1678 key_info->status = CDF_STATUS_E_NOMEM;
1679 goto out;
1680 }
1681
1682 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
1683 WMI_VDEV_INSTALL_KEY_CMDID);
1684 if (status) {
1685 cdf_nbuf_free(buf);
1686 WMA_LOGE("%s:Failed to send install key command",
1687 __func__);
1688 key_info->status = CDF_STATUS_E_FAILURE;
1689 goto out;
1690 }
1691 }
1692
1693 wma_handle->ibss_started++;
1694 /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */
1695 key_info->status = CDF_STATUS_SUCCESS;
1696
1697out:
1698 wma_send_msg(wma_handle, WMA_SET_BSSKEY_RSP, (void *)key_info, 0);
1699}
1700
1701#ifdef QCA_IBSS_SUPPORT
1702/**
1703 * wma_calc_ibss_heart_beat_timer() - calculate IBSS heart beat timer
1704 * @peer_num: number of peers
1705 *
1706 * Return: heart beat timer value
1707 */
1708static uint16_t wma_calc_ibss_heart_beat_timer(int16_t peer_num)
1709{
1710 /* heart beat timer value look-up table */
1711 /* entry index : (the number of currently connected peers) - 1
1712 entry value : the heart time threshold value in seconds for
1713 detecting ibss peer departure */
1714 static const uint16_t heart_beat_timer[MAX_IBSS_PEERS] = {
1715 4, 4, 4, 4, 4, 4, 4, 4,
1716 8, 8, 8, 8, 8, 8, 8, 8,
1717 12, 12, 12, 12, 12, 12, 12, 12,
1718 16, 16, 16, 16, 16, 16, 16, 16
1719 };
1720
1721 if (peer_num < 1 || peer_num > MAX_IBSS_PEERS)
1722 return 0;
1723
1724 return heart_beat_timer[peer_num - 1];
1725
1726}
1727
1728/**
1729 * wma_adjust_ibss_heart_beat_timer() - set ibss heart beat timer in fw.
1730 * @wma: wma handle
1731 * @vdev_id: vdev id
1732 * @peer_num_delta: peer number delta value
1733 *
1734 * Return: none
1735 */
1736void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma,
1737 uint8_t vdev_id,
1738 int8_t peer_num_delta)
1739{
1740 ol_txrx_vdev_handle vdev;
1741 int16_t new_peer_num;
1742 uint16_t new_timer_value_sec;
1743 uint32_t new_timer_value_ms;
1744
1745 if (peer_num_delta != 1 && peer_num_delta != -1) {
1746 WMA_LOGE("Invalid peer_num_delta value %d", peer_num_delta);
1747 return;
1748 }
1749
1750 vdev = wma_find_vdev_by_id(wma, vdev_id);
1751 if (!vdev) {
1752 WMA_LOGE("vdev not found : vdev_id %d", vdev_id);
1753 return;
1754 }
1755
1756 new_peer_num = vdev->ibss_peer_num + peer_num_delta;
1757 if (new_peer_num > MAX_IBSS_PEERS || new_peer_num < 0) {
1758 WMA_LOGE("new peer num %d out of valid boundary", new_peer_num);
1759 return;
1760 }
1761
1762 /* adjust peer numbers */
1763 vdev->ibss_peer_num = new_peer_num;
1764
1765 /* reset timer value if all peers departed */
1766 if (new_peer_num == 0) {
1767 vdev->ibss_peer_heart_beat_timer = 0;
1768 return;
1769 }
1770
1771 /* calculate new timer value */
1772 new_timer_value_sec = wma_calc_ibss_heart_beat_timer(new_peer_num);
1773 if (new_timer_value_sec == 0) {
1774 WMA_LOGE("timer value %d is invalid for peer number %d",
1775 new_timer_value_sec, new_peer_num);
1776 return;
1777 }
1778 if (new_timer_value_sec == vdev->ibss_peer_heart_beat_timer) {
1779 WMA_LOGD("timer value %d stays same, no need to notify target",
1780 new_timer_value_sec);
1781 return;
1782 }
1783
1784 /* send new timer value to target */
1785 vdev->ibss_peer_heart_beat_timer = new_timer_value_sec;
1786
1787 new_timer_value_ms = ((uint32_t) new_timer_value_sec) * 1000;
1788
1789 if (wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
1790 WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS,
1791 new_timer_value_ms)) {
1792 WMA_LOGE("Failed to set IBSS link monitoring timer value");
1793 return;
1794 }
1795
1796 WMA_LOGD("Set IBSS link monitor timer: peer_num = %d timer_value = %d",
1797 new_peer_num, new_timer_value_ms);
1798}
1799
1800#endif /* QCA_IBSS_SUPPORT */
1801/**
1802 * wma_set_ibsskey_helper() - cached IBSS key in wma handle
1803 * @wma_handle: wma handle
1804 * @key_info: set bss key info
1805 * @peerMacAddr: peer mac address
1806 *
1807 * Return: none
1808 */
1809static void wma_set_ibsskey_helper(tp_wma_handle wma_handle,
1810 tpSetBssKeyParams key_info,
1811 uint8_t *peerMacAddr)
1812{
1813 struct wma_set_key_params key_params;
1814 wmi_buf_t buf;
1815 int32_t status;
1816 uint32_t len = 0, i;
1817 uint32_t def_key_idx = 0;
1818 ol_txrx_vdev_handle txrx_vdev;
1819
1820 WMA_LOGD("BSS key setup for peer");
1821 ASSERT(NULL != peerMacAddr);
1822 txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId);
1823 if (!txrx_vdev) {
1824 WMA_LOGE("%s:Invalid vdev handle", __func__);
1825 key_info->status = CDF_STATUS_E_FAILURE;
1826 return;
1827 }
1828
1829 cdf_mem_set(&key_params, sizeof(key_params), 0);
1830 key_params.vdev_id = key_info->smesessionId;
1831 key_params.key_type = key_info->encType;
1832 key_params.singl_tid_rc = key_info->singleTidRc;
1833 key_params.unicast = false;
1834 ASSERT(wlan_op_mode_ibss == txrx_vdev->opmode);
1835
1836 cdf_mem_copy(key_params.peer_mac, peerMacAddr, IEEE80211_ADDR_LEN);
1837
1838 if (key_info->numKeys == 0 &&
1839 (key_info->encType == eSIR_ED_WEP40 ||
1840 key_info->encType == eSIR_ED_WEP104)) {
1841 wma_read_cfg_wepkey(wma_handle, key_info->key,
1842 &def_key_idx, &key_info->numKeys);
1843 }
1844
1845 for (i = 0; i < key_info->numKeys; i++) {
1846 if (key_params.key_type != eSIR_ED_NONE &&
1847 !key_info->key[i].keyLength)
1848 continue;
1849 key_params.key_idx = key_info->key[i].keyId;
1850 key_params.key_len = key_info->key[i].keyLength;
1851 if (key_info->encType == eSIR_ED_TKIP) {
1852 cdf_mem_copy(key_params.key_data,
1853 key_info->key[i].key, 16);
1854 cdf_mem_copy(&key_params.key_data[16],
1855 &key_info->key[i].key[24], 8);
1856 cdf_mem_copy(&key_params.key_data[24],
1857 &key_info->key[i].key[16], 8);
1858 } else
1859 cdf_mem_copy((void *)key_params.key_data,
1860 (const void *)key_info->key[i].key,
1861 key_info->key[i].keyLength);
1862
1863 WMA_LOGD("%s: peer bcast key[%d] length %d", __func__, i,
1864 key_info->key[i].keyLength);
1865
1866 buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len,
1867 txrx_vdev->opmode);
1868 if (!buf) {
1869 WMA_LOGE("%s:Failed to setup install key buf",
1870 __func__);
1871 return;
1872 }
1873
1874 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
1875 WMI_VDEV_INSTALL_KEY_CMDID);
1876 if (status) {
1877 cdf_nbuf_free(buf);
1878 WMA_LOGE("%s:Failed to send install key command",
1879 __func__);
1880 }
1881 }
1882}
1883
1884/**
1885 * wma_set_stakey() - set encryption key
1886 * @wma_handle: wma handle
1887 * @key_info: station key info
1888 *
1889 * This function sets encryption key for WEP/WPA/WPA2
1890 * encryption mode in firmware and send response to upper layer.
1891 *
1892 * Return: none
1893 */
1894void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info)
1895{
1896 wmi_buf_t buf;
1897 int32_t status, i;
1898 uint32_t len = 0;
1899 ol_txrx_pdev_handle txrx_pdev;
1900 ol_txrx_vdev_handle txrx_vdev;
1901 struct ol_txrx_peer_t *peer;
1902 uint8_t num_keys = 0, peer_id;
1903 struct wma_set_key_params key_params;
1904 uint32_t def_key_idx = 0;
1905
1906 WMA_LOGD("STA key setup");
1907
1908 /* Get the txRx Pdev handle */
1909 txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX);
1910 if (!txrx_pdev) {
1911 WMA_LOGE("%s:Invalid txrx pdev handle", __func__);
1912 key_info->status = CDF_STATUS_E_FAILURE;
1913 goto out;
1914 }
1915
1916 peer = ol_txrx_find_peer_by_addr(txrx_pdev, key_info->peerMacAddr,
1917 &peer_id);
1918 if (!peer) {
1919 WMA_LOGE("%s:Invalid peer for key setting", __func__);
1920 key_info->status = CDF_STATUS_E_FAILURE;
1921 goto out;
1922 }
1923
1924 txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId);
1925 if (!txrx_vdev) {
1926 WMA_LOGE("%s:TxRx Vdev Handle is NULL", __func__);
1927 key_info->status = CDF_STATUS_E_FAILURE;
1928 goto out;
1929 }
1930
1931 if (key_info->defWEPIdx == WMA_INVALID_KEY_IDX &&
1932 (key_info->encType == eSIR_ED_WEP40 ||
1933 key_info->encType == eSIR_ED_WEP104) &&
1934 txrx_vdev->opmode != wlan_op_mode_ap) {
1935 wma_read_cfg_wepkey(wma_handle, key_info->key,
1936 &def_key_idx, &num_keys);
1937 key_info->defWEPIdx = def_key_idx;
1938 } else {
1939 num_keys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS;
1940 if (key_info->encType != eSIR_ED_NONE) {
1941 for (i = 0; i < num_keys; i++) {
1942 if (key_info->key[i].keyDirection ==
1943 eSIR_TX_DEFAULT) {
1944 key_info->defWEPIdx = i;
1945 break;
1946 }
1947 }
1948 }
1949 }
1950 cdf_mem_set(&key_params, sizeof(key_params), 0);
1951 key_params.vdev_id = key_info->smesessionId;
1952 key_params.key_type = key_info->encType;
1953 key_params.singl_tid_rc = key_info->singleTidRc;
1954 key_params.unicast = true;
1955 key_params.def_key_idx = key_info->defWEPIdx;
1956 cdf_mem_copy((void *)key_params.peer_mac,
1957 (const void *)key_info->peerMacAddr, IEEE80211_ADDR_LEN);
1958 for (i = 0; i < num_keys; i++) {
1959 if (key_params.key_type != eSIR_ED_NONE &&
1960 !key_info->key[i].keyLength)
1961 continue;
1962 if (key_info->encType == eSIR_ED_TKIP) {
1963 cdf_mem_copy(key_params.key_data,
1964 key_info->key[i].key, 16);
1965 cdf_mem_copy(&key_params.key_data[16],
1966 &key_info->key[i].key[24], 8);
1967 cdf_mem_copy(&key_params.key_data[24],
1968 &key_info->key[i].key[16], 8);
1969 } else
1970 cdf_mem_copy(key_params.key_data, key_info->key[i].key,
1971 key_info->key[i].keyLength);
1972 if (key_info->encType == eSIR_ED_WPI) {
1973 key_params.key_idx = key_info->key[i].keyId;
1974 key_params.def_key_idx = key_info->key[i].keyId;
1975 } else
1976 key_params.key_idx = i;
1977
1978 key_params.key_len = key_info->key[i].keyLength;
1979 buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len,
1980 txrx_vdev->opmode);
1981 if (!buf) {
1982 WMA_LOGE("%s:Failed to setup install key buf",
1983 __func__);
1984 key_info->status = CDF_STATUS_E_NOMEM;
1985 goto out;
1986 }
1987
1988 WMA_LOGD("%s: peer unicast key[%d] %d ", __func__, i,
1989 key_info->key[i].keyLength);
1990
1991 status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
1992 WMI_VDEV_INSTALL_KEY_CMDID);
1993 if (status) {
1994 cdf_nbuf_free(buf);
1995 WMA_LOGE("%s:Failed to send install key command",
1996 __func__);
1997 key_info->status = CDF_STATUS_E_FAILURE;
1998 goto out;
1999 }
2000 }
2001
2002 /* In IBSS mode, set the BSS KEY for this peer
2003 * BSS key is supposed to be cache into wma_handle
2004 */
2005 if (wlan_op_mode_ibss == txrx_vdev->opmode) {
2006 wma_set_ibsskey_helper(wma_handle, &wma_handle->ibsskey_info,
2007 key_info->peerMacAddr);
2008 }
2009
2010 /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */
2011 key_info->status = CDF_STATUS_SUCCESS;
2012out:
2013 if (key_info->sendRsp)
2014 wma_send_msg(wma_handle, WMA_SET_STAKEY_RSP, (void *)key_info,
2015 0);
2016}
2017
2018/**
2019 * wma_process_update_edca_param_req() - update EDCA params
2020 * @handle: wma handle
2021 * @edca_params: edca parameters
2022 *
2023 * This function updates EDCA parameters to the target
2024 *
2025 * Return: CDF Status
2026 */
2027CDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle,
2028 tEdcaParams *edca_params)
2029{
2030 tp_wma_handle wma_handle = (tp_wma_handle) handle;
2031 uint8_t *buf_ptr;
2032 wmi_buf_t buf;
2033 wmi_vdev_set_wmm_params_cmd_fixed_param *cmd;
2034 wmi_wmm_vparams *wmm_param;
2035 tSirMacEdcaParamRecord *edca_record;
2036 int ac;
2037 int len = sizeof(*cmd);
2038 ol_txrx_pdev_handle pdev;
2039 struct ol_tx_wmm_param_t ol_tx_wmm_param;
2040
2041 buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
2042
2043 if (!buf) {
2044 WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
2045 return CDF_STATUS_E_NOMEM;
2046 }
2047
2048 buf_ptr = (uint8_t *) wmi_buf_data(buf);
2049 cmd = (wmi_vdev_set_wmm_params_cmd_fixed_param *) buf_ptr;
2050 WMITLV_SET_HDR(&cmd->tlv_header,
2051 WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param,
2052 WMITLV_GET_STRUCT_TLVLEN
2053 (wmi_vdev_set_wmm_params_cmd_fixed_param));
2054 cmd->vdev_id = edca_params->bssIdx;
2055
2056 for (ac = 0; ac < WME_NUM_AC; ac++) {
2057 wmm_param = (wmi_wmm_vparams *) (&cmd->wmm_params[ac]);
2058 WMITLV_SET_HDR(&wmm_param->tlv_header,
2059 WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param,
2060 WMITLV_GET_STRUCT_TLVLEN(wmi_wmm_vparams));
2061 switch (ac) {
2062 case WME_AC_BE:
2063 edca_record = &edca_params->acbe;
2064 break;
2065 case WME_AC_BK:
2066 edca_record = &edca_params->acbk;
2067 break;
2068 case WME_AC_VI:
2069 edca_record = &edca_params->acvi;
2070 break;
2071 case WME_AC_VO:
2072 edca_record = &edca_params->acvo;
2073 break;
2074 default:
2075 goto fail;
2076 }
2077
2078 wma_update_edca_params_for_ac(edca_record, wmm_param, ac);
2079
2080 ol_tx_wmm_param.ac[ac].aifs = wmm_param->aifs;
2081 ol_tx_wmm_param.ac[ac].cwmin = wmm_param->cwmin;
2082 ol_tx_wmm_param.ac[ac].cwmax = wmm_param->cwmax;
2083 }
2084
2085 if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
2086 WMI_VDEV_SET_WMM_PARAMS_CMDID))
2087 goto fail;
2088
2089 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
Himanshu Agarwal94045e42015-10-19 19:16:19 +05302090 if (pdev)
2091 ol_txrx_set_wmm_param(pdev, ol_tx_wmm_param);
2092 else
2093 CDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002094
2095 return CDF_STATUS_SUCCESS;
2096
2097fail:
2098 wmi_buf_free(buf);
2099 WMA_LOGE("%s: Failed to set WMM Paremeters", __func__);
2100 return CDF_STATUS_E_FAILURE;
2101}
2102
2103/**
2104 * wmi_unified_probe_rsp_tmpl_send() - send probe response template to fw
2105 * @wma: wma handle
2106 * @vdev_id: vdev id
2107 * @probe_rsp_info: probe response info
2108 *
2109 * Return: 0 for success or error code
2110 */
2111static int wmi_unified_probe_rsp_tmpl_send(tp_wma_handle wma,
2112 uint8_t vdev_id,
2113 tpSendProbeRespParams probe_rsp_info)
2114{
2115 wmi_prb_tmpl_cmd_fixed_param *cmd;
2116 wmi_bcn_prb_info *bcn_prb_info;
2117 wmi_buf_t wmi_buf;
2118 uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len;
2119 uint8_t *frm, *buf_ptr;
2120 int ret;
2121 uint64_t adjusted_tsf_le;
2122 struct ieee80211_frame *wh;
2123
2124 WMA_LOGD(FL("Send probe response template for vdev %d"), vdev_id);
2125
2126 frm = probe_rsp_info->pProbeRespTemplate;
2127 tmpl_len = probe_rsp_info->probeRespTemplateLen;
2128 tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32));
2129 /*
2130 * Make the TSF offset negative so probe response in the same
2131 * staggered batch have the same TSF.
2132 */
2133 adjusted_tsf_le = cpu_to_le64(0ULL -
2134 wma->interfaces[vdev_id].tsfadjust);
2135 /* Update the timstamp in the probe response buffer with adjusted TSF */
2136 wh = (struct ieee80211_frame *)frm;
2137 A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
2138
2139 wmi_buf_len = sizeof(wmi_prb_tmpl_cmd_fixed_param) +
2140 sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE +
2141 tmpl_len_aligned;
2142
2143 if (wmi_buf_len > BEACON_TX_BUFFER_SIZE) {
2144 WMA_LOGE(FL("wmi_buf_len: %d > %d. Can't send wmi cmd"),
2145 wmi_buf_len, BEACON_TX_BUFFER_SIZE);
2146 return -EINVAL;
2147 }
2148
2149 wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len);
2150 if (!wmi_buf) {
2151 WMA_LOGE(FL("wmi_buf_alloc failed"));
2152 return -ENOMEM;
2153 }
2154
2155 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
2156
2157 cmd = (wmi_prb_tmpl_cmd_fixed_param *) buf_ptr;
2158 WMITLV_SET_HDR(&cmd->tlv_header,
2159 WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param,
2160 WMITLV_GET_STRUCT_TLVLEN(wmi_prb_tmpl_cmd_fixed_param));
2161 cmd->vdev_id = vdev_id;
2162 cmd->buf_len = tmpl_len;
2163 buf_ptr += sizeof(wmi_prb_tmpl_cmd_fixed_param);
2164
2165 bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr;
2166 WMITLV_SET_HDR(&bcn_prb_info->tlv_header,
2167 WMITLV_TAG_STRUC_wmi_bcn_prb_info,
2168 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info));
2169 bcn_prb_info->caps = 0;
2170 bcn_prb_info->erp = 0;
2171 buf_ptr += sizeof(wmi_bcn_prb_info);
2172
2173 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned);
2174 buf_ptr += WMI_TLV_HDR_SIZE;
2175 cdf_mem_copy(buf_ptr, frm, tmpl_len);
2176
2177 ret = wmi_unified_cmd_send(wma->wmi_handle,
2178 wmi_buf, wmi_buf_len, WMI_PRB_TMPL_CMDID);
2179 if (ret) {
2180 WMA_LOGE(FL("Failed to send PRB RSP tmpl: %d"), ret);
2181 wmi_buf_free(wmi_buf);
2182 }
2183
2184 return ret;
2185}
2186
2187/**
2188 * wmi_unified_bcn_tmpl_send() - send beacon template to fw
2189 * @wma:wma handle
2190 * @vdev_id: vdev id
2191 * @bcn_info: beacon info
2192 * @bytes_to_strip: bytes to strip
2193 *
2194 * Return: 0 for success or error code
2195 */
2196static int wmi_unified_bcn_tmpl_send(tp_wma_handle wma,
2197 uint8_t vdev_id,
2198 tpSendbeaconParams bcn_info,
2199 uint8_t bytes_to_strip)
2200{
2201 wmi_bcn_tmpl_cmd_fixed_param *cmd;
2202 wmi_bcn_prb_info *bcn_prb_info;
2203 wmi_buf_t wmi_buf;
2204 uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len;
2205 uint8_t *frm, *buf_ptr;
2206 int ret;
2207 uint8_t *p2p_ie;
2208 uint16_t p2p_ie_len = 0;
2209 uint64_t adjusted_tsf_le;
2210 struct ieee80211_frame *wh;
2211
2212 WMA_LOGD("Send beacon template for vdev %d", vdev_id);
2213
2214 if (bcn_info->p2pIeOffset) {
2215 p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset;
2216 p2p_ie_len = (uint16_t) p2p_ie[1] + 2;
2217 }
2218
2219 /*
2220 * XXX: The first byte of beacon buffer contains beacon length
2221 * only when UMAC in sending the beacon template. In othercases
2222 * (ex: from tbtt update) beacon length is read from beacon
2223 * information.
2224 */
2225 if (bytes_to_strip)
2226 tmpl_len = *(uint32_t *) &bcn_info->beacon[0];
2227 else
2228 tmpl_len = bcn_info->beaconLength;
2229 if (p2p_ie_len) {
2230 tmpl_len -= (uint32_t) p2p_ie_len;
2231 }
2232
2233 frm = bcn_info->beacon + bytes_to_strip;
2234 tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32));
2235 /*
2236 * Make the TSF offset negative so beacons in the same
2237 * staggered batch have the same TSF.
2238 */
2239 adjusted_tsf_le = cpu_to_le64(0ULL -
2240 wma->interfaces[vdev_id].tsfadjust);
2241 /* Update the timstamp in the beacon buffer with adjusted TSF */
2242 wh = (struct ieee80211_frame *)frm;
2243 A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
2244
2245 wmi_buf_len = sizeof(wmi_bcn_tmpl_cmd_fixed_param) +
2246 sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE +
2247 tmpl_len_aligned;
2248
2249 wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len);
2250 if (!wmi_buf) {
2251 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
2252 return -ENOMEM;
2253 }
2254
2255 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
2256
2257 cmd = (wmi_bcn_tmpl_cmd_fixed_param *) buf_ptr;
2258 WMITLV_SET_HDR(&cmd->tlv_header,
2259 WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param,
2260 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_cmd_fixed_param));
2261 cmd->vdev_id = vdev_id;
2262 cmd->tim_ie_offset = bcn_info->timIeOffset - bytes_to_strip;
2263 cmd->buf_len = tmpl_len;
2264 buf_ptr += sizeof(wmi_bcn_tmpl_cmd_fixed_param);
2265
2266 bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr;
2267 WMITLV_SET_HDR(&bcn_prb_info->tlv_header,
2268 WMITLV_TAG_STRUC_wmi_bcn_prb_info,
2269 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info));
2270 bcn_prb_info->caps = 0;
2271 bcn_prb_info->erp = 0;
2272 buf_ptr += sizeof(wmi_bcn_prb_info);
2273
2274 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned);
2275 buf_ptr += WMI_TLV_HDR_SIZE;
2276 cdf_mem_copy(buf_ptr, frm, tmpl_len);
2277
2278 ret = wmi_unified_cmd_send(wma->wmi_handle,
2279 wmi_buf, wmi_buf_len, WMI_BCN_TMPL_CMDID);
2280 if (ret) {
2281 WMA_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret);
2282 wmi_buf_free(wmi_buf);
2283 }
2284
2285 return ret;
2286}
2287
2288/**
2289 * wma_store_bcn_tmpl() - store beacon template
2290 * @wma: wma handle
2291 * @vdev_id: vdev id
2292 * @bcn_info: beacon params
2293 *
2294 * This function stores beacon template locally.
2295 * This will send to target on the reception of
2296 * SWBA event.
2297 *
2298 * Return: CDF status
2299 */
2300CDF_STATUS wma_store_bcn_tmpl(tp_wma_handle wma, uint8_t vdev_id,
2301 tpSendbeaconParams bcn_info)
2302{
2303 struct beacon_info *bcn;
2304 uint32_t len;
2305 uint8_t *bcn_payload;
2306 struct beacon_tim_ie *tim_ie;
2307
2308 bcn = wma->interfaces[vdev_id].beacon;
2309 if (!bcn || !bcn->buf) {
2310 WMA_LOGE("%s: Memory is not allocated to hold bcn template",
2311 __func__);
2312 return CDF_STATUS_E_INVAL;
2313 }
2314
2315 len = *(u32 *) &bcn_info->beacon[0];
2316 if (len > WMA_BCN_BUF_MAX_SIZE) {
2317 WMA_LOGE("%s: Received beacon len %d exceeding max limit %d",
2318 __func__, len, WMA_BCN_BUF_MAX_SIZE);
2319 return CDF_STATUS_E_INVAL;
2320 }
2321 WMA_LOGD("%s: Storing received beacon template buf to local buffer",
2322 __func__);
2323 cdf_spin_lock_bh(&bcn->lock);
2324
2325 /*
2326 * Copy received beacon template content in local buffer.
2327 * this will be send to target on the reception of SWBA
2328 * event from target.
2329 */
2330 cdf_nbuf_trim_tail(bcn->buf, cdf_nbuf_len(bcn->buf));
2331 memcpy(cdf_nbuf_data(bcn->buf),
2332 bcn_info->beacon + 4 /* Exclude beacon length field */,
2333 len);
2334 if (bcn_info->timIeOffset > 3) {
2335 bcn->tim_ie_offset = bcn_info->timIeOffset - 4;
2336 } else {
2337 bcn->tim_ie_offset = bcn_info->timIeOffset;
2338 }
2339
2340 if (bcn_info->p2pIeOffset > 3) {
2341 bcn->p2p_ie_offset = bcn_info->p2pIeOffset - 4;
2342 } else {
2343 bcn->p2p_ie_offset = bcn_info->p2pIeOffset;
2344 }
2345 bcn_payload = cdf_nbuf_data(bcn->buf);
2346 if (bcn->tim_ie_offset) {
2347 tim_ie =
2348 (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]);
2349 /*
2350 * Intial Value of bcn->dtim_count will be 0.
2351 * But if the beacon gets updated then current dtim
2352 * count will be restored
2353 */
2354 tim_ie->dtim_count = bcn->dtim_count;
2355 tim_ie->tim_bitctl = 0;
2356 }
2357
2358 cdf_nbuf_put_tail(bcn->buf, len);
2359 bcn->len = len;
2360
2361 cdf_spin_unlock_bh(&bcn->lock);
2362
2363 return CDF_STATUS_SUCCESS;
2364}
2365
2366/**
2367 * wma_tbttoffset_update_event_handler() - tbtt offset update handler
2368 * @handle: wma handle
2369 * @event: event buffer
2370 * @len: data length
2371 *
2372 * Return: 0 for success or error code
2373 */
2374int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event,
2375 uint32_t len)
2376{
2377 tp_wma_handle wma = (tp_wma_handle) handle;
2378 WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf;
2379 wmi_tbtt_offset_event_fixed_param *tbtt_offset_event;
2380 struct wma_txrx_node *intf;
2381 struct beacon_info *bcn;
2382 tSendbeaconParams bcn_info;
2383 uint32_t *adjusted_tsf = NULL;
2384 uint32_t if_id = 0, vdev_map;
2385
2386 if (!wma) {
2387 WMA_LOGE("Invalid wma handle");
2388 return -EINVAL;
2389 }
2390
2391 param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) event;
2392 if (!param_buf) {
2393 WMA_LOGE("Invalid tbtt update event buffer");
2394 return -EINVAL;
2395 }
2396
2397 tbtt_offset_event = param_buf->fixed_param;
2398 intf = wma->interfaces;
2399 vdev_map = tbtt_offset_event->vdev_map;
2400 adjusted_tsf = param_buf->tbttoffset_list;
2401 if (!adjusted_tsf) {
2402 WMA_LOGE("%s: Invalid adjusted_tsf", __func__);
2403 return -EINVAL;
2404 }
2405
2406 for (; (vdev_map); vdev_map >>= 1, if_id++) {
2407 if (!(vdev_map & 0x1) || (!(intf[if_id].handle)))
2408 continue;
2409
2410 bcn = intf[if_id].beacon;
2411 if (!bcn) {
2412 WMA_LOGE("%s: Invalid beacon", __func__);
2413 return -EINVAL;
2414 }
2415 if (!bcn->buf) {
2416 WMA_LOGE("%s: Invalid beacon buffer", __func__);
2417 return -EINVAL;
2418 }
2419 /* Save the adjusted TSF */
2420 intf[if_id].tsfadjust = adjusted_tsf[if_id];
2421
2422 cdf_spin_lock_bh(&bcn->lock);
2423 cdf_mem_zero(&bcn_info, sizeof(bcn_info));
2424 bcn_info.beacon = cdf_nbuf_data(bcn->buf);
2425 bcn_info.p2pIeOffset = bcn->p2p_ie_offset;
2426 bcn_info.beaconLength = bcn->len;
2427 bcn_info.timIeOffset = bcn->tim_ie_offset;
2428 cdf_spin_unlock_bh(&bcn->lock);
2429
2430 /* Update beacon template in firmware */
2431 wmi_unified_bcn_tmpl_send(wma, if_id, &bcn_info, 0);
2432 }
2433 return 0;
2434}
2435
2436/**
2437 * wma_p2p_go_set_beacon_ie() - set beacon IE for p2p go
2438 * @wma_handle: wma handle
2439 * @vdev_id: vdev id
2440 * @p2pIe: p2p IE
2441 *
2442 * Return: 0 for success or error code
2443 */
2444static int wma_p2p_go_set_beacon_ie(t_wma_handle *wma_handle,
2445 A_UINT32 vdev_id, uint8_t *p2pIe)
2446{
2447 int ret;
2448 wmi_p2p_go_set_beacon_ie_fixed_param *cmd;
2449 wmi_buf_t wmi_buf;
2450 uint32_t ie_len, ie_len_aligned, wmi_buf_len;
2451 uint8_t *buf_ptr;
2452
2453 ie_len = (uint32_t) (p2pIe[1] + 2);
2454
2455 /* More than one P2P IE may be included in a single frame.
2456 If multiple P2P IEs are present, the complete P2P attribute
2457 data consists of the concatenation of the P2P Attribute
2458 fields of the P2P IEs. The P2P Attributes field of each
2459 P2P IE may be any length up to the maximum (251 octets).
2460 In this case host sends one P2P IE to firmware so the length
2461 should not exceed more than 251 bytes
2462 */
2463 if (ie_len > 251) {
2464 WMA_LOGE("%s : invalid p2p ie length %u", __func__, ie_len);
2465 return -EINVAL;
2466 }
2467
2468 ie_len_aligned = roundup(ie_len, sizeof(A_UINT32));
2469
2470 wmi_buf_len =
2471 sizeof(wmi_p2p_go_set_beacon_ie_fixed_param) + ie_len_aligned +
2472 WMI_TLV_HDR_SIZE;
2473
2474 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, wmi_buf_len);
2475 if (!wmi_buf) {
2476 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
2477 return -ENOMEM;
2478 }
2479
2480 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
2481
2482 cmd = (wmi_p2p_go_set_beacon_ie_fixed_param *) buf_ptr;
2483 WMITLV_SET_HDR(&cmd->tlv_header,
2484 WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param,
2485 WMITLV_GET_STRUCT_TLVLEN
2486 (wmi_p2p_go_set_beacon_ie_fixed_param));
2487 cmd->vdev_id = vdev_id;
2488 cmd->ie_buf_len = ie_len;
2489
2490 buf_ptr += sizeof(wmi_p2p_go_set_beacon_ie_fixed_param);
2491 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned);
2492 buf_ptr += WMI_TLV_HDR_SIZE;
2493 cdf_mem_copy(buf_ptr, p2pIe, ie_len);
2494
2495 WMA_LOGI("%s: Sending WMI_P2P_GO_SET_BEACON_IE", __func__);
2496
2497 ret = wmi_unified_cmd_send(wma_handle->wmi_handle,
2498 wmi_buf, wmi_buf_len,
2499 WMI_P2P_GO_SET_BEACON_IE);
2500 if (ret) {
2501 WMA_LOGE("Failed to send bcn tmpl: %d", ret);
2502 wmi_buf_free(wmi_buf);
2503 }
2504
2505 WMA_LOGI("%s: Successfully sent WMI_P2P_GO_SET_BEACON_IE", __func__);
2506 return ret;
2507}
2508
2509/**
2510 * wma_send_probe_rsp_tmpl() - send probe resp template
2511 * @wma: wma handle
2512 * @probe_rsp_info: probe response info
2513 *
2514 * This funciton sends probe response template to fw which
2515 * firmware will use in case of probe response offload.
2516 *
2517 * Return: none
2518 */
2519void wma_send_probe_rsp_tmpl(tp_wma_handle wma,
2520 tpSendProbeRespParams probe_rsp_info)
2521{
2522 ol_txrx_vdev_handle vdev;
2523 uint8_t vdev_id;
2524 tpAniProbeRspStruct probe_rsp;
2525
2526 if (!probe_rsp_info) {
2527 WMA_LOGE(FL("probe_rsp_info is NULL"));
2528 return;
2529 }
2530
2531 probe_rsp = (tpAniProbeRspStruct) (probe_rsp_info->pProbeRespTemplate);
2532 if (!probe_rsp) {
2533 WMA_LOGE(FL("probe_rsp is NULL"));
2534 return;
2535 }
2536
2537 vdev = wma_find_vdev_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id);
2538 if (!vdev) {
2539 WMA_LOGE(FL("failed to get vdev handle"));
2540 return;
2541 }
2542
2543 if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2544 WMI_SERVICE_BEACON_OFFLOAD)) {
2545 WMA_LOGI("Beacon Offload Enabled Sending Unified command");
2546 if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id,
2547 probe_rsp_info) < 0) {
2548 WMA_LOGE(FL("wmi_unified_probe_rsp_tmpl_send Failed "));
2549 return;
2550 }
2551 }
2552}
2553
2554/**
2555 * wma_send_beacon() - send beacon template
2556 * @wma: wma handle
2557 * @bcn_info: beacon info
2558 *
2559 * This funciton store beacon template locally and
2560 * update keep alive parameters
2561 *
2562 * Return: none
2563 */
2564void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info)
2565{
2566 ol_txrx_vdev_handle vdev;
2567 uint8_t vdev_id;
2568 CDF_STATUS status;
2569 uint8_t *p2p_ie;
2570 tpAniBeaconStruct beacon;
2571
2572 beacon = (tpAniBeaconStruct) (bcn_info->beacon);
2573 vdev = wma_find_vdev_by_addr(wma, beacon->macHdr.sa, &vdev_id);
2574 if (!vdev) {
2575 WMA_LOGE("%s : failed to get vdev handle", __func__);
2576 return;
2577 }
2578
2579 if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2580 WMI_SERVICE_BEACON_OFFLOAD)) {
2581 WMA_LOGI("Beacon Offload Enabled Sending Unified command");
2582 if (wmi_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4) < 0) {
2583 WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ",
2584 __func__);
2585 return;
2586 }
2587
2588 if (bcn_info->p2pIeOffset) {
2589 p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset;
2590 WMA_LOGI
2591 (" %s: p2pIe is present - vdev_id %hu, p2p_ie = %p, p2p ie len = %hu",
2592 __func__, vdev_id, p2p_ie, p2p_ie[1]);
2593 if (wma_p2p_go_set_beacon_ie(wma, vdev_id, p2p_ie) < 0) {
2594 WMA_LOGE
2595 ("%s : wmi_unified_bcn_tmpl_send Failed ",
2596 __func__);
2597 return;
2598 }
2599 }
2600 }
2601 status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info);
2602 if (status != CDF_STATUS_SUCCESS) {
2603 WMA_LOGE("%s : wma_store_bcn_tmpl Failed", __func__);
2604 return;
2605 }
2606 if (!wma->interfaces[vdev_id].vdev_up) {
2607 if (wmi_unified_vdev_up_send(wma->wmi_handle, vdev_id, 0,
2608 bcn_info->bssId) < 0) {
2609 WMA_LOGE("%s : failed to send vdev up", __func__);
2610 return;
2611 }
2612 wma->interfaces[vdev_id].vdev_up = true;
2613 wma_set_sap_keepalive(wma, vdev_id);
2614 }
2615}
2616
2617/**
2618 * wma_set_keepalive_req() - send keep alive request to fw
2619 * @wma: wma handle
2620 * @keepalive: keep alive parameters
2621 *
2622 * Return: none
2623 */
2624void wma_set_keepalive_req(tp_wma_handle wma,
2625 tSirKeepAliveReq *keepalive)
2626{
2627 WMA_LOGD("KEEPALIVE:PacketType:%d", keepalive->packetType);
2628 wma_set_sta_keep_alive(wma, keepalive->sessionId,
2629 keepalive->packetType,
2630 keepalive->timePeriod,
2631 keepalive->hostIpv4Addr,
Srinivas Girigowda9c330a92015-11-24 12:28:25 -08002632 keepalive->destIpv4Addr,
2633 keepalive->dest_macaddr.bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002634
2635 cdf_mem_free(keepalive);
2636}
2637
2638/**
2639 * wma_beacon_miss_handler() - beacon miss event handler
2640 * @wma: wma handle
2641 * @vdev_id: vdev id
2642 *
2643 * This function send beacon miss indication to upper layers.
2644 *
2645 * Return: none
2646 */
2647void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id)
2648{
2649 tSirSmeMissedBeaconInd *beacon_miss_ind;
2650
2651 beacon_miss_ind = (tSirSmeMissedBeaconInd *) cdf_mem_malloc
2652 (sizeof(tSirSmeMissedBeaconInd));
2653
2654 if (NULL == beacon_miss_ind) {
2655 WMA_LOGE("%s: Memory allocation failure", __func__);
2656 return;
2657 }
2658 beacon_miss_ind->messageType = WMA_MISSED_BEACON_IND;
2659 beacon_miss_ind->length = sizeof(tSirSmeMissedBeaconInd);
2660 beacon_miss_ind->bssIdx = vdev_id;
2661
2662 wma_send_msg(wma, WMA_MISSED_BEACON_IND, (void *)beacon_miss_ind, 0);
2663}
2664
2665/**
2666 * wma_mgmt_tx_completion_handler() - wma mgmt Tx completion event handler
2667 * @handle: wma handle
2668 * @cmpl_event_params: completion event handler data
2669 * @len: length of @cmpl_event_params
2670 *
2671 * Return: 0 on success; error number otherwise
2672 */
2673
2674int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params,
2675 uint32_t len)
2676{
2677 tp_wma_handle wma_handle = (tp_wma_handle)handle;
2678 WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf;
2679 wmi_mgmt_tx_compl_event_fixed_param *cmpl_params;
2680 struct wmi_desc_t *wmi_desc;
2681
2682 ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX);
2683
2684 param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *)
2685 cmpl_event_params;
2686 if (!param_buf && !wma_handle) {
2687 WMA_LOGE("%s: Invalid mgmt Tx completion event", __func__);
2688 return -EINVAL;
2689 }
2690 cmpl_params = param_buf->fixed_param;
2691
2692 WMA_LOGI("%s: status:%d wmi_desc_id:%d", __func__, cmpl_params->status,
2693 cmpl_params->desc_id);
2694
2695 wmi_desc = (struct wmi_desc_t *)
2696 (&wma_handle->wmi_desc_pool.array[cmpl_params->desc_id]);
2697
2698 if (!wmi_desc) {
2699 WMA_LOGE("%s: Invalid wmi desc", __func__);
2700 return -EINVAL;
2701 }
2702
2703 if (wmi_desc->nbuf)
2704 cdf_nbuf_unmap_single(pdev->osdev, wmi_desc->nbuf,
2705 CDF_DMA_TO_DEVICE);
2706 if (wmi_desc->tx_cmpl_cb)
2707 wmi_desc->tx_cmpl_cb(wma_handle->mac_context,
2708 wmi_desc->nbuf, 1);
2709
2710 if (wmi_desc->ota_post_proc_cb)
2711 wmi_desc->ota_post_proc_cb((tpAniSirGlobal)
2712 wma_handle->mac_context,
2713 cmpl_params->status);
2714
2715 wmi_desc_put(wma_handle, wmi_desc);
2716
2717 return 0;
2718}
2719
2720/**
2721 * wma_process_update_opmode() - process update VHT opmode cmd from UMAC
2722 * @wma_handle: wma handle
2723 * @update_vht_opmode: vht opmode
2724 *
2725 * Return: none
2726 */
2727void wma_process_update_opmode(tp_wma_handle wma_handle,
2728 tUpdateVHTOpMode *update_vht_opmode)
2729{
2730 WMA_LOGD("%s: opMode = %d", __func__, update_vht_opmode->opMode);
2731
2732 wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
2733 WMI_PEER_CHWIDTH, update_vht_opmode->opMode,
2734 update_vht_opmode->smesessionId);
2735}
2736
2737/**
2738 * wma_process_update_rx_nss() - process update RX NSS cmd from UMAC
2739 * @wma_handle: wma handle
2740 * @update_rx_nss: rx nss value
2741 *
2742 * Return: none
2743 */
2744void wma_process_update_rx_nss(tp_wma_handle wma_handle,
2745 tUpdateRxNss *update_rx_nss)
2746{
2747 struct wma_txrx_node *intr =
2748 &wma_handle->interfaces[update_rx_nss->smesessionId];
2749 int rx_nss = update_rx_nss->rxNss;
2750
2751 wma_update_txrx_chainmask(wma_handle->num_rf_chains, &rx_nss);
2752
2753 intr->nss = (uint8_t)rx_nss;
2754 update_rx_nss->rxNss = (uint32_t)rx_nss;
2755
2756 WMA_LOGD("%s: Rx Nss = %d", __func__, update_rx_nss->rxNss);
2757
2758 wma_set_peer_param(wma_handle, update_rx_nss->peer_mac,
2759 WMI_PEER_NSS, update_rx_nss->rxNss,
2760 update_rx_nss->smesessionId);
2761}
2762
2763#ifdef WLAN_FEATURE_11AC
2764/**
2765 * wma_process_update_membership() - process update group membership cmd
2766 * @wma_handle: wma handle
2767 * @membership: group membership info
2768 *
2769 * Return: none
2770 */
2771void wma_process_update_membership(tp_wma_handle wma_handle,
2772 tUpdateMembership *membership)
2773{
2774 WMA_LOGD("%s: membership = %x ", __func__, membership->membership);
2775
2776 wma_set_peer_param(wma_handle, membership->peer_mac,
2777 WMI_PEER_MEMBERSHIP, membership->membership,
2778 membership->smesessionId);
2779}
2780
2781/**
2782 * wma_process_update_userpos() - process update user pos cmd from UMAC
2783 * @wma_handle: wma handle
2784 * @userpos: user pos value
2785 *
2786 * Return: none
2787 */
2788void wma_process_update_userpos(tp_wma_handle wma_handle,
2789 tUpdateUserPos *userpos)
2790{
2791 WMA_LOGD("%s: userPos = %x ", __func__, userpos->userPos);
2792
2793 wma_set_peer_param(wma_handle, userpos->peer_mac,
2794 WMI_PEER_USERPOS, userpos->userPos,
2795 userpos->smesessionId);
2796
2797 /* Now that membership/userpos is updated in fw,
2798 * enable GID PPS.
2799 */
2800 wma_set_ppsconfig(userpos->smesessionId, WMA_VHT_PPS_GID_MATCH, 1);
2801
2802}
2803#endif /* WLAN_FEATURE_11AC */
2804
2805/**
2806 * wma_set_htconfig() - set ht config parameters to target
2807 * @vdev_id: vdev id
2808 * @ht_capab: ht capablity
2809 * @value: value of ht param
2810 *
2811 * Return: CDF status
2812 */
2813CDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value)
2814{
2815 tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA);
2816 int ret = -EIO;
2817
2818 if (NULL == wma) {
2819 WMA_LOGE("%s: Failed to get wma", __func__);
2820 return CDF_STATUS_E_INVAL;
2821 }
2822
2823 switch (ht_capab) {
2824 case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING:
2825 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2826 WMI_VDEV_PARAM_LDPC,
2827 value);
2828 break;
2829 case WNI_CFG_HT_CAP_INFO_TX_STBC:
2830 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2831 WMI_VDEV_PARAM_TX_STBC,
2832 value);
2833 break;
2834 case WNI_CFG_HT_CAP_INFO_RX_STBC:
2835 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2836 WMI_VDEV_PARAM_RX_STBC,
2837 value);
2838 break;
2839 case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ:
2840 case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ:
2841 WMA_LOGE("%s: ht_capab = %d, value = %d", __func__, ht_capab,
2842 value);
2843 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2844 WMI_VDEV_PARAM_SGI, value);
2845 if (ret == 0)
2846 wma->interfaces[vdev_id].config.shortgi = value;
2847 break;
2848 default:
2849 WMA_LOGE("%s:INVALID HT CONFIG", __func__);
2850 }
2851
2852 return (ret) ? CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS;
2853}
2854
2855/**
2856 * wma_hidden_ssid_vdev_restart() - vdev restart for hidden ssid
2857 * @wma_handle: wma handle
2858 * @pReq: hidden ssid vdev restart request
2859 *
2860 * Return: none
2861 */
2862void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle,
2863 tHalHiddenSsidVdevRestart *pReq)
2864{
2865 struct wma_txrx_node *intr = wma_handle->interfaces;
2866
2867 if ((pReq->sessionId !=
2868 intr[pReq->sessionId].vdev_restart_params.vdev_id)
2869 || !((intr[pReq->sessionId].type == WMI_VDEV_TYPE_AP)
2870 && (intr[pReq->sessionId].sub_type == 0))) {
2871 WMA_LOGE("%s : invalid session id", __func__);
2872 return;
2873 }
2874
2875 intr[pReq->sessionId].vdev_restart_params.ssidHidden = pReq->ssidHidden;
2876 cdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params.
2877 hidden_ssid_restart_in_progress, 1);
2878
2879 /* vdev stop -> vdev restart -> vdev up */
2880 WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP",
2881 __func__, pReq->sessionId);
2882 ol_txrx_vdev_pause(wma_handle->interfaces[pReq->sessionId].handle,
2883 OL_TXQ_PAUSE_REASON_VDEV_STOP);
2884 wma_handle->interfaces[pReq->sessionId].pause_bitmap |=
2885 (1 << PAUSE_TYPE_HOST);
2886 if (wmi_unified_vdev_stop_send(wma_handle->wmi_handle, pReq->sessionId)) {
2887 WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__);
2888 cdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params.
2889 hidden_ssid_restart_in_progress, 0);
2890 return;
2891 }
2892}
2893
2894
2895#ifdef WLAN_FEATURE_11W
2896
2897/**
2898 * wma_extract_ccmp_pn() - extract 6 byte PN from the CCMP header
2899 * @ccmp_ptr: CCMP header
2900 *
2901 * Return: PN extracted from header.
2902 */
2903static uint64_t wma_extract_ccmp_pn(uint8_t *ccmp_ptr)
2904{
2905 uint8_t rsvd, key, pn[6];
2906 uint64_t new_pn;
2907
2908 /*
2909 * +-----+-----+------+----------+-----+-----+-----+-----+
2910 * | PN0 | PN1 | rsvd | rsvd/key | PN2 | PN3 | PN4 | PN5 |
2911 * +-----+-----+------+----------+-----+-----+-----+-----+
2912 * CCMP Header Format
2913 */
2914
2915 /* Extract individual bytes */
2916 pn[0] = (uint8_t) *ccmp_ptr;
2917 pn[1] = (uint8_t) *(ccmp_ptr + 1);
2918 rsvd = (uint8_t) *(ccmp_ptr + 2);
2919 key = (uint8_t) *(ccmp_ptr + 3);
2920 pn[2] = (uint8_t) *(ccmp_ptr + 4);
2921 pn[3] = (uint8_t) *(ccmp_ptr + 5);
2922 pn[4] = (uint8_t) *(ccmp_ptr + 6);
2923 pn[5] = (uint8_t) *(ccmp_ptr + 7);
2924
2925 /* Form 6 byte PN with 6 individual bytes of PN */
2926 new_pn = ((uint64_t) pn[5] << 40) |
2927 ((uint64_t) pn[4] << 32) |
2928 ((uint64_t) pn[3] << 24) |
2929 ((uint64_t) pn[2] << 16) |
2930 ((uint64_t) pn[1] << 8) | ((uint64_t) pn[0] << 0);
2931
2932 WMA_LOGE("PN of received packet is %llu", new_pn);
2933 return new_pn;
2934}
2935
2936/**
2937 * wma_is_ccmp_pn_replay_attack() - detect replay attacking using PN in CCMP
2938 * @cds_ctx: cds context
2939 * @wh: 802.11 frame header
2940 * @ccmp_ptr: CCMP frame header
2941 *
2942 * Return: true/false
2943 */
2944static bool
2945wma_is_ccmp_pn_replay_attack(void *cds_ctx, struct ieee80211_frame *wh,
2946 uint8_t *ccmp_ptr)
2947{
2948 ol_txrx_pdev_handle pdev;
2949 ol_txrx_vdev_handle vdev;
2950 ol_txrx_peer_handle peer;
2951 uint8_t vdev_id, peer_id;
2952 uint8_t *last_pn_valid;
2953 uint64_t *last_pn, new_pn;
2954 uint32_t *rmf_pn_replays;
2955
2956 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
2957 if (!pdev) {
2958 WMA_LOGE("%s: Failed to find pdev", __func__);
2959 return true;
2960 }
2961
Mukul Sharmaa748fbb2015-12-01 19:51:36 +05302962 vdev = wma_find_vdev_by_bssid(cds_ctx, wh->i_addr3, &vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002963 if (!vdev) {
2964 WMA_LOGE("%s: Failed to find vdev", __func__);
2965 return true;
2966 }
2967
2968 /* Retrieve the peer based on vdev and addr */
2969 peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, wh->i_addr2,
2970 &peer_id);
2971
2972 if (NULL == peer) {
2973 WMA_LOGE("%s: Failed to find peer, Not able to validate PN",
2974 __func__);
2975 return true;
2976 }
2977
2978 new_pn = wma_extract_ccmp_pn(ccmp_ptr);
2979 last_pn_valid = &peer->last_rmf_pn_valid;
2980 last_pn = &peer->last_rmf_pn;
2981 rmf_pn_replays = &peer->rmf_pn_replays;
2982
2983 if (*last_pn_valid) {
2984 if (new_pn > *last_pn) {
2985 *last_pn = new_pn;
2986 WMA_LOGE("%s: PN validation successful", __func__);
2987 } else {
2988 WMA_LOGE("%s: PN Replay attack detected", __func__);
2989 /* per 11W amendment, keeping track of replay attacks */
2990 *rmf_pn_replays += 1;
2991 return true;
2992 }
2993 } else {
2994 *last_pn_valid = 1;
2995 *last_pn = new_pn;
2996 }
2997
2998 return false;
2999}
3000
3001/**
mukul sharma72c8b222015-09-04 17:02:01 +05303002 * wma_process_bip() - process mmie in rmf frame
3003 * @wma_handle: wma handle
3004 * @iface: txrx node
3005 * @wh: 80211 frame
3006 * @wbuf: Buffer
3007 *
3008 * Return: 0 for success or error code
3009 */
3010
3011static
3012int wma_process_bip(tp_wma_handle wma_handle,
3013 struct wma_txrx_node *iface,
3014 struct ieee80211_frame *wh,
3015 cdf_nbuf_t wbuf
3016)
3017{
3018 uint16_t key_id;
3019 uint8_t *efrm;
3020
3021 efrm = cdf_nbuf_data(wbuf) + cdf_nbuf_len(wbuf);
3022 key_id = (uint16_t)*(efrm - cds_get_mmie_size() + 2);
3023
3024 if (!((key_id == WMA_IGTK_KEY_INDEX_4)
3025 || (key_id == WMA_IGTK_KEY_INDEX_5))) {
3026 WMA_LOGE(FL("Invalid KeyID(%d) dropping the frame"), key_id);
3027 return -EINVAL;
3028 }
3029 if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
3030 WMI_SERVICE_STA_PMF_OFFLOAD)) {
3031 /*
3032 * if 11w offload is enabled then mmie validation is performed
3033 * in firmware, host just need to trim the mmie.
3034 */
3035 cdf_nbuf_trim_tail(wbuf, cds_get_mmie_size());
3036 } else {
3037 if (cds_is_mmie_valid(iface->key.key,
3038 iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn,
3039 (uint8_t *) wh, efrm)) {
3040 WMA_LOGE(FL("Protected BC/MC frame MMIE validation successful"));
3041 /* Remove MMIE */
3042 cdf_nbuf_trim_tail(wbuf, cds_get_mmie_size());
3043 } else {
3044 WMA_LOGE(FL("BC/MC MIC error or MMIE not present, dropping the frame"));
3045 return -EINVAL;
3046 }
3047 }
3048 return 0;
3049}
3050
3051/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003052 * wma_process_rmf_frame() - process rmf frame
3053 * @wma_handle: wma handle
3054 * @iface: txrx node
3055 * @wh: 80211 frame
3056 * @rx_pkt: rx packet
3057 * @wbuf: Buffer
3058 *
3059 * Return: 0 for success or error code
3060 */
3061static
3062int wma_process_rmf_frame(tp_wma_handle wma_handle,
3063 struct wma_txrx_node *iface,
3064 struct ieee80211_frame *wh,
3065 cds_pkt_t *rx_pkt,
3066 cdf_nbuf_t wbuf)
3067{
mukul sharma72c8b222015-09-04 17:02:01 +05303068 uint8_t *orig_hdr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003069 uint8_t *ccmp;
3070
3071 if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) {
3072 if (IEEE80211_IS_BROADCAST(wh->i_addr1) ||
3073 IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3074 WMA_LOGE("Encrypted BC/MC frame dropping the frame");
3075 cds_pkt_return_packet(rx_pkt);
3076 return -EINVAL;
3077 }
3078
3079 orig_hdr = (uint8_t *) cdf_nbuf_data(wbuf);
3080 /* Pointer to head of CCMP header */
3081 ccmp = orig_hdr + sizeof(*wh);
3082 if (wma_is_ccmp_pn_replay_attack(
3083 wma_handle, wh, ccmp)) {
3084 WMA_LOGE("Dropping the frame");
3085 cds_pkt_return_packet(rx_pkt);
3086 return -EINVAL;
3087 }
3088
3089 /* Strip privacy headers (and trailer)
3090 * for a received frame
3091 */
3092 cdf_mem_move(orig_hdr +
3093 IEEE80211_CCMP_HEADERLEN, wh,
3094 sizeof(*wh));
3095 cdf_nbuf_pull_head(wbuf,
3096 IEEE80211_CCMP_HEADERLEN);
3097 cdf_nbuf_trim_tail(wbuf, IEEE80211_CCMP_MICLEN);
3098
3099 rx_pkt->pkt_meta.mpdu_hdr_ptr =
3100 cdf_nbuf_data(wbuf);
3101 rx_pkt->pkt_meta.mpdu_len = cdf_nbuf_len(wbuf);
3102 rx_pkt->pkt_meta.mpdu_data_len =
3103 rx_pkt->pkt_meta.mpdu_len -
3104 rx_pkt->pkt_meta.mpdu_hdr_len;
3105 rx_pkt->pkt_meta.mpdu_data_ptr =
3106 rx_pkt->pkt_meta.mpdu_hdr_ptr +
3107 rx_pkt->pkt_meta.mpdu_hdr_len;
3108 rx_pkt->pkt_meta.tsf_delta = rx_pkt->pkt_meta.tsf_delta;
3109 rx_pkt->pkt_buf = wbuf;
3110 WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"),
3111 MAC_ADDR_ARRAY(wh->i_addr3), rx_pkt->pkt_meta.tsf_delta);
3112 } else {
3113 if (IEEE80211_IS_BROADCAST(wh->i_addr1) ||
3114 IEEE80211_IS_MULTICAST(wh->i_addr1)) {
mukul sharma72c8b222015-09-04 17:02:01 +05303115 if (0 != wma_process_bip(wma_handle, iface, wh, wbuf)) {
3116 cds_pkt_return_packet(rx_pkt);
3117 return -EINVAL;
Mukul Sharmaa748fbb2015-12-01 19:51:36 +05303118 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003119 } else {
3120 WMA_LOGE("Rx unprotected unicast mgmt frame");
3121 rx_pkt->pkt_meta.dpuFeedback =
3122 DPU_FEEDBACK_UNPROTECTED_ERROR;
3123 }
3124 }
3125 return 0;
3126}
3127#endif
3128
3129/**
3130 * wma_mgmt_rx_process() - process management rx frame.
3131 * @handle: wma handle
3132 * @data: rx data
3133 * @data_len: data length
3134 *
3135 * Return: 0 for success or error code
3136 */
3137static int wma_mgmt_rx_process(void *handle, uint8_t *data,
3138 uint32_t data_len)
3139{
3140 tp_wma_handle wma_handle = (tp_wma_handle) handle;
3141 WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL;
3142 wmi_mgmt_rx_hdr *hdr = NULL;
3143 struct wma_txrx_node *iface = NULL;
Mukul Sharmaa748fbb2015-12-01 19:51:36 +05303144 uint8_t vdev_id = WMA_INVALID_VDEV_ID;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003145 cds_pkt_t *rx_pkt;
3146 cdf_nbuf_t wbuf;
3147 struct ieee80211_frame *wh;
3148 uint8_t mgt_type, mgt_subtype;
3149 int status;
3150
3151 if (!wma_handle) {
3152 WMA_LOGE("%s: Failed to get WMA context", __func__);
3153 return -EINVAL;
3154 }
3155
3156 param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) data;
3157 if (!param_tlvs) {
3158 WMA_LOGE("Get NULL point message from FW");
3159 return -EINVAL;
3160 }
3161
3162 hdr = param_tlvs->hdr;
3163 if (!hdr) {
3164 WMA_LOGE("Rx event is NULL");
3165 return -EINVAL;
3166 }
3167
3168 if (hdr->buf_len < sizeof(struct ieee80211_frame)) {
3169 WMA_LOGE("Invalid rx mgmt packet");
3170 return -EINVAL;
3171 }
3172
3173 rx_pkt = cdf_mem_malloc(sizeof(*rx_pkt));
3174 if (!rx_pkt) {
3175 WMA_LOGE("Failed to allocate rx packet");
3176 return -ENOMEM;
3177 }
3178
Naveen Rawat10ccf872015-11-03 14:15:55 -08003179 if (cds_is_load_unload_in_progress()) {
3180 WMA_LOGE("Load/Unload in progress");
3181 return -EINVAL;
3182 }
3183
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003184 cdf_mem_zero(rx_pkt, sizeof(*rx_pkt));
3185
3186 /*
3187 * Fill in meta information needed by pe/lim
3188 * TODO: Try to maintain rx metainfo as part of skb->data.
3189 */
3190 rx_pkt->pkt_meta.channel = hdr->channel;
3191 rx_pkt->pkt_meta.scan_src = hdr->flags;
3192 /*Get the absolute rssi value from the current rssi value
3193 *the sinr value is hardcoded into 0 in the core stack*/
3194 rx_pkt->pkt_meta.rssi = hdr->snr + WMA_TGT_NOISE_FLOOR_DBM;
3195 rx_pkt->pkt_meta.snr = hdr->snr;
3196 /*
3197 * FIXME: Assigning the local timestamp as hw timestamp is not
3198 * available. Need to see if pe/lim really uses this data.
3199 */
3200 rx_pkt->pkt_meta.timestamp = (uint32_t) jiffies;
3201 rx_pkt->pkt_meta.mpdu_hdr_len = sizeof(struct ieee80211_frame);
3202 rx_pkt->pkt_meta.mpdu_len = hdr->buf_len;
3203 rx_pkt->pkt_meta.mpdu_data_len = hdr->buf_len -
3204 rx_pkt->pkt_meta.mpdu_hdr_len;
3205
3206 rx_pkt->pkt_meta.roamCandidateInd = 0;
3207
3208 /* Why not just use rx_event->hdr.buf_len? */
3209 wbuf = cdf_nbuf_alloc(NULL, roundup(hdr->buf_len, 4), 0, 4, false);
3210 if (!wbuf) {
3211 WMA_LOGE("%s: Failed to allocate wbuf for mgmt rx len(%u)",
3212 __func__, hdr->buf_len);
3213 cdf_mem_free(rx_pkt);
3214 return -ENOMEM;
3215 }
3216
3217 cdf_nbuf_put_tail(wbuf, hdr->buf_len);
3218 cdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL);
3219 wh = (struct ieee80211_frame *)cdf_nbuf_data(wbuf);
3220
3221 rx_pkt->pkt_meta.mpdu_hdr_ptr = cdf_nbuf_data(wbuf);
3222 rx_pkt->pkt_meta.mpdu_data_ptr = rx_pkt->pkt_meta.mpdu_hdr_ptr +
3223 rx_pkt->pkt_meta.mpdu_hdr_len;
3224 rx_pkt->pkt_meta.tsf_delta = hdr->tsf_delta;
3225 rx_pkt->pkt_buf = wbuf;
3226
3227 WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"),
3228 MAC_ADDR_ARRAY(wh->i_addr3), hdr->tsf_delta);
3229
3230#ifdef BIG_ENDIAN_HOST
3231 {
3232 /*
3233 * for big endian host, copy engine byte_swap is enabled
3234 * But the rx mgmt frame buffer content is in network byte order
3235 * Need to byte swap the mgmt frame buffer content - so when
3236 * copy engine does byte_swap - host gets buffer content in the
3237 * correct byte order.
3238 */
3239 int i;
3240 uint32_t *destp, *srcp;
3241 destp = (uint32_t *) wh;
3242 srcp = (uint32_t *) param_tlvs->bufp;
3243 for (i = 0;
3244 i < (roundup(hdr->buf_len, sizeof(uint32_t)) / 4); i++) {
3245 *destp = cpu_to_le32(*srcp);
3246 destp++;
3247 srcp++;
3248 }
3249 }
3250#else
3251 cdf_mem_copy(wh, param_tlvs->bufp, hdr->buf_len);
3252#endif
3253
3254 if (!wma_handle->mgmt_rx) {
3255 WMA_LOGE("Not registered for Mgmt rx, dropping the frame");
3256 cds_pkt_return_packet(rx_pkt);
3257 return -EINVAL;
3258 }
3259
3260 /* If it is a beacon/probe response, save it for future use */
3261 mgt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3262 mgt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
3263
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003264#ifdef WLAN_FEATURE_11W
3265 if (mgt_type == IEEE80211_FC0_TYPE_MGT &&
3266 (mgt_subtype == IEEE80211_FC0_SUBTYPE_DISASSOC ||
3267 mgt_subtype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
3268 mgt_subtype == IEEE80211_FC0_SUBTYPE_ACTION)) {
Mukul Sharmaa748fbb2015-12-01 19:51:36 +05303269 if (wma_find_vdev_by_bssid(
3270 wma_handle, wh->i_addr3, &vdev_id)) {
3271 iface = &(wma_handle->interfaces[vdev_id]);
3272 if (iface->rmfEnabled) {
3273 status = wma_process_rmf_frame(wma_handle,
3274 iface, wh, rx_pkt, wbuf);
3275 if (status != 0)
3276 return status;
3277 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003278 }
3279 }
3280#endif /* WLAN_FEATURE_11W */
Mukul Sharmaa748fbb2015-12-01 19:51:36 +05303281 rx_pkt->pkt_meta.sessionId =
3282 (vdev_id == WMA_INVALID_VDEV_ID ? 0 : vdev_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003283 wma_handle->mgmt_rx(wma_handle, rx_pkt);
3284 return 0;
3285}
3286
3287/**
3288 * wma_de_register_mgmt_frm_client() - deregister management frame
3289 * @cds_ctx: cds context
3290 *
3291 * Return: CDF status
3292 */
3293CDF_STATUS wma_de_register_mgmt_frm_client(void *cds_ctx)
3294{
3295 tp_wma_handle wma_handle;
3296
3297#ifdef QCA_WIFI_FTM
3298 if (cds_get_conparam() == CDF_FTM_MODE)
3299 return CDF_STATUS_SUCCESS;
3300#endif
3301
3302 wma_handle = cds_get_context(CDF_MODULE_ID_WMA);
3303 if (!wma_handle) {
3304 WMA_LOGE("%s: Failed to get WMA context", __func__);
3305 return CDF_STATUS_E_FAILURE;
3306 }
3307
3308 if (wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
3309 WMI_MGMT_RX_EVENTID) != 0) {
3310 WMA_LOGE("Failed to Unregister rx mgmt handler with wmi");
3311 return CDF_STATUS_E_FAILURE;
3312 }
3313 wma_handle->mgmt_rx = NULL;
3314 return CDF_STATUS_SUCCESS;
3315}
3316
3317/**
3318 * wma_register_mgmt_frm_client() - register management frame callback
3319 * @cds_ctx: cds context
3320 * @mgmt_frm_rx: management frame
3321 *
3322 * Return: CDF status
3323 */
3324CDF_STATUS wma_register_mgmt_frm_client(
3325 void *cds_ctx, wma_mgmt_frame_rx_callback mgmt_frm_rx)
3326{
3327 tp_wma_handle wma_handle = cds_get_context(CDF_MODULE_ID_WMA);
3328
3329 if (!wma_handle) {
3330 WMA_LOGE("%s: Failed to get WMA context", __func__);
3331 return CDF_STATUS_E_FAILURE;
3332 }
3333
3334 if (wmi_unified_register_event_handler(wma_handle->wmi_handle,
3335 WMI_MGMT_RX_EVENTID,
3336 wma_mgmt_rx_process) != 0) {
3337 WMA_LOGE("Failed to register rx mgmt handler with wmi");
3338 return CDF_STATUS_E_FAILURE;
3339 }
3340 wma_handle->mgmt_rx = mgmt_frm_rx;
3341
3342 return CDF_STATUS_SUCCESS;
3343}