blob: ec8b742263c859eee5fb216906c856a05d646b20 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2012-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#include "sme_api.h"
29#include "sms_debug.h"
30#include "csr_inside_api.h"
31#include "sme_inside.h"
32#include "p2p_api.h"
33#include "lim_api.h"
34#include "cfg_api.h"
35#include "wma.h"
36
37/*------------------------------------------------------------------
38 *
39 * handle SME remain on channel request.
40 *
41 *------------------------------------------------------------------*/
42
43CDF_STATUS p2p_process_remain_on_channel_cmd(tpAniSirGlobal pMac,
44 tSmeCmd *p2pRemainonChn)
45{
46 CDF_STATUS status = CDF_STATUS_E_FAILURE;
47 tSirRemainOnChnReq *pMsg;
48 uint32_t len;
49 tCsrRoamSession *pSession =
50 CSR_GET_SESSION(pMac, p2pRemainonChn->sessionId);
51
52 if (!pSession) {
53 sms_log(pMac, LOGE, FL(" session %d not found "),
54 p2pRemainonChn->sessionId);
55 goto error;
56 }
57
58 if (!pSession->sessionActive) {
59 sms_log(pMac, LOGE,
60 FL(" session %d is invalid or listen is disabled "),
61 p2pRemainonChn->sessionId);
62 goto error;
63 }
64 len = sizeof(tSirRemainOnChnReq) + pMac->p2pContext.probeRspIeLength;
65
66 if (len > 0xFFFF) {
67 /*In coming len for Msg is more then 16bit value */
68 sms_log(pMac, LOGE, FL(" Message length is very large, %d"),
69 len);
70 goto error;
71 }
72
73 pMsg = cdf_mem_malloc(len);
74 if (NULL == pMsg)
75 goto error;
76 else {
77 CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "%s call",
78 __func__);
79 cdf_mem_set(pMsg, sizeof(tSirRemainOnChnReq), 0);
80 pMsg->messageType = eWNI_SME_REMAIN_ON_CHANNEL_REQ;
81 pMsg->length = (uint16_t) len;
82 cdf_mem_copy(pMsg->selfMacAddr, pSession->selfMacAddr.bytes,
83 sizeof(tSirMacAddr));
84 pMsg->chnNum = p2pRemainonChn->u.remainChlCmd.chn;
85 pMsg->phyMode = p2pRemainonChn->u.remainChlCmd.phyMode;
86 pMsg->duration = p2pRemainonChn->u.remainChlCmd.duration;
87 pMsg->sessionId = p2pRemainonChn->sessionId;
88 pMsg->isProbeRequestAllowed =
89 p2pRemainonChn->u.remainChlCmd.isP2PProbeReqAllowed;
90 pMsg->scan_id = p2pRemainonChn->u.remainChlCmd.scan_id;
91 if (pMac->p2pContext.probeRspIeLength)
92 cdf_mem_copy((void *)pMsg->probeRspIe,
93 (void *)pMac->p2pContext.probeRspIe,
94 pMac->p2pContext.probeRspIeLength);
95 status = cds_send_mb_message_to_mac(pMsg);
96 }
97error:
98 if (CDF_STATUS_E_FAILURE == status)
99 csr_release_roc_req_cmd(pMac);
100 return status;
101}
102
103/*------------------------------------------------------------------
104 *
105 * handle LIM remain on channel rsp: Success/failure.
106 *
107 *------------------------------------------------------------------*/
108
109CDF_STATUS sme_remain_on_chn_rsp(tpAniSirGlobal pMac, uint8_t *pMsg)
110{
111 CDF_STATUS status = CDF_STATUS_SUCCESS;
112 tListElem *pEntry = NULL;
113 tSmeCmd *pCommand = NULL;
114 bool fFound;
115 remainOnChanCallback callback = NULL;
116 struct sir_roc_rsp *rsp = (struct sir_roc_rsp *)pMsg;
117
118 csr_get_active_scan_entry(pMac, rsp->scan_id, &pEntry);
119 if (!pEntry) {
120 sms_log(pMac, LOGE, FL("No cmd found in active list."));
121 return status;
122 }
123
124 pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
125 if (eSmeCommandRemainOnChannel != pCommand->command)
126 return status;
127
128 callback = pCommand->u.remainChlCmd.callback;
129 if (callback)
130 callback(pMac, pCommand->u.remainChlCmd.callbackCtx,
131 rsp->status, rsp->scan_id);
132
133 fFound = csr_ll_remove_entry(&pMac->sme.smeScanCmdActiveList, pEntry,
134 LL_ACCESS_LOCK);
135 if (fFound) {
136 /* Now put this command back on the avilable command list */
137 sme_release_command(pMac, pCommand);
138 }
139 sme_process_pending_queue(pMac);
140 return status;
141}
142
143/*------------------------------------------------------------------
144 *
145 * Handle the Mgmt frm ind from LIM and forward to HDD.
146 *
147 *------------------------------------------------------------------*/
148
149CDF_STATUS sme_mgmt_frm_ind(tHalHandle hHal, tpSirSmeMgmtFrameInd pSmeMgmtFrm)
150{
151 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
152 CDF_STATUS status = CDF_STATUS_SUCCESS;
153 tCsrRoamInfo pRoamInfo = { 0 };
154 uint8_t i = 0;
155 uint32_t SessionId = pSmeMgmtFrm->sessionId;
156
157 pRoamInfo.nFrameLength =
158 pSmeMgmtFrm->mesgLen - sizeof(tSirSmeMgmtFrameInd);
159 pRoamInfo.pbFrames = pSmeMgmtFrm->frameBuf;
160 pRoamInfo.frameType = pSmeMgmtFrm->frameType;
161 pRoamInfo.rxChan = pSmeMgmtFrm->rxChan;
162 pRoamInfo.rxRssi = pSmeMgmtFrm->rxRssi;
163 if (CSR_IS_SESSION_ANY(SessionId)) {
164 for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
165 if (CSR_IS_SESSION_VALID(pMac, i)) {
166 SessionId = i;
167 break;
168 }
169 }
170 }
171
172 if (i == CSR_ROAM_SESSION_MAX) {
173 sms_log(pMac, LOGE, FL("No valid sessions found."));
174 return CDF_STATUS_E_FAILURE;
175 }
176 /* forward the mgmt frame to HDD */
177 csr_roam_call_callback(pMac, SessionId, &pRoamInfo, 0,
178 eCSR_ROAM_INDICATE_MGMT_FRAME, 0);
179
180 return status;
181}
182
183/*------------------------------------------------------------------
184 *
185 * Handle the remain on channel ready indication from PE
186 *
187 *------------------------------------------------------------------*/
188
189CDF_STATUS sme_remain_on_chn_ready(tHalHandle hHal, uint8_t *pMsg)
190{
191 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
192 CDF_STATUS status = CDF_STATUS_SUCCESS;
193 tListElem *pEntry = NULL;
194 tSmeCmd *pCommand = NULL;
195 tCsrRoamInfo RoamInfo;
196 struct sir_roc_rsp *rsp = (struct sir_roc_rsp *)pMsg;
197
198 csr_get_active_scan_entry(pMac, rsp->scan_id, &pEntry);
199 if (!pEntry) {
200 sms_log(pMac, LOGE, FL("No cmd found in active list."));
201 return status;
202 }
203 sms_log(pMac, LOG1,
204 FL("Ready Ind %d %d"), rsp->session_id, rsp->scan_id);
205 pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
206 if (eSmeCommandRemainOnChannel == pCommand->command) {
207 RoamInfo.roc_scan_id = rsp->scan_id;
208 /* forward the indication to HDD */
209 RoamInfo.pRemainCtx = pCommand->u.remainChlCmd.callbackCtx;
210 csr_roam_call_callback(pMac, rsp->session_id,
211 &RoamInfo, 0,
212 eCSR_ROAM_REMAIN_CHAN_READY, 0);
213 }
214
215 return status;
216}
217
218CDF_STATUS sme_send_action_cnf(tHalHandle hHal, uint8_t *pMsg)
219{
220 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
221 CDF_STATUS status = CDF_STATUS_SUCCESS;
222 tCsrRoamInfo RoamInfo;
223 tSirSmeRsp *pSmeRsp = (tSirSmeRsp *) pMsg;
224
225 /* forward the indication to HDD */
226 /* RoamInfo can be passed as NULL....todo */
227 csr_roam_call_callback(pMac, pSmeRsp->sessionId, &RoamInfo, 0,
228 eCSR_ROAM_SEND_ACTION_CNF,
229 (pSmeRsp->statusCode == eSIR_SME_SUCCESS) ? 0 :
230 eCSR_ROAM_RESULT_SEND_ACTION_FAIL);
231 return status;
232}
233
234CDF_STATUS sme_p2p_open(tHalHandle hHal)
235{
236 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
237 CDF_STATUS status = CDF_STATUS_SUCCESS;
238
239 /* If static structure is too big, Need to change this function to allocate memory dynamically */
240 cdf_mem_zero(&pMac->p2pContext, sizeof(tp2pContext));
241
242 if (!CDF_IS_STATUS_SUCCESS(status)) {
243 sme_p2p_close(hHal);
244 }
245
246 return status;
247}
248
249CDF_STATUS p2p_stop(tHalHandle hHal)
250{
251 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
252
253 if (pMac->p2pContext.probeRspIe) {
254 cdf_mem_free(pMac->p2pContext.probeRspIe);
255 pMac->p2pContext.probeRspIe = NULL;
256 }
257
258 pMac->p2pContext.probeRspIeLength = 0;
259
260 return CDF_STATUS_SUCCESS;
261}
262
263CDF_STATUS sme_p2p_close(tHalHandle hHal)
264{
265 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
266
267 if (pMac->p2pContext.probeRspIe) {
268 cdf_mem_free(pMac->p2pContext.probeRspIe);
269 pMac->p2pContext.probeRspIe = NULL;
270 }
271
272 pMac->p2pContext.probeRspIeLength = 0;
273
274 return CDF_STATUS_SUCCESS;
275}
276
277tSirRFBand get_rf_band(uint8_t channel)
278{
279 if ((channel >= SIR_11A_CHANNEL_BEGIN) &&
280 (channel <= SIR_11A_CHANNEL_END))
281 return SIR_BAND_5_GHZ;
282
283 if ((channel >= SIR_11B_CHANNEL_BEGIN) &&
284 (channel <= SIR_11B_CHANNEL_END))
285 return SIR_BAND_2_4_GHZ;
286
287 return SIR_BAND_UNKNOWN;
288}
289
290/* ---------------------------------------------------------------------------
291
292 \fn p2p_remain_on_channel
293 \brief API to post the remain on channel command.
294 \param hHal - The handle returned by mac_open.
295 \param sessinId - HDD session ID.
296 \param channel - Channel to remain on channel.
297 \param duration - Duration for which we should remain on channel
298 \param callback - callback function.
299 \param pContext - argument to the callback function
300 \return CDF_STATUS
301
302 -------------------------------------------------------------------------------*/
303CDF_STATUS p2p_remain_on_channel(tHalHandle hHal, uint8_t sessionId,
304 uint8_t channel, uint32_t duration,
305 remainOnChanCallback callback,
306 void *pContext, uint8_t isP2PProbeReqAllowed,
307 uint32_t scan_id)
308{
309 CDF_STATUS status = CDF_STATUS_SUCCESS;
310 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
311 tSmeCmd *pRemainChlCmd = NULL;
312 uint32_t phyMode;
313
314 pRemainChlCmd = sme_get_command_buffer(pMac);
315 if (pRemainChlCmd == NULL)
316 return CDF_STATUS_E_FAILURE;
317
318 if (SIR_BAND_5_GHZ == get_rf_band(channel)) {
319 phyMode = WNI_CFG_PHY_MODE_11A;
320 } else {
321 phyMode = WNI_CFG_PHY_MODE_11G;
322 }
323
324 cfg_set_int(pMac, WNI_CFG_PHY_MODE, phyMode);
325
326 do {
327 /* call set in context */
328 pRemainChlCmd->command = eSmeCommandRemainOnChannel;
329 pRemainChlCmd->sessionId = sessionId;
330 pRemainChlCmd->u.remainChlCmd.chn = channel;
331 pRemainChlCmd->u.remainChlCmd.duration = duration;
332 pRemainChlCmd->u.remainChlCmd.isP2PProbeReqAllowed =
333 isP2PProbeReqAllowed;
334 pRemainChlCmd->u.remainChlCmd.callback = callback;
335 pRemainChlCmd->u.remainChlCmd.callbackCtx = pContext;
336 pRemainChlCmd->u.remainChlCmd.scan_id = scan_id;
337
338 /* Put it at the head of the Q if we just finish finding the peer and ready to send a frame */
339 status = csr_queue_sme_command(pMac, pRemainChlCmd, false);
340 } while (0);
341
342 sms_log(pMac, LOGW, "exiting function %s", __func__);
343
344 return (status);
345}
346
347CDF_STATUS p2p_send_action(tHalHandle hHal, uint8_t sessionId,
348 const uint8_t *pBuf, uint32_t len, uint16_t wait,
349 bool noack, uint16_t channel_freq)
350{
351 CDF_STATUS status = CDF_STATUS_SUCCESS;
352 tSirMbMsgP2p *pMsg;
353 uint16_t msgLen;
354
355 CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED,
356 " %s sends action frame", __func__);
357 msgLen = (uint16_t) ((sizeof(tSirMbMsgP2p)) + len);
358 pMsg = cdf_mem_malloc(msgLen);
359 if (NULL == pMsg)
360 status = CDF_STATUS_E_NOMEM;
361 else {
362 cdf_mem_set((void *)pMsg, msgLen, 0);
363 pMsg->type = eWNI_SME_SEND_ACTION_FRAME_IND;
364 pMsg->msgLen = msgLen;
365 pMsg->sessionId = sessionId;
366 pMsg->noack = noack;
367 pMsg->channel_freq = channel_freq;
368 pMsg->wait = (uint16_t) wait;
369 cdf_mem_copy(pMsg->data, pBuf, len);
370 status = cds_send_mb_message_to_mac(pMsg);
371 }
372 return (status);
373}
374
375CDF_STATUS p2p_cancel_remain_on_channel(tHalHandle hHal,
376 uint8_t sessionId, uint32_t scan_id)
377{
378 CDF_STATUS status = CDF_STATUS_SUCCESS;
379 tSirMbMsgP2p *pMsg;
380 uint16_t msgLen;
381
382 /* Need to check session ID to support concurrency */
383
384 msgLen = (uint16_t) (sizeof(tSirMbMsgP2p));
385 pMsg = cdf_mem_malloc(msgLen);
386 if (NULL == pMsg)
387 status = CDF_STATUS_E_NOMEM;
388 else {
389 cdf_mem_set((void *)pMsg, msgLen, 0);
390 pMsg->type = eWNI_SME_ABORT_REMAIN_ON_CHAN_IND;
391 pMsg->msgLen = msgLen;
392 pMsg->sessionId = sessionId;
393 pMsg->scan_id = scan_id;
394 status = cds_send_mb_message_to_mac(pMsg);
395 }
396
397 return (status);
398}
399
400CDF_STATUS p2p_set_ps(tHalHandle hHal, tP2pPsConfig *pNoA)
401{
402 tpP2pPsConfig pNoAParam;
403 tSirMsgQ msg;
404 CDF_STATUS status = CDF_STATUS_SUCCESS;
405 tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
406
407 pNoAParam = cdf_mem_malloc(sizeof(tP2pPsConfig));
408 if (NULL == pNoAParam)
409 status = CDF_STATUS_E_NOMEM;
410 else {
411 cdf_mem_set(pNoAParam, sizeof(tP2pPsConfig), 0);
412 cdf_mem_copy(pNoAParam, pNoA, sizeof(tP2pPsConfig));
413 msg.type = eWNI_SME_UPDATE_NOA;
414 msg.bodyval = 0;
415 msg.bodyptr = pNoAParam;
416 lim_post_msg_api(pMac, &msg);
417 }
418 return status;
419}