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