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