blob: 10011aa2f2f33f7feae5c0f03333fe37dca5917c [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);
Himanshu Agarwal94045e42015-10-19 19:16:19 +05301998 if (pdev)
1999 ol_txrx_set_wmm_param(pdev, ol_tx_wmm_param);
2000 else
2001 CDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002002
2003 return CDF_STATUS_SUCCESS;
2004
2005fail:
2006 wmi_buf_free(buf);
2007 WMA_LOGE("%s: Failed to set WMM Paremeters", __func__);
2008 return CDF_STATUS_E_FAILURE;
2009}
2010
2011/**
2012 * wmi_unified_probe_rsp_tmpl_send() - send probe response template to fw
2013 * @wma: wma handle
2014 * @vdev_id: vdev id
2015 * @probe_rsp_info: probe response info
2016 *
2017 * Return: 0 for success or error code
2018 */
2019static int wmi_unified_probe_rsp_tmpl_send(tp_wma_handle wma,
2020 uint8_t vdev_id,
2021 tpSendProbeRespParams probe_rsp_info)
2022{
2023 wmi_prb_tmpl_cmd_fixed_param *cmd;
2024 wmi_bcn_prb_info *bcn_prb_info;
2025 wmi_buf_t wmi_buf;
2026 uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len;
2027 uint8_t *frm, *buf_ptr;
2028 int ret;
2029 uint64_t adjusted_tsf_le;
2030 struct ieee80211_frame *wh;
2031
2032 WMA_LOGD(FL("Send probe response template for vdev %d"), vdev_id);
2033
2034 frm = probe_rsp_info->pProbeRespTemplate;
2035 tmpl_len = probe_rsp_info->probeRespTemplateLen;
2036 tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32));
2037 /*
2038 * Make the TSF offset negative so probe response in the same
2039 * staggered batch have the same TSF.
2040 */
2041 adjusted_tsf_le = cpu_to_le64(0ULL -
2042 wma->interfaces[vdev_id].tsfadjust);
2043 /* Update the timstamp in the probe response buffer with adjusted TSF */
2044 wh = (struct ieee80211_frame *)frm;
2045 A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
2046
2047 wmi_buf_len = sizeof(wmi_prb_tmpl_cmd_fixed_param) +
2048 sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE +
2049 tmpl_len_aligned;
2050
2051 if (wmi_buf_len > BEACON_TX_BUFFER_SIZE) {
2052 WMA_LOGE(FL("wmi_buf_len: %d > %d. Can't send wmi cmd"),
2053 wmi_buf_len, BEACON_TX_BUFFER_SIZE);
2054 return -EINVAL;
2055 }
2056
2057 wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len);
2058 if (!wmi_buf) {
2059 WMA_LOGE(FL("wmi_buf_alloc failed"));
2060 return -ENOMEM;
2061 }
2062
2063 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
2064
2065 cmd = (wmi_prb_tmpl_cmd_fixed_param *) buf_ptr;
2066 WMITLV_SET_HDR(&cmd->tlv_header,
2067 WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param,
2068 WMITLV_GET_STRUCT_TLVLEN(wmi_prb_tmpl_cmd_fixed_param));
2069 cmd->vdev_id = vdev_id;
2070 cmd->buf_len = tmpl_len;
2071 buf_ptr += sizeof(wmi_prb_tmpl_cmd_fixed_param);
2072
2073 bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr;
2074 WMITLV_SET_HDR(&bcn_prb_info->tlv_header,
2075 WMITLV_TAG_STRUC_wmi_bcn_prb_info,
2076 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info));
2077 bcn_prb_info->caps = 0;
2078 bcn_prb_info->erp = 0;
2079 buf_ptr += sizeof(wmi_bcn_prb_info);
2080
2081 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned);
2082 buf_ptr += WMI_TLV_HDR_SIZE;
2083 cdf_mem_copy(buf_ptr, frm, tmpl_len);
2084
2085 ret = wmi_unified_cmd_send(wma->wmi_handle,
2086 wmi_buf, wmi_buf_len, WMI_PRB_TMPL_CMDID);
2087 if (ret) {
2088 WMA_LOGE(FL("Failed to send PRB RSP tmpl: %d"), ret);
2089 wmi_buf_free(wmi_buf);
2090 }
2091
2092 return ret;
2093}
2094
2095/**
2096 * wmi_unified_bcn_tmpl_send() - send beacon template to fw
2097 * @wma:wma handle
2098 * @vdev_id: vdev id
2099 * @bcn_info: beacon info
2100 * @bytes_to_strip: bytes to strip
2101 *
2102 * Return: 0 for success or error code
2103 */
2104static int wmi_unified_bcn_tmpl_send(tp_wma_handle wma,
2105 uint8_t vdev_id,
2106 tpSendbeaconParams bcn_info,
2107 uint8_t bytes_to_strip)
2108{
2109 wmi_bcn_tmpl_cmd_fixed_param *cmd;
2110 wmi_bcn_prb_info *bcn_prb_info;
2111 wmi_buf_t wmi_buf;
2112 uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len;
2113 uint8_t *frm, *buf_ptr;
2114 int ret;
2115 uint8_t *p2p_ie;
2116 uint16_t p2p_ie_len = 0;
2117 uint64_t adjusted_tsf_le;
2118 struct ieee80211_frame *wh;
2119
2120 WMA_LOGD("Send beacon template for vdev %d", vdev_id);
2121
2122 if (bcn_info->p2pIeOffset) {
2123 p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset;
2124 p2p_ie_len = (uint16_t) p2p_ie[1] + 2;
2125 }
2126
2127 /*
2128 * XXX: The first byte of beacon buffer contains beacon length
2129 * only when UMAC in sending the beacon template. In othercases
2130 * (ex: from tbtt update) beacon length is read from beacon
2131 * information.
2132 */
2133 if (bytes_to_strip)
2134 tmpl_len = *(uint32_t *) &bcn_info->beacon[0];
2135 else
2136 tmpl_len = bcn_info->beaconLength;
2137 if (p2p_ie_len) {
2138 tmpl_len -= (uint32_t) p2p_ie_len;
2139 }
2140
2141 frm = bcn_info->beacon + bytes_to_strip;
2142 tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32));
2143 /*
2144 * Make the TSF offset negative so beacons in the same
2145 * staggered batch have the same TSF.
2146 */
2147 adjusted_tsf_le = cpu_to_le64(0ULL -
2148 wma->interfaces[vdev_id].tsfadjust);
2149 /* Update the timstamp in the beacon buffer with adjusted TSF */
2150 wh = (struct ieee80211_frame *)frm;
2151 A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
2152
2153 wmi_buf_len = sizeof(wmi_bcn_tmpl_cmd_fixed_param) +
2154 sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE +
2155 tmpl_len_aligned;
2156
2157 wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len);
2158 if (!wmi_buf) {
2159 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
2160 return -ENOMEM;
2161 }
2162
2163 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
2164
2165 cmd = (wmi_bcn_tmpl_cmd_fixed_param *) buf_ptr;
2166 WMITLV_SET_HDR(&cmd->tlv_header,
2167 WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param,
2168 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_cmd_fixed_param));
2169 cmd->vdev_id = vdev_id;
2170 cmd->tim_ie_offset = bcn_info->timIeOffset - bytes_to_strip;
2171 cmd->buf_len = tmpl_len;
2172 buf_ptr += sizeof(wmi_bcn_tmpl_cmd_fixed_param);
2173
2174 bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr;
2175 WMITLV_SET_HDR(&bcn_prb_info->tlv_header,
2176 WMITLV_TAG_STRUC_wmi_bcn_prb_info,
2177 WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info));
2178 bcn_prb_info->caps = 0;
2179 bcn_prb_info->erp = 0;
2180 buf_ptr += sizeof(wmi_bcn_prb_info);
2181
2182 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned);
2183 buf_ptr += WMI_TLV_HDR_SIZE;
2184 cdf_mem_copy(buf_ptr, frm, tmpl_len);
2185
2186 ret = wmi_unified_cmd_send(wma->wmi_handle,
2187 wmi_buf, wmi_buf_len, WMI_BCN_TMPL_CMDID);
2188 if (ret) {
2189 WMA_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret);
2190 wmi_buf_free(wmi_buf);
2191 }
2192
2193 return ret;
2194}
2195
2196/**
2197 * wma_store_bcn_tmpl() - store beacon template
2198 * @wma: wma handle
2199 * @vdev_id: vdev id
2200 * @bcn_info: beacon params
2201 *
2202 * This function stores beacon template locally.
2203 * This will send to target on the reception of
2204 * SWBA event.
2205 *
2206 * Return: CDF status
2207 */
2208CDF_STATUS wma_store_bcn_tmpl(tp_wma_handle wma, uint8_t vdev_id,
2209 tpSendbeaconParams bcn_info)
2210{
2211 struct beacon_info *bcn;
2212 uint32_t len;
2213 uint8_t *bcn_payload;
2214 struct beacon_tim_ie *tim_ie;
2215
2216 bcn = wma->interfaces[vdev_id].beacon;
2217 if (!bcn || !bcn->buf) {
2218 WMA_LOGE("%s: Memory is not allocated to hold bcn template",
2219 __func__);
2220 return CDF_STATUS_E_INVAL;
2221 }
2222
2223 len = *(u32 *) &bcn_info->beacon[0];
2224 if (len > WMA_BCN_BUF_MAX_SIZE) {
2225 WMA_LOGE("%s: Received beacon len %d exceeding max limit %d",
2226 __func__, len, WMA_BCN_BUF_MAX_SIZE);
2227 return CDF_STATUS_E_INVAL;
2228 }
2229 WMA_LOGD("%s: Storing received beacon template buf to local buffer",
2230 __func__);
2231 cdf_spin_lock_bh(&bcn->lock);
2232
2233 /*
2234 * Copy received beacon template content in local buffer.
2235 * this will be send to target on the reception of SWBA
2236 * event from target.
2237 */
2238 cdf_nbuf_trim_tail(bcn->buf, cdf_nbuf_len(bcn->buf));
2239 memcpy(cdf_nbuf_data(bcn->buf),
2240 bcn_info->beacon + 4 /* Exclude beacon length field */,
2241 len);
2242 if (bcn_info->timIeOffset > 3) {
2243 bcn->tim_ie_offset = bcn_info->timIeOffset - 4;
2244 } else {
2245 bcn->tim_ie_offset = bcn_info->timIeOffset;
2246 }
2247
2248 if (bcn_info->p2pIeOffset > 3) {
2249 bcn->p2p_ie_offset = bcn_info->p2pIeOffset - 4;
2250 } else {
2251 bcn->p2p_ie_offset = bcn_info->p2pIeOffset;
2252 }
2253 bcn_payload = cdf_nbuf_data(bcn->buf);
2254 if (bcn->tim_ie_offset) {
2255 tim_ie =
2256 (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]);
2257 /*
2258 * Intial Value of bcn->dtim_count will be 0.
2259 * But if the beacon gets updated then current dtim
2260 * count will be restored
2261 */
2262 tim_ie->dtim_count = bcn->dtim_count;
2263 tim_ie->tim_bitctl = 0;
2264 }
2265
2266 cdf_nbuf_put_tail(bcn->buf, len);
2267 bcn->len = len;
2268
2269 cdf_spin_unlock_bh(&bcn->lock);
2270
2271 return CDF_STATUS_SUCCESS;
2272}
2273
2274/**
2275 * wma_tbttoffset_update_event_handler() - tbtt offset update handler
2276 * @handle: wma handle
2277 * @event: event buffer
2278 * @len: data length
2279 *
2280 * Return: 0 for success or error code
2281 */
2282int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event,
2283 uint32_t len)
2284{
2285 tp_wma_handle wma = (tp_wma_handle) handle;
2286 WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf;
2287 wmi_tbtt_offset_event_fixed_param *tbtt_offset_event;
2288 struct wma_txrx_node *intf;
2289 struct beacon_info *bcn;
2290 tSendbeaconParams bcn_info;
2291 uint32_t *adjusted_tsf = NULL;
2292 uint32_t if_id = 0, vdev_map;
2293
2294 if (!wma) {
2295 WMA_LOGE("Invalid wma handle");
2296 return -EINVAL;
2297 }
2298
2299 param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) event;
2300 if (!param_buf) {
2301 WMA_LOGE("Invalid tbtt update event buffer");
2302 return -EINVAL;
2303 }
2304
2305 tbtt_offset_event = param_buf->fixed_param;
2306 intf = wma->interfaces;
2307 vdev_map = tbtt_offset_event->vdev_map;
2308 adjusted_tsf = param_buf->tbttoffset_list;
2309 if (!adjusted_tsf) {
2310 WMA_LOGE("%s: Invalid adjusted_tsf", __func__);
2311 return -EINVAL;
2312 }
2313
2314 for (; (vdev_map); vdev_map >>= 1, if_id++) {
2315 if (!(vdev_map & 0x1) || (!(intf[if_id].handle)))
2316 continue;
2317
2318 bcn = intf[if_id].beacon;
2319 if (!bcn) {
2320 WMA_LOGE("%s: Invalid beacon", __func__);
2321 return -EINVAL;
2322 }
2323 if (!bcn->buf) {
2324 WMA_LOGE("%s: Invalid beacon buffer", __func__);
2325 return -EINVAL;
2326 }
2327 /* Save the adjusted TSF */
2328 intf[if_id].tsfadjust = adjusted_tsf[if_id];
2329
2330 cdf_spin_lock_bh(&bcn->lock);
2331 cdf_mem_zero(&bcn_info, sizeof(bcn_info));
2332 bcn_info.beacon = cdf_nbuf_data(bcn->buf);
2333 bcn_info.p2pIeOffset = bcn->p2p_ie_offset;
2334 bcn_info.beaconLength = bcn->len;
2335 bcn_info.timIeOffset = bcn->tim_ie_offset;
2336 cdf_spin_unlock_bh(&bcn->lock);
2337
2338 /* Update beacon template in firmware */
2339 wmi_unified_bcn_tmpl_send(wma, if_id, &bcn_info, 0);
2340 }
2341 return 0;
2342}
2343
2344/**
2345 * wma_p2p_go_set_beacon_ie() - set beacon IE for p2p go
2346 * @wma_handle: wma handle
2347 * @vdev_id: vdev id
2348 * @p2pIe: p2p IE
2349 *
2350 * Return: 0 for success or error code
2351 */
2352static int wma_p2p_go_set_beacon_ie(t_wma_handle *wma_handle,
2353 A_UINT32 vdev_id, uint8_t *p2pIe)
2354{
2355 int ret;
2356 wmi_p2p_go_set_beacon_ie_fixed_param *cmd;
2357 wmi_buf_t wmi_buf;
2358 uint32_t ie_len, ie_len_aligned, wmi_buf_len;
2359 uint8_t *buf_ptr;
2360
2361 ie_len = (uint32_t) (p2pIe[1] + 2);
2362
2363 /* More than one P2P IE may be included in a single frame.
2364 If multiple P2P IEs are present, the complete P2P attribute
2365 data consists of the concatenation of the P2P Attribute
2366 fields of the P2P IEs. The P2P Attributes field of each
2367 P2P IE may be any length up to the maximum (251 octets).
2368 In this case host sends one P2P IE to firmware so the length
2369 should not exceed more than 251 bytes
2370 */
2371 if (ie_len > 251) {
2372 WMA_LOGE("%s : invalid p2p ie length %u", __func__, ie_len);
2373 return -EINVAL;
2374 }
2375
2376 ie_len_aligned = roundup(ie_len, sizeof(A_UINT32));
2377
2378 wmi_buf_len =
2379 sizeof(wmi_p2p_go_set_beacon_ie_fixed_param) + ie_len_aligned +
2380 WMI_TLV_HDR_SIZE;
2381
2382 wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, wmi_buf_len);
2383 if (!wmi_buf) {
2384 WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
2385 return -ENOMEM;
2386 }
2387
2388 buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf);
2389
2390 cmd = (wmi_p2p_go_set_beacon_ie_fixed_param *) buf_ptr;
2391 WMITLV_SET_HDR(&cmd->tlv_header,
2392 WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param,
2393 WMITLV_GET_STRUCT_TLVLEN
2394 (wmi_p2p_go_set_beacon_ie_fixed_param));
2395 cmd->vdev_id = vdev_id;
2396 cmd->ie_buf_len = ie_len;
2397
2398 buf_ptr += sizeof(wmi_p2p_go_set_beacon_ie_fixed_param);
2399 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned);
2400 buf_ptr += WMI_TLV_HDR_SIZE;
2401 cdf_mem_copy(buf_ptr, p2pIe, ie_len);
2402
2403 WMA_LOGI("%s: Sending WMI_P2P_GO_SET_BEACON_IE", __func__);
2404
2405 ret = wmi_unified_cmd_send(wma_handle->wmi_handle,
2406 wmi_buf, wmi_buf_len,
2407 WMI_P2P_GO_SET_BEACON_IE);
2408 if (ret) {
2409 WMA_LOGE("Failed to send bcn tmpl: %d", ret);
2410 wmi_buf_free(wmi_buf);
2411 }
2412
2413 WMA_LOGI("%s: Successfully sent WMI_P2P_GO_SET_BEACON_IE", __func__);
2414 return ret;
2415}
2416
2417/**
2418 * wma_send_probe_rsp_tmpl() - send probe resp template
2419 * @wma: wma handle
2420 * @probe_rsp_info: probe response info
2421 *
2422 * This funciton sends probe response template to fw which
2423 * firmware will use in case of probe response offload.
2424 *
2425 * Return: none
2426 */
2427void wma_send_probe_rsp_tmpl(tp_wma_handle wma,
2428 tpSendProbeRespParams probe_rsp_info)
2429{
2430 ol_txrx_vdev_handle vdev;
2431 uint8_t vdev_id;
2432 tpAniProbeRspStruct probe_rsp;
2433
2434 if (!probe_rsp_info) {
2435 WMA_LOGE(FL("probe_rsp_info is NULL"));
2436 return;
2437 }
2438
2439 probe_rsp = (tpAniProbeRspStruct) (probe_rsp_info->pProbeRespTemplate);
2440 if (!probe_rsp) {
2441 WMA_LOGE(FL("probe_rsp is NULL"));
2442 return;
2443 }
2444
2445 vdev = wma_find_vdev_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id);
2446 if (!vdev) {
2447 WMA_LOGE(FL("failed to get vdev handle"));
2448 return;
2449 }
2450
2451 if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2452 WMI_SERVICE_BEACON_OFFLOAD)) {
2453 WMA_LOGI("Beacon Offload Enabled Sending Unified command");
2454 if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id,
2455 probe_rsp_info) < 0) {
2456 WMA_LOGE(FL("wmi_unified_probe_rsp_tmpl_send Failed "));
2457 return;
2458 }
2459 }
2460}
2461
2462/**
2463 * wma_send_beacon() - send beacon template
2464 * @wma: wma handle
2465 * @bcn_info: beacon info
2466 *
2467 * This funciton store beacon template locally and
2468 * update keep alive parameters
2469 *
2470 * Return: none
2471 */
2472void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info)
2473{
2474 ol_txrx_vdev_handle vdev;
2475 uint8_t vdev_id;
2476 CDF_STATUS status;
2477 uint8_t *p2p_ie;
2478 tpAniBeaconStruct beacon;
2479
2480 beacon = (tpAniBeaconStruct) (bcn_info->beacon);
2481 vdev = wma_find_vdev_by_addr(wma, beacon->macHdr.sa, &vdev_id);
2482 if (!vdev) {
2483 WMA_LOGE("%s : failed to get vdev handle", __func__);
2484 return;
2485 }
2486
2487 if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
2488 WMI_SERVICE_BEACON_OFFLOAD)) {
2489 WMA_LOGI("Beacon Offload Enabled Sending Unified command");
2490 if (wmi_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4) < 0) {
2491 WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ",
2492 __func__);
2493 return;
2494 }
2495
2496 if (bcn_info->p2pIeOffset) {
2497 p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset;
2498 WMA_LOGI
2499 (" %s: p2pIe is present - vdev_id %hu, p2p_ie = %p, p2p ie len = %hu",
2500 __func__, vdev_id, p2p_ie, p2p_ie[1]);
2501 if (wma_p2p_go_set_beacon_ie(wma, vdev_id, p2p_ie) < 0) {
2502 WMA_LOGE
2503 ("%s : wmi_unified_bcn_tmpl_send Failed ",
2504 __func__);
2505 return;
2506 }
2507 }
2508 }
2509 status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info);
2510 if (status != CDF_STATUS_SUCCESS) {
2511 WMA_LOGE("%s : wma_store_bcn_tmpl Failed", __func__);
2512 return;
2513 }
2514 if (!wma->interfaces[vdev_id].vdev_up) {
2515 if (wmi_unified_vdev_up_send(wma->wmi_handle, vdev_id, 0,
2516 bcn_info->bssId) < 0) {
2517 WMA_LOGE("%s : failed to send vdev up", __func__);
2518 return;
2519 }
2520 wma->interfaces[vdev_id].vdev_up = true;
2521 wma_set_sap_keepalive(wma, vdev_id);
2522 }
2523}
2524
2525/**
2526 * wma_set_keepalive_req() - send keep alive request to fw
2527 * @wma: wma handle
2528 * @keepalive: keep alive parameters
2529 *
2530 * Return: none
2531 */
2532void wma_set_keepalive_req(tp_wma_handle wma,
2533 tSirKeepAliveReq *keepalive)
2534{
2535 WMA_LOGD("KEEPALIVE:PacketType:%d", keepalive->packetType);
2536 wma_set_sta_keep_alive(wma, keepalive->sessionId,
2537 keepalive->packetType,
2538 keepalive->timePeriod,
2539 keepalive->hostIpv4Addr,
2540 keepalive->destIpv4Addr, keepalive->destMacAddr);
2541
2542 cdf_mem_free(keepalive);
2543}
2544
2545/**
2546 * wma_beacon_miss_handler() - beacon miss event handler
2547 * @wma: wma handle
2548 * @vdev_id: vdev id
2549 *
2550 * This function send beacon miss indication to upper layers.
2551 *
2552 * Return: none
2553 */
2554void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id)
2555{
2556 tSirSmeMissedBeaconInd *beacon_miss_ind;
2557
2558 beacon_miss_ind = (tSirSmeMissedBeaconInd *) cdf_mem_malloc
2559 (sizeof(tSirSmeMissedBeaconInd));
2560
2561 if (NULL == beacon_miss_ind) {
2562 WMA_LOGE("%s: Memory allocation failure", __func__);
2563 return;
2564 }
2565 beacon_miss_ind->messageType = WMA_MISSED_BEACON_IND;
2566 beacon_miss_ind->length = sizeof(tSirSmeMissedBeaconInd);
2567 beacon_miss_ind->bssIdx = vdev_id;
2568
2569 wma_send_msg(wma, WMA_MISSED_BEACON_IND, (void *)beacon_miss_ind, 0);
2570}
2571
2572/**
2573 * wma_mgmt_tx_completion_handler() - wma mgmt Tx completion event handler
2574 * @handle: wma handle
2575 * @cmpl_event_params: completion event handler data
2576 * @len: length of @cmpl_event_params
2577 *
2578 * Return: 0 on success; error number otherwise
2579 */
2580
2581int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params,
2582 uint32_t len)
2583{
2584 tp_wma_handle wma_handle = (tp_wma_handle)handle;
2585 WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf;
2586 wmi_mgmt_tx_compl_event_fixed_param *cmpl_params;
2587 struct wmi_desc_t *wmi_desc;
2588
2589 ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX);
2590
2591 param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *)
2592 cmpl_event_params;
2593 if (!param_buf && !wma_handle) {
2594 WMA_LOGE("%s: Invalid mgmt Tx completion event", __func__);
2595 return -EINVAL;
2596 }
2597 cmpl_params = param_buf->fixed_param;
2598
2599 WMA_LOGI("%s: status:%d wmi_desc_id:%d", __func__, cmpl_params->status,
2600 cmpl_params->desc_id);
2601
2602 wmi_desc = (struct wmi_desc_t *)
2603 (&wma_handle->wmi_desc_pool.array[cmpl_params->desc_id]);
2604
2605 if (!wmi_desc) {
2606 WMA_LOGE("%s: Invalid wmi desc", __func__);
2607 return -EINVAL;
2608 }
2609
2610 if (wmi_desc->nbuf)
2611 cdf_nbuf_unmap_single(pdev->osdev, wmi_desc->nbuf,
2612 CDF_DMA_TO_DEVICE);
2613 if (wmi_desc->tx_cmpl_cb)
2614 wmi_desc->tx_cmpl_cb(wma_handle->mac_context,
2615 wmi_desc->nbuf, 1);
2616
2617 if (wmi_desc->ota_post_proc_cb)
2618 wmi_desc->ota_post_proc_cb((tpAniSirGlobal)
2619 wma_handle->mac_context,
2620 cmpl_params->status);
2621
2622 wmi_desc_put(wma_handle, wmi_desc);
2623
2624 return 0;
2625}
2626
2627/**
2628 * wma_process_update_opmode() - process update VHT opmode cmd from UMAC
2629 * @wma_handle: wma handle
2630 * @update_vht_opmode: vht opmode
2631 *
2632 * Return: none
2633 */
2634void wma_process_update_opmode(tp_wma_handle wma_handle,
2635 tUpdateVHTOpMode *update_vht_opmode)
2636{
2637 WMA_LOGD("%s: opMode = %d", __func__, update_vht_opmode->opMode);
2638
2639 wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
2640 WMI_PEER_CHWIDTH, update_vht_opmode->opMode,
2641 update_vht_opmode->smesessionId);
2642}
2643
2644/**
2645 * wma_process_update_rx_nss() - process update RX NSS cmd from UMAC
2646 * @wma_handle: wma handle
2647 * @update_rx_nss: rx nss value
2648 *
2649 * Return: none
2650 */
2651void wma_process_update_rx_nss(tp_wma_handle wma_handle,
2652 tUpdateRxNss *update_rx_nss)
2653{
2654 struct wma_txrx_node *intr =
2655 &wma_handle->interfaces[update_rx_nss->smesessionId];
2656 int rx_nss = update_rx_nss->rxNss;
2657
2658 wma_update_txrx_chainmask(wma_handle->num_rf_chains, &rx_nss);
2659
2660 intr->nss = (uint8_t)rx_nss;
2661 update_rx_nss->rxNss = (uint32_t)rx_nss;
2662
2663 WMA_LOGD("%s: Rx Nss = %d", __func__, update_rx_nss->rxNss);
2664
2665 wma_set_peer_param(wma_handle, update_rx_nss->peer_mac,
2666 WMI_PEER_NSS, update_rx_nss->rxNss,
2667 update_rx_nss->smesessionId);
2668}
2669
2670#ifdef WLAN_FEATURE_11AC
2671/**
2672 * wma_process_update_membership() - process update group membership cmd
2673 * @wma_handle: wma handle
2674 * @membership: group membership info
2675 *
2676 * Return: none
2677 */
2678void wma_process_update_membership(tp_wma_handle wma_handle,
2679 tUpdateMembership *membership)
2680{
2681 WMA_LOGD("%s: membership = %x ", __func__, membership->membership);
2682
2683 wma_set_peer_param(wma_handle, membership->peer_mac,
2684 WMI_PEER_MEMBERSHIP, membership->membership,
2685 membership->smesessionId);
2686}
2687
2688/**
2689 * wma_process_update_userpos() - process update user pos cmd from UMAC
2690 * @wma_handle: wma handle
2691 * @userpos: user pos value
2692 *
2693 * Return: none
2694 */
2695void wma_process_update_userpos(tp_wma_handle wma_handle,
2696 tUpdateUserPos *userpos)
2697{
2698 WMA_LOGD("%s: userPos = %x ", __func__, userpos->userPos);
2699
2700 wma_set_peer_param(wma_handle, userpos->peer_mac,
2701 WMI_PEER_USERPOS, userpos->userPos,
2702 userpos->smesessionId);
2703
2704 /* Now that membership/userpos is updated in fw,
2705 * enable GID PPS.
2706 */
2707 wma_set_ppsconfig(userpos->smesessionId, WMA_VHT_PPS_GID_MATCH, 1);
2708
2709}
2710#endif /* WLAN_FEATURE_11AC */
2711
2712/**
2713 * wma_set_htconfig() - set ht config parameters to target
2714 * @vdev_id: vdev id
2715 * @ht_capab: ht capablity
2716 * @value: value of ht param
2717 *
2718 * Return: CDF status
2719 */
2720CDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value)
2721{
2722 tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA);
2723 int ret = -EIO;
2724
2725 if (NULL == wma) {
2726 WMA_LOGE("%s: Failed to get wma", __func__);
2727 return CDF_STATUS_E_INVAL;
2728 }
2729
2730 switch (ht_capab) {
2731 case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING:
2732 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2733 WMI_VDEV_PARAM_LDPC,
2734 value);
2735 break;
2736 case WNI_CFG_HT_CAP_INFO_TX_STBC:
2737 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2738 WMI_VDEV_PARAM_TX_STBC,
2739 value);
2740 break;
2741 case WNI_CFG_HT_CAP_INFO_RX_STBC:
2742 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2743 WMI_VDEV_PARAM_RX_STBC,
2744 value);
2745 break;
2746 case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ:
2747 case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ:
2748 WMA_LOGE("%s: ht_capab = %d, value = %d", __func__, ht_capab,
2749 value);
2750 ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
2751 WMI_VDEV_PARAM_SGI, value);
2752 if (ret == 0)
2753 wma->interfaces[vdev_id].config.shortgi = value;
2754 break;
2755 default:
2756 WMA_LOGE("%s:INVALID HT CONFIG", __func__);
2757 }
2758
2759 return (ret) ? CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS;
2760}
2761
2762/**
2763 * wma_hidden_ssid_vdev_restart() - vdev restart for hidden ssid
2764 * @wma_handle: wma handle
2765 * @pReq: hidden ssid vdev restart request
2766 *
2767 * Return: none
2768 */
2769void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle,
2770 tHalHiddenSsidVdevRestart *pReq)
2771{
2772 struct wma_txrx_node *intr = wma_handle->interfaces;
2773
2774 if ((pReq->sessionId !=
2775 intr[pReq->sessionId].vdev_restart_params.vdev_id)
2776 || !((intr[pReq->sessionId].type == WMI_VDEV_TYPE_AP)
2777 && (intr[pReq->sessionId].sub_type == 0))) {
2778 WMA_LOGE("%s : invalid session id", __func__);
2779 return;
2780 }
2781
2782 intr[pReq->sessionId].vdev_restart_params.ssidHidden = pReq->ssidHidden;
2783 cdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params.
2784 hidden_ssid_restart_in_progress, 1);
2785
2786 /* vdev stop -> vdev restart -> vdev up */
2787 WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP",
2788 __func__, pReq->sessionId);
2789 ol_txrx_vdev_pause(wma_handle->interfaces[pReq->sessionId].handle,
2790 OL_TXQ_PAUSE_REASON_VDEV_STOP);
2791 wma_handle->interfaces[pReq->sessionId].pause_bitmap |=
2792 (1 << PAUSE_TYPE_HOST);
2793 if (wmi_unified_vdev_stop_send(wma_handle->wmi_handle, pReq->sessionId)) {
2794 WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__);
2795 cdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params.
2796 hidden_ssid_restart_in_progress, 0);
2797 return;
2798 }
2799}
2800
2801
2802#ifdef WLAN_FEATURE_11W
2803
2804/**
2805 * wma_extract_ccmp_pn() - extract 6 byte PN from the CCMP header
2806 * @ccmp_ptr: CCMP header
2807 *
2808 * Return: PN extracted from header.
2809 */
2810static uint64_t wma_extract_ccmp_pn(uint8_t *ccmp_ptr)
2811{
2812 uint8_t rsvd, key, pn[6];
2813 uint64_t new_pn;
2814
2815 /*
2816 * +-----+-----+------+----------+-----+-----+-----+-----+
2817 * | PN0 | PN1 | rsvd | rsvd/key | PN2 | PN3 | PN4 | PN5 |
2818 * +-----+-----+------+----------+-----+-----+-----+-----+
2819 * CCMP Header Format
2820 */
2821
2822 /* Extract individual bytes */
2823 pn[0] = (uint8_t) *ccmp_ptr;
2824 pn[1] = (uint8_t) *(ccmp_ptr + 1);
2825 rsvd = (uint8_t) *(ccmp_ptr + 2);
2826 key = (uint8_t) *(ccmp_ptr + 3);
2827 pn[2] = (uint8_t) *(ccmp_ptr + 4);
2828 pn[3] = (uint8_t) *(ccmp_ptr + 5);
2829 pn[4] = (uint8_t) *(ccmp_ptr + 6);
2830 pn[5] = (uint8_t) *(ccmp_ptr + 7);
2831
2832 /* Form 6 byte PN with 6 individual bytes of PN */
2833 new_pn = ((uint64_t) pn[5] << 40) |
2834 ((uint64_t) pn[4] << 32) |
2835 ((uint64_t) pn[3] << 24) |
2836 ((uint64_t) pn[2] << 16) |
2837 ((uint64_t) pn[1] << 8) | ((uint64_t) pn[0] << 0);
2838
2839 WMA_LOGE("PN of received packet is %llu", new_pn);
2840 return new_pn;
2841}
2842
2843/**
2844 * wma_is_ccmp_pn_replay_attack() - detect replay attacking using PN in CCMP
2845 * @cds_ctx: cds context
2846 * @wh: 802.11 frame header
2847 * @ccmp_ptr: CCMP frame header
2848 *
2849 * Return: true/false
2850 */
2851static bool
2852wma_is_ccmp_pn_replay_attack(void *cds_ctx, struct ieee80211_frame *wh,
2853 uint8_t *ccmp_ptr)
2854{
2855 ol_txrx_pdev_handle pdev;
2856 ol_txrx_vdev_handle vdev;
2857 ol_txrx_peer_handle peer;
2858 uint8_t vdev_id, peer_id;
2859 uint8_t *last_pn_valid;
2860 uint64_t *last_pn, new_pn;
2861 uint32_t *rmf_pn_replays;
2862
2863 pdev = cds_get_context(CDF_MODULE_ID_TXRX);
2864 if (!pdev) {
2865 WMA_LOGE("%s: Failed to find pdev", __func__);
2866 return true;
2867 }
2868
2869 vdev = wma_find_vdev_by_addr(cds_ctx, wh->i_addr2, &vdev_id);
2870 if (!vdev) {
2871 WMA_LOGE("%s: Failed to find vdev", __func__);
2872 return true;
2873 }
2874
2875 /* Retrieve the peer based on vdev and addr */
2876 peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, wh->i_addr2,
2877 &peer_id);
2878
2879 if (NULL == peer) {
2880 WMA_LOGE("%s: Failed to find peer, Not able to validate PN",
2881 __func__);
2882 return true;
2883 }
2884
2885 new_pn = wma_extract_ccmp_pn(ccmp_ptr);
2886 last_pn_valid = &peer->last_rmf_pn_valid;
2887 last_pn = &peer->last_rmf_pn;
2888 rmf_pn_replays = &peer->rmf_pn_replays;
2889
2890 if (*last_pn_valid) {
2891 if (new_pn > *last_pn) {
2892 *last_pn = new_pn;
2893 WMA_LOGE("%s: PN validation successful", __func__);
2894 } else {
2895 WMA_LOGE("%s: PN Replay attack detected", __func__);
2896 /* per 11W amendment, keeping track of replay attacks */
2897 *rmf_pn_replays += 1;
2898 return true;
2899 }
2900 } else {
2901 *last_pn_valid = 1;
2902 *last_pn = new_pn;
2903 }
2904
2905 return false;
2906}
2907
2908/**
2909 * wma_process_rmf_frame() - process rmf frame
2910 * @wma_handle: wma handle
2911 * @iface: txrx node
2912 * @wh: 80211 frame
2913 * @rx_pkt: rx packet
2914 * @wbuf: Buffer
2915 *
2916 * Return: 0 for success or error code
2917 */
2918static
2919int wma_process_rmf_frame(tp_wma_handle wma_handle,
2920 struct wma_txrx_node *iface,
2921 struct ieee80211_frame *wh,
2922 cds_pkt_t *rx_pkt,
2923 cdf_nbuf_t wbuf)
2924{
2925 uint8_t *efrm, *orig_hdr;
2926 uint16_t key_id;
2927 uint8_t *ccmp;
2928
2929 if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) {
2930 if (IEEE80211_IS_BROADCAST(wh->i_addr1) ||
2931 IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2932 WMA_LOGE("Encrypted BC/MC frame dropping the frame");
2933 cds_pkt_return_packet(rx_pkt);
2934 return -EINVAL;
2935 }
2936
2937 orig_hdr = (uint8_t *) cdf_nbuf_data(wbuf);
2938 /* Pointer to head of CCMP header */
2939 ccmp = orig_hdr + sizeof(*wh);
2940 if (wma_is_ccmp_pn_replay_attack(
2941 wma_handle, wh, ccmp)) {
2942 WMA_LOGE("Dropping the frame");
2943 cds_pkt_return_packet(rx_pkt);
2944 return -EINVAL;
2945 }
2946
2947 /* Strip privacy headers (and trailer)
2948 * for a received frame
2949 */
2950 cdf_mem_move(orig_hdr +
2951 IEEE80211_CCMP_HEADERLEN, wh,
2952 sizeof(*wh));
2953 cdf_nbuf_pull_head(wbuf,
2954 IEEE80211_CCMP_HEADERLEN);
2955 cdf_nbuf_trim_tail(wbuf, IEEE80211_CCMP_MICLEN);
2956
2957 rx_pkt->pkt_meta.mpdu_hdr_ptr =
2958 cdf_nbuf_data(wbuf);
2959 rx_pkt->pkt_meta.mpdu_len = cdf_nbuf_len(wbuf);
2960 rx_pkt->pkt_meta.mpdu_data_len =
2961 rx_pkt->pkt_meta.mpdu_len -
2962 rx_pkt->pkt_meta.mpdu_hdr_len;
2963 rx_pkt->pkt_meta.mpdu_data_ptr =
2964 rx_pkt->pkt_meta.mpdu_hdr_ptr +
2965 rx_pkt->pkt_meta.mpdu_hdr_len;
2966 rx_pkt->pkt_meta.tsf_delta = rx_pkt->pkt_meta.tsf_delta;
2967 rx_pkt->pkt_buf = wbuf;
2968 WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"),
2969 MAC_ADDR_ARRAY(wh->i_addr3), rx_pkt->pkt_meta.tsf_delta);
2970 } else {
2971 if (IEEE80211_IS_BROADCAST(wh->i_addr1) ||
2972 IEEE80211_IS_MULTICAST(wh->i_addr1)) {
2973 efrm = cdf_nbuf_data(wbuf) +
2974 cdf_nbuf_len(wbuf);
2975
2976 key_id = (uint16_t)*(efrm - cds_get_mmie_size() + 2);
2977 if (!((key_id == WMA_IGTK_KEY_INDEX_4)
2978 || (key_id == WMA_IGTK_KEY_INDEX_5))) {
2979 WMA_LOGE("Invalid KeyID(%d) dropping the frame", key_id);
2980 cds_pkt_return_packet(rx_pkt);
2981 return -EINVAL;
2982 }
2983
2984 if (cds_is_mmie_valid(iface->key.key,
2985 iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn,
2986 (uint8_t *) wh, efrm)) {
2987 WMA_LOGE("Protected BC/MC frame MMIE validation successful");
2988 /* Remove MMIE */
2989 cdf_nbuf_trim_tail(wbuf,
2990 cds_get_mmie_size());
2991 } else {
2992 WMA_LOGE("BC/MC MIC error or MMIE not present, dropping the frame");
2993 cds_pkt_return_packet(rx_pkt);
2994 return -EINVAL;
2995 }
2996 } else {
2997 WMA_LOGE("Rx unprotected unicast mgmt frame");
2998 rx_pkt->pkt_meta.dpuFeedback =
2999 DPU_FEEDBACK_UNPROTECTED_ERROR;
3000 }
3001 }
3002 return 0;
3003}
3004#endif
3005
3006/**
3007 * wma_mgmt_rx_process() - process management rx frame.
3008 * @handle: wma handle
3009 * @data: rx data
3010 * @data_len: data length
3011 *
3012 * Return: 0 for success or error code
3013 */
3014static int wma_mgmt_rx_process(void *handle, uint8_t *data,
3015 uint32_t data_len)
3016{
3017 tp_wma_handle wma_handle = (tp_wma_handle) handle;
3018 WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL;
3019 wmi_mgmt_rx_hdr *hdr = NULL;
3020 struct wma_txrx_node *iface = NULL;
3021 uint8_t vdev_id;
3022 cds_pkt_t *rx_pkt;
3023 cdf_nbuf_t wbuf;
3024 struct ieee80211_frame *wh;
3025 uint8_t mgt_type, mgt_subtype;
3026 int status;
3027
3028 if (!wma_handle) {
3029 WMA_LOGE("%s: Failed to get WMA context", __func__);
3030 return -EINVAL;
3031 }
3032
3033 param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) data;
3034 if (!param_tlvs) {
3035 WMA_LOGE("Get NULL point message from FW");
3036 return -EINVAL;
3037 }
3038
3039 hdr = param_tlvs->hdr;
3040 if (!hdr) {
3041 WMA_LOGE("Rx event is NULL");
3042 return -EINVAL;
3043 }
3044
3045 if (hdr->buf_len < sizeof(struct ieee80211_frame)) {
3046 WMA_LOGE("Invalid rx mgmt packet");
3047 return -EINVAL;
3048 }
3049
3050 rx_pkt = cdf_mem_malloc(sizeof(*rx_pkt));
3051 if (!rx_pkt) {
3052 WMA_LOGE("Failed to allocate rx packet");
3053 return -ENOMEM;
3054 }
3055
Naveen Rawat10ccf872015-11-03 14:15:55 -08003056 if (cds_is_load_unload_in_progress()) {
3057 WMA_LOGE("Load/Unload in progress");
3058 return -EINVAL;
3059 }
3060
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003061 cdf_mem_zero(rx_pkt, sizeof(*rx_pkt));
3062
3063 /*
3064 * Fill in meta information needed by pe/lim
3065 * TODO: Try to maintain rx metainfo as part of skb->data.
3066 */
3067 rx_pkt->pkt_meta.channel = hdr->channel;
3068 rx_pkt->pkt_meta.scan_src = hdr->flags;
3069 /*Get the absolute rssi value from the current rssi value
3070 *the sinr value is hardcoded into 0 in the core stack*/
3071 rx_pkt->pkt_meta.rssi = hdr->snr + WMA_TGT_NOISE_FLOOR_DBM;
3072 rx_pkt->pkt_meta.snr = hdr->snr;
3073 /*
3074 * FIXME: Assigning the local timestamp as hw timestamp is not
3075 * available. Need to see if pe/lim really uses this data.
3076 */
3077 rx_pkt->pkt_meta.timestamp = (uint32_t) jiffies;
3078 rx_pkt->pkt_meta.mpdu_hdr_len = sizeof(struct ieee80211_frame);
3079 rx_pkt->pkt_meta.mpdu_len = hdr->buf_len;
3080 rx_pkt->pkt_meta.mpdu_data_len = hdr->buf_len -
3081 rx_pkt->pkt_meta.mpdu_hdr_len;
3082
3083 rx_pkt->pkt_meta.roamCandidateInd = 0;
3084
3085 /* Why not just use rx_event->hdr.buf_len? */
3086 wbuf = cdf_nbuf_alloc(NULL, roundup(hdr->buf_len, 4), 0, 4, false);
3087 if (!wbuf) {
3088 WMA_LOGE("%s: Failed to allocate wbuf for mgmt rx len(%u)",
3089 __func__, hdr->buf_len);
3090 cdf_mem_free(rx_pkt);
3091 return -ENOMEM;
3092 }
3093
3094 cdf_nbuf_put_tail(wbuf, hdr->buf_len);
3095 cdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL);
3096 wh = (struct ieee80211_frame *)cdf_nbuf_data(wbuf);
3097
3098 rx_pkt->pkt_meta.mpdu_hdr_ptr = cdf_nbuf_data(wbuf);
3099 rx_pkt->pkt_meta.mpdu_data_ptr = rx_pkt->pkt_meta.mpdu_hdr_ptr +
3100 rx_pkt->pkt_meta.mpdu_hdr_len;
3101 rx_pkt->pkt_meta.tsf_delta = hdr->tsf_delta;
3102 rx_pkt->pkt_buf = wbuf;
3103
3104 WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"),
3105 MAC_ADDR_ARRAY(wh->i_addr3), hdr->tsf_delta);
3106
3107#ifdef BIG_ENDIAN_HOST
3108 {
3109 /*
3110 * for big endian host, copy engine byte_swap is enabled
3111 * But the rx mgmt frame buffer content is in network byte order
3112 * Need to byte swap the mgmt frame buffer content - so when
3113 * copy engine does byte_swap - host gets buffer content in the
3114 * correct byte order.
3115 */
3116 int i;
3117 uint32_t *destp, *srcp;
3118 destp = (uint32_t *) wh;
3119 srcp = (uint32_t *) param_tlvs->bufp;
3120 for (i = 0;
3121 i < (roundup(hdr->buf_len, sizeof(uint32_t)) / 4); i++) {
3122 *destp = cpu_to_le32(*srcp);
3123 destp++;
3124 srcp++;
3125 }
3126 }
3127#else
3128 cdf_mem_copy(wh, param_tlvs->bufp, hdr->buf_len);
3129#endif
3130
3131 if (!wma_handle->mgmt_rx) {
3132 WMA_LOGE("Not registered for Mgmt rx, dropping the frame");
3133 cds_pkt_return_packet(rx_pkt);
3134 return -EINVAL;
3135 }
3136
3137 /* If it is a beacon/probe response, save it for future use */
3138 mgt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3139 mgt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
3140
3141 iface = wma_find_vdev_by_addr(wma_handle, wh->i_addr3, &vdev_id);
3142 rx_pkt->pkt_meta.sessionId = vdev_id;
3143
3144#ifdef WLAN_FEATURE_11W
3145 if (mgt_type == IEEE80211_FC0_TYPE_MGT &&
3146 (mgt_subtype == IEEE80211_FC0_SUBTYPE_DISASSOC ||
3147 mgt_subtype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
3148 mgt_subtype == IEEE80211_FC0_SUBTYPE_ACTION)) {
3149 if (iface && iface->rmfEnabled) {
3150 status = wma_process_rmf_frame(wma_handle,
3151 iface, wh, rx_pkt, wbuf);
3152 if (status != 0)
3153 return status;
3154 }
3155 }
3156#endif /* WLAN_FEATURE_11W */
3157 wma_handle->mgmt_rx(wma_handle, rx_pkt);
3158 return 0;
3159}
3160
3161/**
3162 * wma_de_register_mgmt_frm_client() - deregister management frame
3163 * @cds_ctx: cds context
3164 *
3165 * Return: CDF status
3166 */
3167CDF_STATUS wma_de_register_mgmt_frm_client(void *cds_ctx)
3168{
3169 tp_wma_handle wma_handle;
3170
3171#ifdef QCA_WIFI_FTM
3172 if (cds_get_conparam() == CDF_FTM_MODE)
3173 return CDF_STATUS_SUCCESS;
3174#endif
3175
3176 wma_handle = cds_get_context(CDF_MODULE_ID_WMA);
3177 if (!wma_handle) {
3178 WMA_LOGE("%s: Failed to get WMA context", __func__);
3179 return CDF_STATUS_E_FAILURE;
3180 }
3181
3182 if (wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
3183 WMI_MGMT_RX_EVENTID) != 0) {
3184 WMA_LOGE("Failed to Unregister rx mgmt handler with wmi");
3185 return CDF_STATUS_E_FAILURE;
3186 }
3187 wma_handle->mgmt_rx = NULL;
3188 return CDF_STATUS_SUCCESS;
3189}
3190
3191/**
3192 * wma_register_mgmt_frm_client() - register management frame callback
3193 * @cds_ctx: cds context
3194 * @mgmt_frm_rx: management frame
3195 *
3196 * Return: CDF status
3197 */
3198CDF_STATUS wma_register_mgmt_frm_client(
3199 void *cds_ctx, wma_mgmt_frame_rx_callback mgmt_frm_rx)
3200{
3201 tp_wma_handle wma_handle = cds_get_context(CDF_MODULE_ID_WMA);
3202
3203 if (!wma_handle) {
3204 WMA_LOGE("%s: Failed to get WMA context", __func__);
3205 return CDF_STATUS_E_FAILURE;
3206 }
3207
3208 if (wmi_unified_register_event_handler(wma_handle->wmi_handle,
3209 WMI_MGMT_RX_EVENTID,
3210 wma_mgmt_rx_process) != 0) {
3211 WMA_LOGE("Failed to register rx mgmt handler with wmi");
3212 return CDF_STATUS_E_FAILURE;
3213 }
3214 wma_handle->mgmt_rx = mgmt_frm_rx;
3215
3216 return CDF_STATUS_SUCCESS;
3217}