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