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