blob: fb48f5f273148b6195c75297fc58238daa97101c [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 *
30 * @file wlan_hdd_p2p.c
31 *
32 * @brief WLAN Host Device Driver implementation for P2P commands interface
33 *
34 */
35
36#include <wlan_hdd_includes.h>
37#include <wlan_hdd_hostapd.h>
38#include <net/cfg80211.h>
39#include "sme_api.h"
40#include "sme_qos_api.h"
41#include "wlan_hdd_p2p.h"
42#include "sap_api.h"
43#include "wlan_hdd_main.h"
44#include "cdf_trace.h"
45#include <linux/netdevice.h>
46#include <linux/skbuff.h>
47#include <linux/etherdevice.h>
48#include <net/ieee80211_radiotap.h>
49#include "wlan_hdd_tdls.h"
50#include "wlan_hdd_trace.h"
51#include "cdf_types.h"
52#include "cdf_trace.h"
53#include "cds_sched.h"
54#include "cds_concurrency.h"
55
56/* Ms to Micro Sec */
57#define MS_TO_MUS(x) ((x) * 1000)
58
59static uint8_t *hdd_get_action_string(uint16_t MsgType)
60{
61 switch (MsgType) {
62 CASE_RETURN_STRING(SIR_MAC_ACTION_SPECTRUM_MGMT);
63 CASE_RETURN_STRING(SIR_MAC_ACTION_QOS_MGMT);
64 CASE_RETURN_STRING(SIR_MAC_ACTION_DLP);
65 CASE_RETURN_STRING(SIR_MAC_ACTION_PUBLIC_USAGE);
66 CASE_RETURN_STRING(SIR_MAC_ACTION_RRM);
67 CASE_RETURN_STRING(SIR_MAC_ACTION_FAST_BSS_TRNST);
68 CASE_RETURN_STRING(SIR_MAC_ACTION_HT);
69 CASE_RETURN_STRING(SIR_MAC_ACTION_SA_QUERY);
70 CASE_RETURN_STRING(SIR_MAC_ACTION_PROT_DUAL_PUB);
71 CASE_RETURN_STRING(SIR_MAC_ACTION_WNM);
72 CASE_RETURN_STRING(SIR_MAC_ACTION_UNPROT_WNM);
73 CASE_RETURN_STRING(SIR_MAC_ACTION_TDLS);
74 CASE_RETURN_STRING(SIR_MAC_ACITON_MESH);
75 CASE_RETURN_STRING(SIR_MAC_ACTION_MHF);
76 CASE_RETURN_STRING(SIR_MAC_SELF_PROTECTED);
77 CASE_RETURN_STRING(SIR_MAC_ACTION_WME);
78 CASE_RETURN_STRING(SIR_MAC_ACTION_VHT);
79 default:
80 return "UNKNOWN";
81 }
82}
83
84#ifdef WLAN_FEATURE_P2P_DEBUG
85#define MAX_P2P_ACTION_FRAME_TYPE 9
86const char *p2p_action_frame_type[] = { "GO Negotiation Request",
87 "GO Negotiation Response",
88 "GO Negotiation Confirmation",
89 "P2P Invitation Request",
90 "P2P Invitation Response",
91 "Device Discoverability Request",
92 "Device Discoverability Response",
93 "Provision Discovery Request",
94 "Provision Discovery Response"};
95
96/* We no need to protect this variable since
97 * there is no chance of race to condition
98 * and also not make any complicating the code
99 * just for debugging log
100 */
101tP2PConnectionStatus global_p2p_connection_status = P2P_NOT_ACTIVE;
102
103#endif
104#define MAX_TDLS_ACTION_FRAME_TYPE 11
105const char *tdls_action_frame_type[] = { "TDLS Setup Request",
106 "TDLS Setup Response",
107 "TDLS Setup Confirm",
108 "TDLS Teardown",
109 "TDLS Peer Traffic Indication",
110 "TDLS Channel Switch Request",
111 "TDLS Channel Switch Response",
112 "TDLS Peer PSM Request",
113 "TDLS Peer PSM Response",
114 "TDLS Peer Traffic Response",
115 "TDLS Discovery Request"};
116
117static bool wlan_hdd_is_type_p2p_action(const u8 *buf)
118{
119 const u8 *ouiPtr;
120
121 if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET] !=
122 WLAN_HDD_PUBLIC_ACTION_FRAME) {
123 return false;
124 }
125
126 if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET] !=
127 WLAN_HDD_VENDOR_SPECIFIC_ACTION) {
128 return false;
129 }
130
131 ouiPtr = &buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET];
132
133 if (WPA_GET_BE24(ouiPtr) != WLAN_HDD_WFA_OUI) {
134 return false;
135 }
136
137 if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET] !=
138 WLAN_HDD_WFA_P2P_OUI_TYPE) {
139 return false;
140 }
141
142 return true;
143}
144
145static bool hdd_p2p_is_action_type_rsp(const u8 *buf)
146{
147 tActionFrmType actionFrmType;
148
149 if (wlan_hdd_is_type_p2p_action(buf)) {
150 actionFrmType =
151 buf[WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET];
152 if (actionFrmType != WLAN_HDD_INVITATION_REQ
153 && actionFrmType != WLAN_HDD_GO_NEG_REQ
154 && actionFrmType != WLAN_HDD_DEV_DIS_REQ
155 && actionFrmType != WLAN_HDD_PROV_DIS_REQ)
156 return true;
157 }
158
159 return false;
160}
161
162static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530163QDF_STATUS wlan_hdd_remain_on_channel_callback(tHalHandle hHal, void *pCtx,
164 QDF_STATUS status, uint32_t scan_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165{
166 hdd_adapter_t *pAdapter = (hdd_adapter_t *) pCtx;
167 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
168 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
169 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
170
171 if (!hdd_ctx) {
172 hdd_err("Invalid HDD context");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530173 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174 }
175
176 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
177 pRemainChanCtx = cfgState->remain_on_chan_ctx;
178
179 if (pRemainChanCtx == NULL) {
180 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
181 hddLog(LOGW,
182 "%s: No Rem on channel pending for which Rsp is received",
183 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530184 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185 }
186
187 hddLog(LOG1, "Received remain on channel rsp");
188 cdf_mc_timer_stop(&pRemainChanCtx->hdd_remain_on_chan_timer);
189 cdf_mc_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer);
190
191 cfgState->remain_on_chan_ctx = NULL;
192 /*
193 * Resetting the roc in progress early ensures that the subsequent
194 * roc requests are immediately processed without being queued
195 */
196 pAdapter->is_roc_inprogress = false;
197 /*
198 * If the allow suspend is done later, the scheduled roc wil prevent
199 * the system from going into suspend and immediately this logic
200 * will allow the system to go to suspend breaking the exising logic.
201 * Basically, the system must not go into suspend while roc is in
202 * progress.
203 */
204 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
205 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
206
207 if (REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request) {
208 if (cfgState->buf) {
209 hddLog(LOGP,
210 "%s: We need to receive yet an ack from one of tx packet",
211 __func__);
212 }
213 cfg80211_remain_on_channel_expired(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214 pRemainChanCtx->dev->
215 ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800216 pRemainChanCtx->
217 cookie,
218 &pRemainChanCtx->chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800219 GFP_KERNEL);
220 pAdapter->last_roc_ts = cdf_mc_timer_get_system_time();
221 }
222
223 /* Schedule any pending RoC: Any new roc request during this time
224 * would have got queued in 'wlan_hdd_request_remain_on_channel'
225 * since the queue is not empty. So, the roc at the head of the
226 * queue will only get the priority. Scheduling the work queue
227 * after sending any cancel remain on channel event will also
228 * ensure that the cancel roc is sent without any delays.
229 */
230 schedule_delayed_work(&hdd_ctx->roc_req_work, 0);
231
232 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
233 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
234 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
235 ) {
236 uint8_t sessionId = pAdapter->sessionId;
237 if (REMAIN_ON_CHANNEL_REQUEST ==
238 pRemainChanCtx->rem_on_chan_request) {
239 sme_deregister_mgmt_frame(hHal, sessionId,
240 (SIR_MAC_MGMT_FRAME << 2) |
241 (SIR_MAC_MGMT_PROBE_REQ << 4),
242 NULL, 0);
243 }
244 } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
245 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
246 ) {
247 wlansap_de_register_mgmt_frame(
248#ifdef WLAN_FEATURE_MBSSID
249 WLAN_HDD_GET_SAP_CTX_PTR
250 (pAdapter),
251#else
252 (WLAN_HDD_GET_CTX
253 (pAdapter))->pcds_context,
254#endif
255 (SIR_MAC_MGMT_FRAME << 2) |
256 (SIR_MAC_MGMT_PROBE_REQ <<
257 4), NULL, 0);
258
259 }
260
261 if (pRemainChanCtx->action_pkt_buff.frame_ptr != NULL
262 && pRemainChanCtx->action_pkt_buff.frame_length != 0) {
263 cdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr);
264 pRemainChanCtx->action_pkt_buff.frame_ptr = NULL;
265 pRemainChanCtx->action_pkt_buff.frame_length = 0;
266 }
267 cdf_mem_free(pRemainChanCtx);
268 complete(&pAdapter->cancel_rem_on_chan_var);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530269 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800270 complete(&pAdapter->rem_on_chan_ready_event);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530271 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272}
273
274void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter)
275{
276 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
277 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
278 unsigned long rc;
279
280 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
281 if (cfgState->remain_on_chan_ctx != NULL) {
282 hddLog(LOGE, "Cancel Existing Remain on Channel");
283
284 if (CDF_TIMER_STATE_RUNNING == cdf_mc_timer_get_current_state(
Anurag Chouhanffb21542016-02-17 14:33:03 +0530285 &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800286 cdf_mc_timer_stop(&cfgState->remain_on_chan_ctx->
287 hdd_remain_on_chan_timer);
288
289 pRemainChanCtx = cfgState->remain_on_chan_ctx;
290 if (pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress ==
291 true) {
292 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
293 hddLog(LOGE,
294 "ROC timer cancellation in progress,"
295 " wait for completion");
296 rc = wait_for_completion_timeout(&pAdapter->
297 cancel_rem_on_chan_var,
298 msecs_to_jiffies
299 (WAIT_CANCEL_REM_CHAN));
300 if (!rc) {
301 hddLog(LOGE,
302 "%s:wait on cancel_rem_on_chan_var timed out",
303 __func__);
304 }
305 return;
306 }
307 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true;
308 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
309 /* Wait till remain on channel ready indication before issuing cancel
310 * remain on channel request, otherwise if remain on channel not
311 * received and if the driver issues cancel remain on channel then lim
312 * will be in unknown state.
313 */
314 rc = wait_for_completion_timeout(&pAdapter->
315 rem_on_chan_ready_event,
316 msecs_to_jiffies
317 (WAIT_REM_CHAN_READY));
318 if (!rc) {
319 hddLog(LOGE,
320 "%s: timeout waiting for remain on channel ready indication",
321 __func__);
322 }
323
324 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
325
326 /* Issue abort remain on chan request to sme.
327 * The remain on channel callback will make sure the remain_on_chan
328 * expired event is sent.
329 */
330 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
331 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
332 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
333 ) {
334 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX
335 (pAdapter),
336 pAdapter->sessionId,
337 pRemainChanCtx->scan_id);
338 } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode)
339 || (WLAN_HDD_P2P_GO == pAdapter->device_mode)
340 ) {
341 wlansap_cancel_remain_on_channel(
342#ifdef WLAN_FEATURE_MBSSID
343 WLAN_HDD_GET_SAP_CTX_PTR
344 (pAdapter),
345#else
346 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
347#endif
348 pRemainChanCtx->scan_id);
349 }
350
351 rc = wait_for_completion_timeout(&pAdapter->
352 cancel_rem_on_chan_var,
353 msecs_to_jiffies
354 (WAIT_CANCEL_REM_CHAN));
355
356 if (!rc) {
357 hddLog(LOGE,
358 "%s: timeout waiting for cancel remain on channel ready"
359 " indication", __func__);
360 }
361 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
362 } else
363 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
364}
365
366int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter)
367{
368 int status = 0;
369 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
370
371 if (WLAN_HDD_P2P_GO != pAdapter->device_mode) {
372 /* Cancel Existing Remain On Channel */
373 /* If no action frame is pending */
374 if (cfgState->remain_on_chan_ctx != NULL) {
375 /* Check whether Action Frame is pending or not */
376 if (cfgState->buf == NULL) {
377 wlan_hdd_cancel_existing_remain_on_channel
378 (pAdapter);
379 } else {
380 hddLog(LOG1,
381 "Cannot Cancel Existing Remain on Channel");
382 status = -EBUSY;
383 }
384 }
385 }
386 return status;
387}
388
389/**
390 * wlan_hdd_cancel_pending_roc() - Cancel pending roc
391 * @adapter: HDD adapter
392 *
393 * Cancels any pending remain on channel request
394 *
395 * Return: None
396 */
397void wlan_hdd_cancel_pending_roc(hdd_adapter_t *adapter)
398{
399 hdd_remain_on_chan_ctx_t *roc_ctx;
400 unsigned long rc;
401 hdd_cfg80211_state_t *cfg_state = WLAN_HDD_GET_CFG_STATE_PTR(adapter);
402
403 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
404 "%s: ROC completion is not received.!!!",
405 __func__);
406
407 mutex_lock(&cfg_state->remain_on_chan_ctx_lock);
408 roc_ctx = cfg_state->remain_on_chan_ctx;
409
410 if (roc_ctx->hdd_remain_on_chan_cancel_in_progress) {
411 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
412 hdd_debug("roc cancel already in progress");
413 /*
414 * Since a cancel roc is already issued and is
415 * in progress, we need not send another
416 * cancel roc again. Instead we can just wait
417 * for cancel roc completion
418 */
419 goto wait;
420 }
421 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
422
423 if (adapter->device_mode == WLAN_HDD_P2P_GO) {
424 wlansap_cancel_remain_on_channel((WLAN_HDD_GET_CTX
425 (adapter))->pcds_context,
426 cfg_state->remain_on_chan_ctx->scan_id);
427 } else if (adapter->device_mode == WLAN_HDD_P2P_CLIENT
428 || adapter->device_mode ==
429 WLAN_HDD_P2P_DEVICE) {
430 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX
431 (adapter),
432 adapter->sessionId,
433 cfg_state->remain_on_chan_ctx->scan_id);
434 }
435
436wait:
437 rc = wait_for_completion_timeout(&adapter->cancel_rem_on_chan_var,
438 msecs_to_jiffies
439 (WAIT_CANCEL_REM_CHAN));
440 if (!rc) {
441 CDF_TRACE(CDF_MODULE_ID_HDD,
442 CDF_TRACE_LEVEL_ERROR,
443 "%s: Timeout occurred while waiting for RoC Cancellation",
444 __func__);
445 mutex_lock(&cfg_state->remain_on_chan_ctx_lock);
446 roc_ctx = cfg_state->remain_on_chan_ctx;
447 if (roc_ctx != NULL) {
448 cfg_state->remain_on_chan_ctx = NULL;
449 cdf_mc_timer_stop(&roc_ctx->hdd_remain_on_chan_timer);
450 cdf_mc_timer_destroy(
451 &roc_ctx->hdd_remain_on_chan_timer);
452 if (roc_ctx->action_pkt_buff.frame_ptr != NULL
453 && roc_ctx->action_pkt_buff.frame_length != 0) {
454 cdf_mem_free(
455 roc_ctx->action_pkt_buff.frame_ptr);
456 roc_ctx->action_pkt_buff.frame_ptr = NULL;
457 roc_ctx->action_pkt_buff.frame_length = 0;
458 }
459 cdf_mem_free(roc_ctx);
460 adapter->is_roc_inprogress = false;
461 }
462 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
463 }
464}
465
466/* Clean up RoC context at hdd_stop_adapter*/
467void wlan_hdd_cleanup_remain_on_channel_ctx(hdd_adapter_t *pAdapter)
468{
469 uint8_t retry = 0;
470 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
471
472 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
473 while (pAdapter->is_roc_inprogress) {
474 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
475 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
476 "%s: ROC in progress for session %d!!!",
477 __func__, pAdapter->sessionId);
478 msleep(500);
479 if (retry++ > 3) {
480 wlan_hdd_cancel_pending_roc(pAdapter);
481 /* hold the lock before break from the loop */
482 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
483 break;
484 }
485 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
486 } /* end of while */
487 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
488
489}
490
491void wlan_hdd_remain_on_chan_timeout(void *data)
492{
493 hdd_adapter_t *pAdapter = (hdd_adapter_t *) data;
494 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
495 hdd_cfg80211_state_t *cfgState;
496
497 if (NULL == pAdapter) {
498 hddLog(LOGE, "%s: pAdapter is NULL !!!", __func__);
499 return;
500 }
501
502 cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
503 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
504 pRemainChanCtx = cfgState->remain_on_chan_ctx;
505
506 if (NULL == pRemainChanCtx) {
507 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
508 hddLog(LOGE, "%s: No Remain on channel is pending", __func__);
509 return;
510 }
511
512 if (true == pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) {
513 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
514 hddLog(LOGE, FL("Cancellation already in progress"));
515 return;
516 }
517
518 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true;
519 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
520 hddLog(LOG1, "%s: Cancel Remain on Channel on timeout", __func__);
521
522 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
523 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
524 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
525 ) {
526 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter),
527 pAdapter->sessionId,
528 pRemainChanCtx->scan_id);
529 } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
530 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
531 ) {
532 wlansap_cancel_remain_on_channel(
533 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
534 pRemainChanCtx->scan_id);
535 }
536
537 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
538
539}
540
541static int wlan_hdd_execute_remain_on_channel(hdd_adapter_t *pAdapter,
542 hdd_remain_on_chan_ctx_t *pRemainChanCtx)
543{
544 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530545 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
547 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
548 hdd_adapter_t *pAdapter_temp;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530549 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 bool isGoPresent = false;
551 unsigned int duration;
552
553
554 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
555 if (pAdapter->is_roc_inprogress == true) {
556 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
557 hddLog(CDF_TRACE_LEVEL_ERROR,
558 FL("remain on channel request is in execution"));
559 return -EBUSY;
560 }
561
562 cfgState->remain_on_chan_ctx = pRemainChanCtx;
563 cfgState->current_freq = pRemainChanCtx->chan.center_freq;
564 pAdapter->is_roc_inprogress = true;
565 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
566
567 /* Initialize Remain on chan timer */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530568 qdf_status =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800569 cdf_mc_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer,
570 CDF_TIMER_TYPE_SW,
571 wlan_hdd_remain_on_chan_timeout, pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530572 if (qdf_status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800573 hddLog(CDF_TRACE_LEVEL_ERROR,
574 FL("Not able to initialize remain_on_chan timer"));
575 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
576 cfgState->remain_on_chan_ctx = NULL;
577 pAdapter->is_roc_inprogress = false;
578 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
579 cdf_mem_free(pRemainChanCtx);
580 return -EINVAL;
581 }
582
583 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530584 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585 pAdapter_temp = pAdapterNode->pAdapter;
586 if (pAdapter_temp->device_mode == WLAN_HDD_P2P_GO) {
587 isGoPresent = true;
588 }
589 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
590 pAdapterNode = pNext;
591 }
592
593 /* Extending duration for proactive extension logic for RoC */
594 duration = pRemainChanCtx->duration;
595 if (isGoPresent == true)
596 duration = P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT * duration;
597 else
598 duration = P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT * duration;
599
600 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
601 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
602
603 /* call sme API to start remain on channel. */
604 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
605 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
606 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
607 ) {
608 uint8_t sessionId = pAdapter->sessionId;
609 /* call sme API to start remain on channel. */
610
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530611 if (QDF_STATUS_SUCCESS != sme_remain_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800612 WLAN_HDD_GET_HAL_CTX(pAdapter),
613 sessionId,
614 pRemainChanCtx->chan.hw_value, duration,
615 wlan_hdd_remain_on_channel_callback,
616 pAdapter,
617 (pRemainChanCtx->rem_on_chan_request ==
618 REMAIN_ON_CHANNEL_REQUEST) ? true : false,
619 &pRemainChanCtx->scan_id)) {
620 hddLog(LOGE, FL("sme_remain_on_channel failed"));
621 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
622 cfgState->remain_on_chan_ctx = NULL;
623 pAdapter->is_roc_inprogress = false;
624 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
625 cdf_mc_timer_destroy(
626 &pRemainChanCtx->hdd_remain_on_chan_timer);
627 cdf_mem_free(pRemainChanCtx);
628 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
629 return -EINVAL;
630 }
631
632 if (REMAIN_ON_CHANNEL_REQUEST ==
633 pRemainChanCtx->rem_on_chan_request) {
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530634 if (QDF_STATUS_SUCCESS != sme_register_mgmt_frame(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800635 WLAN_HDD_GET_HAL_CTX(pAdapter),
636 sessionId,
637 (SIR_MAC_MGMT_FRAME << 2) |
638 (SIR_MAC_MGMT_PROBE_REQ << 4),
639 NULL, 0))
640 hddLog(LOGE,
641 FL("sme_register_mgmt_frame failed"));
642 }
643
644 } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
645 (WLAN_HDD_P2P_GO == pAdapter->device_mode)) {
646 /* call sme API to start remain on channel. */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530647 if (QDF_STATUS_SUCCESS != wlansap_remain_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800648#ifdef WLAN_FEATURE_MBSSID
649 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
650#else
651 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
652#endif
653 pRemainChanCtx->chan.hw_value,
654 duration, wlan_hdd_remain_on_channel_callback,
655 pAdapter, &pRemainChanCtx->scan_id)) {
656 hddLog(LOGE, FL("wlansap_remain_on_channel failed"));
657 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
658 cfgState->remain_on_chan_ctx = NULL;
659 pAdapter->is_roc_inprogress = false;
660 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
661 cdf_mc_timer_destroy(
662 &pRemainChanCtx->hdd_remain_on_chan_timer);
663 cdf_mem_free(pRemainChanCtx);
664 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
665 return -EINVAL;
666 }
667
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530668 if (QDF_STATUS_SUCCESS != wlansap_register_mgmt_frame(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800669#ifdef WLAN_FEATURE_MBSSID
670 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
671#else
672 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
673#endif
674 (SIR_MAC_MGMT_FRAME << 2) |
675 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0)) {
676 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
677 FL("wlansap_register_mgmt_frame return fail"));
678 wlansap_cancel_remain_on_channel(
679#ifdef WLAN_FEATURE_MBSSID
680 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
681#else
682 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
683#endif
684 pRemainChanCtx->scan_id);
685 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
686 return -EINVAL;
687 }
688
689 }
690 return 0;
691}
692
693/**
694 * wlan_hdd_roc_request_enqueue() - enqueue remain on channel request
695 * @adapter: Pointer to the adapter
696 * @remain_chan_ctx: Pointer to the remain on channel context
697 *
698 * Return: 0 on success, error number otherwise
699 */
700static int wlan_hdd_roc_request_enqueue(hdd_adapter_t *adapter,
701 hdd_remain_on_chan_ctx_t *remain_chan_ctx)
702{
703 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
704 hdd_roc_req_t *hdd_roc_req;
Anurag Chouhanffb21542016-02-17 14:33:03 +0530705 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800706
707 /*
708 * "Driver is busy" OR "there is already RoC request inside the queue"
709 * so enqueue this RoC Request and execute sequentially later.
710 */
711
712 hdd_roc_req = cdf_mem_malloc(sizeof(*hdd_roc_req));
713
714 if (NULL == hdd_roc_req) {
715 hddLog(LOGP, FL("malloc failed for roc req context"));
716 return -ENOMEM;
717 }
718
719 hdd_roc_req->pAdapter = adapter;
720 hdd_roc_req->pRemainChanCtx = remain_chan_ctx;
721
722 /* Enqueue this RoC request */
723 cdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530724 status = qdf_list_insert_back(&hdd_ctx->hdd_roc_req_q,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800725 &hdd_roc_req->node);
726 cdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock);
727
Anurag Chouhanffb21542016-02-17 14:33:03 +0530728 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729 hddLog(LOGP, FL("Not able to enqueue RoC Req context"));
730 cdf_mem_free(hdd_roc_req);
731 return -EINVAL;
732 }
733
734 return 0;
735}
736
737/**
738 * wlan_hdd_indicate_roc_drop() - Indicate roc drop to userspace
739 * @adapter: HDD adapter
740 * @ctx: Remain on channel context
741 *
742 * Send remain on channel ready and cancel event for the queued
743 * roc that is being dropped. This will ensure that the userspace
744 * will send more roc requests. If this drop is not indicated to
745 * userspace, subsequent roc will not be sent to the driver since
746 * the userspace times out waiting for the remain on channel ready
747 * event.
748 *
749 * Return: None
750 */
751void wlan_hdd_indicate_roc_drop(hdd_adapter_t *adapter,
752 hdd_remain_on_chan_ctx_t *ctx)
753{
754 hdd_debug("indicate roc drop to userspace");
755 cfg80211_ready_on_channel(
756 adapter->dev->ieee80211_ptr,
757 (uintptr_t)ctx,
758 &ctx->chan,
759 ctx->duration, GFP_KERNEL);
760
761 cfg80211_remain_on_channel_expired(
762 ctx->dev->ieee80211_ptr,
763 ctx->cookie,
764 &ctx->chan,
765 GFP_KERNEL);
766}
767
768/**
769 * wlan_hdd_roc_request_dequeue() - dequeue remain on channel request
770 * @work: Pointer to work queue struct
771 *
772 * Return: none
773 */
774void wlan_hdd_roc_request_dequeue(struct work_struct *work)
775{
Anurag Chouhanffb21542016-02-17 14:33:03 +0530776 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777 int ret = 0;
778 hdd_roc_req_t *hdd_roc_req;
779 hdd_context_t *hdd_ctx =
780 container_of(work, hdd_context_t, roc_req_work.work);
781
782 hdd_debug("going to dequeue roc");
783
784 if (0 != (wlan_hdd_validate_context(hdd_ctx)))
785 return;
786
787 /*
788 * The queued roc requests is dequeued and processed one at a time.
789 * Callback 'wlan_hdd_remain_on_channel_callback' ensures
790 * that any pending roc in the queue will be scheduled
791 * on the current roc completion by scheduling the work queue.
792 */
793 cdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock);
794 if (list_empty(&hdd_ctx->hdd_roc_req_q.anchor)) {
795 cdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock);
796 hdd_debug("list is empty");
797 return;
798 }
Anurag Chouhanffb21542016-02-17 14:33:03 +0530799 status = qdf_list_remove_front(&hdd_ctx->hdd_roc_req_q,
800 (qdf_list_node_t **) &hdd_roc_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800801 cdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530802 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800803 hdd_debug("unable to remove roc element from list");
804 return;
805 }
806 ret = wlan_hdd_execute_remain_on_channel(
807 hdd_roc_req->pAdapter,
808 hdd_roc_req->pRemainChanCtx);
809 if (ret == -EBUSY) {
810 hddLog(CDF_TRACE_LEVEL_ERROR,
811 FL("dropping RoC request"));
812 wlan_hdd_indicate_roc_drop(hdd_roc_req->pAdapter,
813 hdd_roc_req->pRemainChanCtx);
814 cdf_mem_free(hdd_roc_req->pRemainChanCtx);
815 }
816 cdf_mem_free(hdd_roc_req);
817}
818
819static int wlan_hdd_request_remain_on_channel(struct wiphy *wiphy,
820 struct net_device *dev,
821 struct ieee80211_channel *chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800822 unsigned int duration,
823 u64 *cookie,
824 rem_on_channel_request_type_t
825 request_type)
826{
827 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
828 hdd_context_t *pHddCtx;
829 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
830 bool isBusy = false;
831 uint32_t size = 0;
832 hdd_adapter_t *sta_adapter;
833 int ret;
834 int status = 0;
835
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530836 ENTER();
837
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800838 hddLog(LOG1, FL("Device_mode %s(%d)"),
839 hdd_device_mode_to_string(pAdapter->device_mode),
840 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841 hddLog(LOG1,
842 "chan(hw_val)0x%x chan(centerfreq) %d, duration %d",
843 chan->hw_value, chan->center_freq, duration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
845 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530846 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847 return ret;
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -0800848 if (cds_is_connection_in_progress()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800849 hddLog(LOGE, FL("Connection is in progress"));
850 isBusy = true;
851 }
852 pRemainChanCtx = cdf_mem_malloc(sizeof(hdd_remain_on_chan_ctx_t));
853 if (NULL == pRemainChanCtx) {
854 hddLog(CDF_TRACE_LEVEL_FATAL,
855 "%s: Not able to allocate memory for Channel context",
856 __func__);
857 return -ENOMEM;
858 }
859
860 cdf_mem_zero(pRemainChanCtx, sizeof(*pRemainChanCtx));
861 cdf_mem_copy(&pRemainChanCtx->chan, chan,
862 sizeof(struct ieee80211_channel));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800863 pRemainChanCtx->duration = duration;
864 pRemainChanCtx->dev = dev;
865 *cookie = (uintptr_t) pRemainChanCtx;
866 pRemainChanCtx->cookie = *cookie;
867 pRemainChanCtx->rem_on_chan_request = request_type;
868 pRemainChanCtx->action_pkt_buff.freq = 0;
869 pRemainChanCtx->action_pkt_buff.frame_ptr = NULL;
870 pRemainChanCtx->action_pkt_buff.frame_length = 0;
871 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = false;
872 if (REMAIN_ON_CHANNEL_REQUEST == request_type) {
873 sta_adapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530874 if ((NULL != sta_adapter) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875 hdd_conn_is_connected(
876 WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter))) {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530877 if (pAdapter->last_roc_ts != 0 &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 ((cdf_mc_timer_get_system_time() -
879 pAdapter->last_roc_ts) <
880 pHddCtx->config->p2p_listen_defer_interval)) {
881 if (pRemainChanCtx->duration > HDD_P2P_MAX_ROC_DURATION)
882 pRemainChanCtx->duration =
883 HDD_P2P_MAX_ROC_DURATION;
884
885 wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx);
886 schedule_delayed_work(&pHddCtx->roc_req_work,
887 msecs_to_jiffies(
888 pHddCtx->config->p2p_listen_defer_interval));
889 hddLog(LOG1, "Defer interval is %hu, pAdapter %p",
890 pHddCtx->config->p2p_listen_defer_interval,
891 pAdapter);
892 return 0;
893 }
894 }
895 }
896
897 cdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530898 size = qdf_list_size(&(pHddCtx->hdd_roc_req_q));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 cdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock);
900 if ((isBusy == false) && (!size)) {
901 status = wlan_hdd_execute_remain_on_channel(pAdapter,
902 pRemainChanCtx);
903 if (status == -EBUSY) {
904 if (wlan_hdd_roc_request_enqueue(pAdapter,
905 pRemainChanCtx)) {
906 cdf_mem_free(pRemainChanCtx);
907 return -EAGAIN;
908 }
909 }
910 return 0;
911 } else {
912 if (wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx)) {
913 cdf_mem_free(pRemainChanCtx);
914 return -EAGAIN;
915 }
916 }
917
918 /*
919 * If a connection is not in progress (isBusy), before scheduling
920 * the work queue it is necessary to check if a roc in in progress
921 * or not because: if an roc is in progress, the dequeued roc
922 * that will be processed will be dropped. To ensure that this new
923 * roc request is not dropped, it is suggested to check if an roc
924 * is in progress or not. The existing roc completion will provide
925 * the trigger to dequeue the next roc request.
926 */
927 if (isBusy == false && pAdapter->is_roc_inprogress == false) {
928 hdd_debug("scheduling delayed work: no connection/roc active");
929 schedule_delayed_work(&pHddCtx->roc_req_work, 0);
930 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530931 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 return 0;
933}
934
935int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800936 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937 struct ieee80211_channel *chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800938 unsigned int duration, u64 *cookie)
939{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800940 struct net_device *dev = wdev->netdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
942 hdd_context_t *hdd_ctx;
943 int ret;
944
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530945 ENTER();
946
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
948 ret = wlan_hdd_validate_context(hdd_ctx);
949 if (0 != ret)
950 return ret;
951
Peng Xuf5d60c82015-10-02 17:17:03 -0700952 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 hddLog(LOGE, FL("Command not allowed in FTM mode"));
954 return -EINVAL;
955 }
956
957 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
958 TRACE_CODE_HDD_REMAIN_ON_CHANNEL,
959 pAdapter->sessionId, REMAIN_ON_CHANNEL_REQUEST));
Amar Singhal01098f72015-10-08 11:55:32 -0700960
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530961 ret = wlan_hdd_request_remain_on_channel(wiphy, dev, chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 duration, cookie,
963 REMAIN_ON_CHANNEL_REQUEST);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530964 EXIT();
965 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800966}
967
968int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800969 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970 struct ieee80211_channel *chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800971 unsigned int duration, u64 *cookie)
972{
973 int ret;
974
975 cds_ssr_protect(__func__);
976 ret = __wlan_hdd_cfg80211_remain_on_channel(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800978 chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800979 duration, cookie);
980 cds_ssr_unprotect(__func__);
981
982 return ret;
983}
984
985void hdd_remain_chan_ready_handler(hdd_adapter_t *pAdapter,
986 uint32_t scan_id)
987{
988 hdd_cfg80211_state_t *cfgState = NULL;
989 hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530990 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991
992 if (NULL == pAdapter) {
993 hddLog(LOGE, FL("pAdapter is NULL"));
994 return;
995 }
996 cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
997 hddLog(LOG1, "Ready on chan ind %d", scan_id);
998
999 pAdapter->start_roc_ts = cdf_mc_timer_get_system_time();
1000 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1001 pRemainChanCtx = cfgState->remain_on_chan_ctx;
1002 if (pRemainChanCtx != NULL) {
1003 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
1004 TRACE_CODE_HDD_REMAINCHANREADYHANDLER,
1005 pAdapter->sessionId,
1006 pRemainChanCtx->duration));
1007 /* start timer for actual duration */
1008 if (CDF_TIMER_STATE_RUNNING ==
1009 cdf_mc_timer_get_current_state(
1010 &pRemainChanCtx->hdd_remain_on_chan_timer)) {
1011 hddLog(LOGE, "Timer Started before ready event!!!");
1012 cdf_mc_timer_stop(&pRemainChanCtx->
1013 hdd_remain_on_chan_timer);
1014 }
1015 status =
1016 cdf_mc_timer_start(&pRemainChanCtx->
1017 hdd_remain_on_chan_timer,
1018 (pRemainChanCtx->duration +
1019 COMPLETE_EVENT_PROPOGATE_TIME));
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301020 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 hddLog(LOGE, "%s: Remain on Channel timer start failed",
1022 __func__);
1023 }
1024
1025 if (REMAIN_ON_CHANNEL_REQUEST ==
1026 pRemainChanCtx->rem_on_chan_request) {
1027 cfg80211_ready_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 pAdapter->dev->
1029 ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 (uintptr_t)
1031 pRemainChanCtx,
1032 &pRemainChanCtx->chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001033 pRemainChanCtx->
1034 duration, GFP_KERNEL);
1035 } else if (OFF_CHANNEL_ACTION_TX ==
1036 pRemainChanCtx->rem_on_chan_request) {
1037 complete(&pAdapter->offchannel_tx_event);
1038 }
1039 /* Check for cached action frame */
1040 if (pRemainChanCtx->action_pkt_buff.frame_length != 0) {
1041 hddLog(LOGE,
1042 "%s: Sent cached action frame to supplicant",
1043 __func__);
1044#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
1045 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
1046 pRemainChanCtx->action_pkt_buff.freq, 0,
1047 pRemainChanCtx->action_pkt_buff.frame_ptr,
1048 pRemainChanCtx->action_pkt_buff.frame_length,
1049 NL80211_RXMGMT_FLAG_ANSWERED);
1050#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
1051 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
1052 pRemainChanCtx->action_pkt_buff.freq, 0,
1053 pRemainChanCtx->action_pkt_buff.frame_ptr,
1054 pRemainChanCtx->action_pkt_buff.frame_length,
1055 NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
Amar Singhal01098f72015-10-08 11:55:32 -07001056#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
1058 pRemainChanCtx->action_pkt_buff.freq,
1059 0,
1060 pRemainChanCtx->action_pkt_buff.
1061 frame_ptr,
1062 pRemainChanCtx->action_pkt_buff.
1063 frame_length, GFP_ATOMIC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064#endif /* LINUX_VERSION_CODE */
1065
1066 cdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr);
1067 pRemainChanCtx->action_pkt_buff.frame_length = 0;
1068 pRemainChanCtx->action_pkt_buff.freq = 0;
1069 pRemainChanCtx->action_pkt_buff.frame_ptr = NULL;
1070 }
1071 complete(&pAdapter->rem_on_chan_ready_event);
1072 } else {
1073 hddLog(LOGW, "%s: No Pending Remain on channel Request",
1074 __func__);
1075 }
1076 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1077 return;
1078}
1079
1080int __wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001081 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001082 u64 cookie)
1083{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 struct net_device *dev = wdev->netdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001085 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1086 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
1087 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
1088 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1089 int status;
Anurag Chouhanffb21542016-02-17 14:33:03 +05301090 int qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001091 unsigned long rc;
Anurag Chouhanffb21542016-02-17 14:33:03 +05301092 qdf_list_node_t *tmp, *q;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093 hdd_roc_req_t *curr_roc_req;
1094
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301095 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096
Peng Xuf5d60c82015-10-02 17:17:03 -07001097 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1099 return -EINVAL;
1100 }
1101
1102 status = wlan_hdd_validate_context(pHddCtx);
1103
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301104 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001105 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 cdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock);
1107 list_for_each_safe(tmp, q, &pHddCtx->hdd_roc_req_q.anchor) {
1108 curr_roc_req = list_entry(tmp, hdd_roc_req_t, node);
1109 if ((uintptr_t) curr_roc_req->pRemainChanCtx == cookie) {
Anurag Chouhanffb21542016-02-17 14:33:03 +05301110 qdf_status = qdf_list_remove_node(&pHddCtx->hdd_roc_req_q,
1111 (qdf_list_node_t *)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001112 curr_roc_req);
1113 cdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +05301114 if (qdf_status == QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 cdf_mem_free(curr_roc_req->pRemainChanCtx);
1116 cdf_mem_free(curr_roc_req);
1117 }
1118 return 0;
1119 }
1120 }
1121 cdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock);
1122 /* FIXME cancel currently running remain on chan.
1123 * Need to check cookie and cancel accordingly
1124 */
1125 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1126 pRemainChanCtx = cfgState->remain_on_chan_ctx;
1127 if ((cfgState->remain_on_chan_ctx == NULL) ||
1128 (cfgState->remain_on_chan_ctx->cookie != cookie)) {
1129 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1130 hddLog(LOGE,
1131 "%s: No Remain on channel pending with specified cookie value",
1132 __func__);
1133 return -EINVAL;
1134 }
1135
1136 if (NULL != cfgState->remain_on_chan_ctx) {
1137 cdf_mc_timer_stop(&cfgState->remain_on_chan_ctx->
1138 hdd_remain_on_chan_timer);
1139 if (true ==
1140 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) {
1141 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1142 hddLog(LOG1,
1143 FL("ROC timer cancellation in progress,"
1144 " wait for completion"));
1145 rc = wait_for_completion_timeout(&pAdapter->
1146 cancel_rem_on_chan_var,
1147 msecs_to_jiffies
1148 (WAIT_CANCEL_REM_CHAN));
1149 if (!rc) {
1150 hddLog(LOGE,
1151 "%s:wait on cancel_rem_on_chan_var timed out",
1152 __func__);
1153 }
1154 return 0;
1155 } else
1156 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress =
1157 true;
1158 }
1159 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1160
1161 /* wait until remain on channel ready event received
1162 * for already issued remain on channel request */
1163 rc = wait_for_completion_timeout(&pAdapter->rem_on_chan_ready_event,
1164 msecs_to_jiffies(WAIT_REM_CHAN_READY));
1165 if (!rc) {
1166 hddLog(LOGE,
1167 "%s: timeout waiting for remain on channel ready indication",
1168 __func__);
1169
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001170 if (cds_is_driver_recovering()) {
1171 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
1172 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173 return -EAGAIN;
1174 }
1175 }
1176 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
1177 /* Issue abort remain on chan request to sme.
1178 * The remain on channel callback will make sure the remain_on_chan
1179 * expired event is sent.
1180 */
1181 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1182 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
1183 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
1184 ) {
1185
1186 uint8_t sessionId = pAdapter->sessionId;
1187 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter),
1188 sessionId,
1189 pRemainChanCtx->scan_id);
1190 } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
1191 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
1192 ) {
1193 wlansap_cancel_remain_on_channel(
1194#ifdef WLAN_FEATURE_MBSSID
1195 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
1196#else
1197 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
1198#endif
1199 pRemainChanCtx->scan_id);
1200
1201 } else {
1202 hddLog(LOGE, FL("Invalid device_mode %s(%d)"),
1203 hdd_device_mode_to_string(pAdapter->device_mode),
1204 pAdapter->device_mode);
1205 return -EIO;
1206 }
1207 rc = wait_for_completion_timeout(&pAdapter->cancel_rem_on_chan_var,
1208 msecs_to_jiffies
1209 (WAIT_CANCEL_REM_CHAN));
1210 if (!rc) {
1211 hddLog(LOGE,
1212 "%s:wait on cancel_rem_on_chan_var timed out ",
1213 __func__);
1214 }
1215 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301216 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001217 return 0;
1218}
1219
1220int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001221 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001222 u64 cookie)
1223{
1224 int ret;
1225
1226 cds_ssr_protect(__func__);
1227 ret = __wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 cookie);
1230 cds_ssr_unprotect(__func__);
1231
1232 return ret;
1233}
1234
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001235int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1236 struct ieee80211_channel *chan, bool offchan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001237 unsigned int wait,
1238 const u8 *buf, size_t len, bool no_cck,
1239 bool dont_wait_for_ack, u64 *cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001241 struct net_device *dev = wdev->netdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001242 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1243 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
1244 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
1245 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1246 uint16_t extendedWait = 0;
1247 uint8_t type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
1248 uint8_t subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
1249 tActionFrmType actionFrmType;
1250 bool noack = 0;
1251 int status;
1252 unsigned long rc;
1253 hdd_adapter_t *goAdapter;
1254 uint16_t current_freq;
1255
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301256 ENTER();
1257
Peng Xuf5d60c82015-10-02 17:17:03 -07001258 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001259 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1260 return -EINVAL;
1261 }
1262
1263 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
1264 TRACE_CODE_HDD_ACTION, pAdapter->sessionId,
1265 pAdapter->device_mode));
1266 status = wlan_hdd_validate_context(pHddCtx);
1267
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301268 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001269 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270
1271 hddLog(LOG1, FL("Device_mode %s(%d) type: %d"),
1272 hdd_device_mode_to_string(pAdapter->device_mode),
1273 pAdapter->device_mode, type);
1274
1275#ifdef WLAN_FEATURE_P2P_DEBUG
1276 if ((type == SIR_MAC_MGMT_FRAME) &&
1277 (subType == SIR_MAC_MGMT_ACTION) &&
1278 wlan_hdd_is_type_p2p_action(&buf
1279 [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])) {
1280 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1281 if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) {
1282 hddLog(CDF_TRACE_LEVEL_ERROR,
1283 "[P2P] unknown[%d] ---> OTA to " MAC_ADDRESS_STR,
1284 actionFrmType,
1285 MAC_ADDR_ARRAY(&buf
1286 [WLAN_HDD_80211_FRM_DA_OFFSET]));
1287 } else {
1288 hddLog(CDF_TRACE_LEVEL_ERROR, "[P2P] %s ---> OTA to "
1289 MAC_ADDRESS_STR,
1290 p2p_action_frame_type[actionFrmType],
1291 MAC_ADDR_ARRAY(&buf
1292 [WLAN_HDD_80211_FRM_DA_OFFSET]));
1293 if ((actionFrmType == WLAN_HDD_PROV_DIS_REQ)
1294 && (global_p2p_connection_status == P2P_NOT_ACTIVE)) {
1295 global_p2p_connection_status = P2P_GO_NEG_PROCESS;
1296 hddLog(LOGE, "[P2P State]Inactive state to "
1297 "GO negotiation progress state");
1298 } else if ((actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1299 (global_p2p_connection_status ==
1300 P2P_GO_NEG_PROCESS)) {
1301 global_p2p_connection_status =
1302 P2P_GO_NEG_COMPLETED;
1303 hddLog(LOGE,
1304 "[P2P State]GO nego progress to GO nego"
1305 " completed state");
1306 }
1307 }
1308 }
1309#endif
1310
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311 noack = dont_wait_for_ack;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001312
1313 /* If the wait is coming as 0 with off channel set */
1314 /* then set the wait to 200 ms */
1315 if (offchan && !wait) {
1316 wait = ACTION_FRAME_DEFAULT_WAIT;
1317 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1318 if (cfgState->remain_on_chan_ctx) {
1319
1320 uint32_t current_time = cdf_mc_timer_get_system_time();
1321 int remaining_roc_time =
1322 ((int) cfgState->remain_on_chan_ctx->duration -
1323 (current_time - pAdapter->start_roc_ts));
1324
1325 if (remaining_roc_time > ACTION_FRAME_DEFAULT_WAIT)
1326 wait = remaining_roc_time;
1327 }
1328 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1329 }
1330
1331 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) &&
1332 (type == SIR_MAC_MGMT_FRAME &&
1333 subType == SIR_MAC_MGMT_PROBE_RSP)) {
1334 /* Drop Probe response received
1335 * from supplicant in sta mode
1336 */
1337 goto err_rem_channel;
1338 }
1339
1340 /* Call sme API to send out a action frame. */
1341 /* OR can we send it directly through data path?? */
1342 /* After tx completion send tx status back. */
1343 if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
1344 (WLAN_HDD_P2P_GO == pAdapter->device_mode)
1345 ) {
1346 if (type == SIR_MAC_MGMT_FRAME) {
1347 if (subType == SIR_MAC_MGMT_PROBE_RSP) {
1348 /* Drop Probe response recieved from supplicant, as for GO and
1349 SAP PE itself sends probe response
1350 */
1351 goto err_rem_channel;
1352 } else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
1353 (subType == SIR_MAC_MGMT_DEAUTH)) {
1354 /* During EAP failure or P2P Group Remove supplicant
1355 * is sending del_station command to driver. From
1356 * del_station function, Driver will send deauth frame to
1357 * p2p client. No need to send disassoc frame from here.
1358 * so Drop the frame here and send tx indication back to
1359 * supplicant.
1360 */
1361 uint8_t dstMac[ETH_ALEN] = { 0 };
1362 memcpy(&dstMac,
1363 &buf[WLAN_HDD_80211_FRM_DA_OFFSET],
1364 ETH_ALEN);
1365 hddLog(CDF_TRACE_LEVEL_INFO,
1366 "%s: Deauth/Disassoc received for STA:"
1367 MAC_ADDRESS_STR, __func__,
1368 MAC_ADDR_ARRAY(dstMac));
1369 goto err_rem_channel;
1370 }
1371 }
1372 }
1373
1374 if (NULL != cfgState->buf) {
1375 if (!noack) {
1376 hddLog(LOGE,
1377 "(%s):Previous P2P Action frame packet pending",
1378 __func__);
1379 hdd_cleanup_actionframe(pAdapter->pHddCtx, pAdapter);
1380 } else {
1381 hddLog(LOGE,
1382 "(%s):Pending Action frame packet return EBUSY",
1383 __func__);
1384 return -EBUSY;
1385 }
1386 }
1387
1388 if (subType == SIR_MAC_MGMT_ACTION) {
1389 hddLog(LOG1, "Action frame tx request : %s",
1390 hdd_get_action_string(buf
1391 [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET]));
1392 }
1393
1394 goAdapter = hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_P2P_GO);
1395
1396 /* If GO adapter exists and operating on same frequency */
1397 /* then we will not request remain on channel */
1398 if (goAdapter && (ieee80211_frequency_to_channel(chan->center_freq)
1399 == goAdapter->sessionCtx.ap.operatingChannel)) {
1400 /* if GO exist and is not off channel
1401 * wait time should be zero
1402 */
1403 wait = 0;
1404 goto send_frame;
1405 }
1406
1407 if (offchan && wait) {
1408 int status;
1409 rem_on_channel_request_type_t req_type = OFF_CHANNEL_ACTION_TX;
1410 /* In case of P2P Client mode if we are already */
1411 /* on the same channel then send the frame directly */
1412
1413 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1414 pRemainChanCtx = cfgState->remain_on_chan_ctx;
1415 if ((type == SIR_MAC_MGMT_FRAME) &&
1416 (subType == SIR_MAC_MGMT_ACTION) &&
1417 hdd_p2p_is_action_type_rsp(&buf
1418 [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])
1419 && cfgState->remain_on_chan_ctx
1420 && cfgState->current_freq == chan->center_freq) {
1421 if (CDF_TIMER_STATE_RUNNING ==
1422 cdf_mc_timer_get_current_state(&cfgState->
1423 remain_on_chan_ctx->
1424 hdd_remain_on_chan_timer)) {
1425 cdf_mc_timer_stop(&cfgState->
1426 remain_on_chan_ctx->
1427 hdd_remain_on_chan_timer);
1428 status =
1429 cdf_mc_timer_start(&cfgState->
1430 remain_on_chan_ctx->
1431 hdd_remain_on_chan_timer,
1432 wait);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301433 if (status != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001434 hddLog(LOGE,
1435 "%s: Remain on Channel timer start failed",
1436 __func__);
1437 }
1438 mutex_unlock(&cfgState->
1439 remain_on_chan_ctx_lock);
1440 goto send_frame;
1441 } else {
1442 if (pRemainChanCtx->
1443 hdd_remain_on_chan_cancel_in_progress ==
1444 true) {
1445 mutex_unlock(&cfgState->
1446 remain_on_chan_ctx_lock);
1447 hddLog(CDF_TRACE_LEVEL_INFO,
1448 "action frame tx: waiting for completion of ROC ");
1449
1450 rc = wait_for_completion_timeout
1451 (&pAdapter->cancel_rem_on_chan_var,
1452 msecs_to_jiffies
1453 (WAIT_CANCEL_REM_CHAN));
1454 if (!rc) {
1455 hddLog(LOGE,
1456 "%s:wait on cancel_rem_on_chan_var timed out",
1457 __func__);
1458 }
1459
1460 } else
1461 mutex_unlock(&cfgState->
1462 remain_on_chan_ctx_lock);
1463 }
1464 } else
1465 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1466
1467 if ((cfgState->remain_on_chan_ctx != NULL) &&
1468 (cfgState->current_freq == chan->center_freq)
1469 ) {
1470 hddLog(LOG1, "action frame: extending the wait time");
1471 extendedWait = (uint16_t) wait;
1472 goto send_frame;
1473 }
1474
1475 INIT_COMPLETION(pAdapter->offchannel_tx_event);
1476
1477 status = wlan_hdd_request_remain_on_channel(wiphy, dev, chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 wait, cookie,
1479 req_type);
1480 if (0 != status) {
1481 if ((-EBUSY == status) &&
1482 (cfgState->current_freq == chan->center_freq)) {
1483 goto send_frame;
1484 }
1485 goto err_rem_channel;
1486 }
1487 /* This will extend timer in LIM when sending Any action frame
1488 * It will cover remain on channel timer till next action frame
1489 * in rx direction.
1490 */
1491 extendedWait = (uint16_t) wait;
1492 /* Wait for driver to be ready on the requested channel */
1493 rc = wait_for_completion_timeout(&pAdapter->offchannel_tx_event,
1494 msecs_to_jiffies
1495 (WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
1496 if (!rc) {
1497 hddLog(LOGE, "wait on offchannel_tx_event timed out");
1498 goto err_rem_channel;
1499 }
1500 } else if (offchan) {
1501 /* Check before sending action frame
1502 whether we already remain on channel */
1503 if (NULL == cfgState->remain_on_chan_ctx) {
1504 goto err_rem_channel;
1505 }
1506 }
1507send_frame:
1508
1509 if (!noack) {
1510 cfgState->buf = cdf_mem_malloc(len); /* buf; */
1511 if (cfgState->buf == NULL)
1512 return -ENOMEM;
1513
1514 cfgState->len = len;
1515
1516 cdf_mem_copy(cfgState->buf, buf, len);
1517
1518 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1519
1520 if (cfgState->remain_on_chan_ctx) {
1521 cfgState->action_cookie =
1522 cfgState->remain_on_chan_ctx->cookie;
1523 *cookie = cfgState->action_cookie;
1524 } else {
1525 *cookie = (uintptr_t) cfgState->buf;
1526 cfgState->action_cookie = *cookie;
1527 }
1528
1529 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1530 }
1531
1532 /*
1533 * Firmware needs channel information for action frames
1534 * which are not sent on the current operating channel of VDEV
1535 */
1536 if ((WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) ||
1537 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
1538 (WLAN_HDD_P2P_GO == pAdapter->device_mode)) {
1539 if (chan && (chan->center_freq != 0))
1540 current_freq = chan->center_freq;
1541 else
1542 current_freq = cfgState->current_freq;
1543 } else {
1544 current_freq = 0;
1545 }
1546
Jeff Johnson19caeb12015-12-10 12:29:44 -08001547 INIT_COMPLETION(pAdapter->tx_action_cnf_event);
1548
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
1550 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) ||
1551 (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode)
1552 ) {
1553 uint8_t sessionId = pAdapter->sessionId;
1554
1555 if ((type == SIR_MAC_MGMT_FRAME) &&
1556 (subType == SIR_MAC_MGMT_ACTION) &&
1557 (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
1558 WLAN_HDD_PUBLIC_ACTION_FRAME)) {
1559 actionFrmType =
1560 buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1561 hddLog(LOG1, "Tx Action Frame %u", actionFrmType);
1562 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ) {
1563 cfgState->actionFrmState =
1564 HDD_PD_REQ_ACK_PENDING;
1565 hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING",
1566 __func__);
1567 } else if (actionFrmType == WLAN_HDD_GO_NEG_REQ) {
1568 cfgState->actionFrmState =
1569 HDD_GO_NEG_REQ_ACK_PENDING;
1570 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING",
1571 __func__);
1572 }
1573 }
1574
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301575 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001576 sme_send_action(WLAN_HDD_GET_HAL_CTX(pAdapter),
1577 sessionId, buf, len, extendedWait, noack,
1578 current_freq)) {
1579 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1580 "%s: sme_send_action returned fail", __func__);
1581 goto err;
1582 }
1583 } else if (WLAN_HDD_SOFTAP == pAdapter->device_mode ||
1584 WLAN_HDD_P2P_GO == pAdapter->device_mode) {
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301585 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586#ifdef WLAN_FEATURE_MBSSID
1587 wlansap_send_action(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
1588#else
1589 wlansap_send_action((WLAN_HDD_GET_CTX(pAdapter))->
1590 pcds_context,
1591#endif
1592 buf, len, 0, current_freq)) {
1593 hddLog(LOGE,
1594 FL("wlansap_send_action returned fail"));
1595 goto err;
1596 }
1597 }
1598
1599 return 0;
1600err:
1601 if (!noack) {
1602 hdd_send_action_cnf(pAdapter, false);
1603 }
1604 return 0;
1605err_rem_channel:
1606 *cookie = (uintptr_t) cfgState;
1607 cfg80211_mgmt_tx_status(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608 pAdapter->dev->ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609 *cookie, buf, len, false, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301610 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 return 0;
1612}
1613
1614#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1615int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1616 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Amar Singhal01098f72015-10-08 11:55:32 -07001617#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1619 struct ieee80211_channel *chan, bool offchan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620 unsigned int wait,
1621 const u8 *buf, size_t len, bool no_cck,
1622 bool dont_wait_for_ack, u64 *cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001623#endif /* LINUX_VERSION_CODE */
1624{
1625 int ret;
1626
1627 cds_ssr_protect(__func__);
1628
1629#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1630 ret = __wlan_hdd_mgmt_tx(wiphy, wdev, params->chan, params->offchan,
1631 params->wait, params->buf, params->len,
1632 params->no_cck, params->dont_wait_for_ack,
1633 cookie);
Amar Singhal01098f72015-10-08 11:55:32 -07001634#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001635 ret = __wlan_hdd_mgmt_tx(wiphy, wdev, chan, offchan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001636 wait, buf, len, no_cck,
1637 dont_wait_for_ack, cookie);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638#endif /* LINUX_VERSION_CODE */
1639 cds_ssr_unprotect(__func__);
1640
1641 return ret;
1642}
1643
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001644int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
1645 struct wireless_dev *wdev,
1646 u64 cookie)
1647{
1648 return wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, wdev, cookie);
1649}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001650
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001651int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
1652 struct wireless_dev *wdev, u64 cookie)
1653{
1654 int ret;
1655
1656 cds_ssr_protect(__func__);
1657 ret = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, cookie);
1658 cds_ssr_unprotect(__func__);
1659
1660 return ret;
1661}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001662
1663void hdd_send_action_cnf(hdd_adapter_t *pAdapter, bool actionSendSuccess)
1664{
1665 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
1666
1667 cfgState->actionFrmState = HDD_IDLE;
1668
1669 hddLog(LOG1, "Send Action cnf, actionSendSuccess %d",
1670 actionSendSuccess);
1671
1672 if (NULL == cfgState->buf) {
1673 return;
1674 }
1675
1676 /*
1677 * buf is the same pointer it passed us to send. Since we are sending
1678 * it through control path, we use different buffers.
1679 * In case of mac80211, they just push it to the skb and pass the same
1680 * data while sending tx ack status.
1681 * */
1682 cfg80211_mgmt_tx_status(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001683 pAdapter->dev->ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684 cfgState->action_cookie,
1685 cfgState->buf, cfgState->len,
1686 actionSendSuccess, GFP_KERNEL);
1687
1688 cdf_mem_free(cfgState->buf);
1689 cfgState->buf = NULL;
1690
1691 complete(&pAdapter->tx_action_cnf_event);
1692}
1693
1694/**
1695 * hdd_set_p2p_noa
1696 *
1697 ***FUNCTION:
1698 * This function is called from hdd_hostapd_ioctl function when Driver
1699 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
1700 *
1701 ***LOGIC:
1702 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
1703 *
1704 ***ASSUMPTIONS:
1705 *
1706 *
1707 ***NOTE:
1708 *
1709 * @param dev Pointer to net device structure
1710 * @param command Pointer to command
1711 *
1712 * @return Status
1713 */
1714
1715int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command)
1716{
1717 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1718 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
1719 tP2pPsConfig NoA;
1720 int count, duration, start_time;
1721 char *param;
1722 int ret;
1723
1724 param = strnchr(command, strlen(command), ' ');
1725 if (param == NULL) {
1726 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1727 "%s: strnchr failed to find delimeter", __func__);
1728 return -EINVAL;
1729 }
1730 param++;
1731 ret = sscanf(param, "%d %d %d", &count, &start_time, &duration);
1732 if (ret != 3) {
1733 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1734 "%s: P2P_SET GO NoA: fail to read params, ret=%d",
1735 __func__, ret);
1736 return -EINVAL;
1737 }
1738 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1739 "%s: P2P_SET GO NoA: count=%d start_time=%d duration=%d",
1740 __func__, count, start_time, duration);
1741 duration = MS_TO_MUS(duration);
1742 /* PS Selection
1743 * Periodic NoA (2)
1744 * Single NOA (4)
1745 */
1746 NoA.opp_ps = 0;
1747 NoA.ctWindow = 0;
1748 if (count == 1) {
1749 NoA.duration = 0;
1750 NoA.single_noa_duration = duration;
1751 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
1752 } else {
1753 NoA.duration = duration;
1754 NoA.single_noa_duration = 0;
1755 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
1756 }
1757 NoA.interval = MS_TO_MUS(100);
1758 NoA.count = count;
1759 NoA.sessionid = pAdapter->sessionId;
1760
1761 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1762 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1763 "interval %d count %d single noa duration %d "
1764 "PsSelection %x", __func__, NoA.opp_ps,
1765 NoA.ctWindow, NoA.duration, NoA.interval,
1766 NoA.count, NoA.single_noa_duration, NoA.psSelection);
1767
1768 sme_p2p_set_ps(hHal, &NoA);
1769 return 0;
1770}
1771
1772/**
1773 * hdd_set_p2p_opps
1774 *
1775 ***FUNCTION:
1776 * This function is called from hdd_hostapd_ioctl function when Driver
1777 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
1778 *
1779 ***LOGIC:
1780 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
1781 *
1782 ***ASSUMPTIONS:
1783 *
1784 *
1785 ***NOTE:
1786 *
1787 * @param dev Pointer to net device structure
1788 * @param command Pointer to command
1789 *
1790 * @return Status
1791 */
1792
1793int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command)
1794{
1795 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1796 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
1797 tP2pPsConfig NoA;
1798 char *param;
1799 int legacy_ps, opp_ps, ctwindow;
1800 int ret;
1801
1802 param = strnchr(command, strlen(command), ' ');
1803 if (param == NULL) {
1804 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1805 "%s: strnchr failed to find delimiter", __func__);
1806 return -EINVAL;
1807 }
1808 param++;
1809 ret = sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
1810 if (ret != 3) {
1811 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1812 "%s: P2P_SET GO PS: fail to read params, ret=%d",
1813 __func__, ret);
1814 return -EINVAL;
1815 }
1816 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1817 "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d",
1818 __func__, legacy_ps, opp_ps, ctwindow);
1819
1820 /* PS Selection
1821 * Opportunistic Power Save (1)
1822 */
1823
1824 /* From wpa_cli user need to use separate command to set ctWindow and Opps
1825 * When user want to set ctWindow during that time other parameters
1826 * values are coming from wpa_supplicant as -1.
1827 * Example : User want to set ctWindow with 30 then wpa_cli command :
1828 * P2P_SET ctwindow 30
1829 * Command Received at hdd_hostapd_ioctl is as below:
1830 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
1831 */
1832 if (ctwindow != -1) {
1833
1834 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1835 "Opportunistic Power Save is %s",
1836 (true == pAdapter->ops) ? "Enable" : "Disable");
1837
1838 if (ctwindow != pAdapter->ctw) {
1839 pAdapter->ctw = ctwindow;
1840
1841 if (pAdapter->ops) {
1842 NoA.opp_ps = pAdapter->ops;
1843 NoA.ctWindow = pAdapter->ctw;
1844 NoA.duration = 0;
1845 NoA.single_noa_duration = 0;
1846 NoA.interval = 0;
1847 NoA.count = 0;
1848 NoA.psSelection =
1849 P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1850 NoA.sessionid = pAdapter->sessionId;
1851
1852 CDF_TRACE(CDF_MODULE_ID_HDD,
1853 CDF_TRACE_LEVEL_INFO,
1854 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1855 "interval %d count %d single noa duration %d "
1856 "PsSelection %x", __func__,
1857 NoA.opp_ps, NoA.ctWindow,
1858 NoA.duration, NoA.interval, NoA.count,
1859 NoA.single_noa_duration,
1860 NoA.psSelection);
1861
1862 sme_p2p_set_ps(hHal, &NoA);
1863 }
1864 return 0;
1865 }
1866 }
1867
1868 if (opp_ps != -1) {
1869 pAdapter->ops = opp_ps;
1870
1871 if ((opp_ps != -1) && (pAdapter->ctw)) {
1872 NoA.opp_ps = opp_ps;
1873 NoA.ctWindow = pAdapter->ctw;
1874 NoA.duration = 0;
1875 NoA.single_noa_duration = 0;
1876 NoA.interval = 0;
1877 NoA.count = 0;
1878 NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
1879 NoA.sessionid = pAdapter->sessionId;
1880
1881 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
1882 "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
1883 "interval %d count %d single noa duration %d "
1884 "PsSelection %x", __func__, NoA.opp_ps,
1885 NoA.ctWindow, NoA.duration, NoA.interval,
1886 NoA.count, NoA.single_noa_duration,
1887 NoA.psSelection);
1888
1889 sme_p2p_set_ps(hHal, &NoA);
1890 }
1891 }
1892 return 0;
1893}
1894
1895int hdd_set_p2p_ps(struct net_device *dev, void *msgData)
1896{
1897 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1898 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301899 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 tP2pPsConfig NoA;
1901 p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData;
1902
1903 NoA.opp_ps = pappNoA->opp_ps;
1904 NoA.ctWindow = pappNoA->ctWindow;
1905 NoA.duration = pappNoA->duration;
1906 NoA.interval = pappNoA->interval;
1907 NoA.count = pappNoA->count;
1908 NoA.single_noa_duration = pappNoA->single_noa_duration;
1909 NoA.psSelection = pappNoA->psSelection;
1910 NoA.sessionid = pAdapter->sessionId;
1911
1912 sme_p2p_set_ps(hHal, &NoA);
1913 return status;
1914}
1915
1916static uint8_t wlan_hdd_get_session_type(enum nl80211_iftype type)
1917{
1918 uint8_t sessionType;
1919
1920 switch (type) {
1921 case NL80211_IFTYPE_AP:
1922 sessionType = WLAN_HDD_SOFTAP;
1923 break;
1924 case NL80211_IFTYPE_P2P_GO:
1925 sessionType = WLAN_HDD_P2P_GO;
1926 break;
1927 case NL80211_IFTYPE_P2P_CLIENT:
1928 sessionType = WLAN_HDD_P2P_CLIENT;
1929 break;
1930 case NL80211_IFTYPE_STATION:
1931 sessionType = WLAN_HDD_INFRA_STATION;
1932 break;
1933 default:
1934 sessionType = WLAN_HDD_INFRA_STATION;
1935 break;
1936 }
1937
1938 return sessionType;
1939}
1940
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
1942 const char *name,
1943 enum nl80211_iftype type,
1944 u32 *flags,
1945 struct vif_params *params)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946{
1947 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
1948 hdd_adapter_t *pAdapter = NULL;
1949 hdd_scaninfo_t *scan_info = NULL;
1950 int ret;
Peng Xu45486ea2015-11-12 16:37:44 -08001951 uint8_t session_type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001952
1953 ENTER();
1954
Peng Xuf5d60c82015-10-02 17:17:03 -07001955 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956 hddLog(LOGE, FL("Command not allowed in FTM mode"));
1957 return ERR_PTR(-EINVAL);
1958 }
1959
1960 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301961 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001962 return ERR_PTR(ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963
1964 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
1965 TRACE_CODE_HDD_ADD_VIRTUAL_INTF, NO_SESSION, type));
1966 /*
Peng Xu45486ea2015-11-12 16:37:44 -08001967 * Allow addition multiple interfaces for WLAN_HDD_P2P_GO,
1968 * WLAN_HDD_SOFTAP, WLAN_HDD_P2P_CLIENT and WLAN_HDD_INFRA_STATION
1969 * session type.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 */
Peng Xu45486ea2015-11-12 16:37:44 -08001971 session_type = wlan_hdd_get_session_type(type);
1972 if ((hdd_get_adapter(pHddCtx, session_type) != NULL)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973#ifdef WLAN_FEATURE_MBSSID
Peng Xu45486ea2015-11-12 16:37:44 -08001974 && WLAN_HDD_SOFTAP != session_type
1975 && WLAN_HDD_P2P_GO != session_type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001976#endif
Peng Xu45486ea2015-11-12 16:37:44 -08001977 && WLAN_HDD_P2P_CLIENT != session_type
1978 && WLAN_HDD_INFRA_STATION != session_type) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001979 hddLog(LOGE,
1980 "%s: Interface type %d already exists. "
1981 "Two interfaces of same type are not supported currently.",
1982 __func__, type);
1983 return ERR_PTR(-EINVAL);
1984 }
1985
1986 wlan_hdd_tdls_disable_offchan_and_teardown_links(pHddCtx);
1987
1988 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
1989 if (pAdapter != NULL) {
1990 scan_info = &pAdapter->scan_info;
1991 if (scan_info->mScanPending) {
1992 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
1993 eCSR_SCAN_ABORT_DEFAULT);
1994 hddLog(LOG1,
1995 FL("Abort Scan while adding virtual interface"));
1996 }
1997 }
1998
1999 pAdapter = NULL;
2000 if (pHddCtx->config->isP2pDeviceAddrAdministrated &&
2001 ((NL80211_IFTYPE_P2P_GO == type) ||
2002 (NL80211_IFTYPE_P2P_CLIENT == type))) {
2003 /*
2004 * Generate the P2P Interface Address. this address must be
2005 * different from the P2P Device Address.
2006 */
2007 struct cdf_mac_addr p2pDeviceAddress =
2008 pHddCtx->p2pDeviceAddress;
2009 p2pDeviceAddress.bytes[4] ^= 0x80;
2010 pAdapter = hdd_open_adapter(pHddCtx,
2011 wlan_hdd_get_session_type(type),
2012 name, p2pDeviceAddress.bytes, true);
2013 } else {
2014 pAdapter =
2015 hdd_open_adapter(pHddCtx, wlan_hdd_get_session_type(type),
2016 name, wlan_hdd_get_intf_addr(pHddCtx),
2017 true);
2018 }
2019
2020 if (NULL == pAdapter) {
2021 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: hdd_open_adapter failed",
2022 __func__);
2023 return ERR_PTR(-ENOSPC);
2024 }
2025 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002026 return pAdapter->dev->ieee80211_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027}
2028
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002029struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
2030 const char *name,
2031 enum nl80211_iftype type,
2032 u32 *flags,
2033 struct vif_params *params)
2034{
2035 struct wireless_dev *wdev;
2036
2037 cds_ssr_protect(__func__);
2038 wdev = __wlan_hdd_add_virtual_intf(wiphy, name, type, flags, params);
2039 cds_ssr_unprotect(__func__);
2040 return wdev;
2041}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002044{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045 struct net_device *dev = wdev->netdev;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046 hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy);
2047 hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2048 int status;
2049 ENTER();
2050
Peng Xuf5d60c82015-10-02 17:17:03 -07002051 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 hddLog(LOGE, FL("Command not allowed in FTM mode"));
2053 return -EINVAL;
2054 }
2055
2056 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
2057 TRACE_CODE_HDD_DEL_VIRTUAL_INTF,
2058 pVirtAdapter->sessionId, pVirtAdapter->device_mode));
2059 hddLog(LOG1, FL("Device_mode %s(%d)"),
2060 hdd_device_mode_to_string(pVirtAdapter->device_mode),
2061 pVirtAdapter->device_mode);
2062
2063 status = wlan_hdd_validate_context(pHddCtx);
2064
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302065 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002066 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002067
2068 wlan_hdd_release_intf_addr(pHddCtx,
2069 pVirtAdapter->macAddressCurrent.bytes);
2070
2071 hdd_stop_adapter(pHddCtx, pVirtAdapter, true);
2072 hdd_close_adapter(pHddCtx, pVirtAdapter, true);
2073 EXIT();
2074 return 0;
2075}
2076
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002077int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002078{
2079 int ret;
2080
2081 cds_ssr_protect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002082 ret = __wlan_hdd_del_virtual_intf(wiphy, wdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 cds_ssr_unprotect(__func__);
2084
2085 return ret;
2086}
2087
Abhishek Singh7996eb72015-12-30 17:24:02 +05302088void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002089 uint32_t nFrameLength,
2090 uint8_t *pbFrames,
2091 uint8_t frameType, uint32_t rxChan, int8_t rxRssi)
2092{
2093 uint16_t freq;
2094 uint16_t extend_time;
2095 uint8_t type = 0;
2096 uint8_t subType = 0;
2097 tActionFrmType actionFrmType;
2098 hdd_cfg80211_state_t *cfgState = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302099 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002100 hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL;
2101 hdd_context_t *pHddCtx;
2102
2103 hddLog(CDF_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d",
2104 __func__, frameType, nFrameLength);
2105
2106 if (NULL == pAdapter) {
2107 hddLog(LOGE, FL("pAdapter is NULL"));
2108 return;
2109 }
2110 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2111
2112 if (0 == nFrameLength) {
2113 hddLog(LOGE, FL("Frame Length is Invalid ZERO"));
2114 return;
2115 }
2116
2117 if (NULL == pbFrames) {
2118 hddLog(LOGE, FL("pbFrames is NULL"));
2119 return;
2120 }
2121
2122 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
2123 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
2124
2125 /* Get pAdapter from Destination mac address of the frame */
2126 if ((type == SIR_MAC_MGMT_FRAME) && (subType != SIR_MAC_MGMT_PROBE_REQ)) {
2127 pAdapter =
2128 hdd_get_adapter_by_macaddr(WLAN_HDD_GET_CTX(pAdapter),
2129 &pbFrames
2130 [WLAN_HDD_80211_FRM_DA_OFFSET]);
2131 if (NULL == pAdapter) {
2132 /*
2133 * Under assumtion that we don't receive any action
2134 * frame with BCST as destination,
2135 * we are dropping action frame
2136 */
2137 hddLog(LOGP,
2138 "pAdapter for action frame is NULL Macaddr = "
2139 MAC_ADDRESS_STR,
2140 MAC_ADDR_ARRAY(&pbFrames
2141 [WLAN_HDD_80211_FRM_DA_OFFSET]));
2142 hddLog(LOGP,
2143 FL("Frame Type = %d Frame Length = %d subType = %d"),
2144 frameType, nFrameLength, subType);
2145 return;
2146 }
2147 }
2148
2149 if (NULL == pAdapter->dev) {
2150 hddLog(LOGE, FL("pAdapter->dev is NULL"));
2151 return;
2152 }
2153
2154 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
2155 hddLog(LOGE, FL("pAdapter has invalid magic"));
2156 return;
2157 }
2158
2159 /* Channel indicated may be wrong. TODO */
2160 /* Indicate an action frame. */
2161 if (rxChan <= MAX_NO_OF_2_4_CHANNELS)
2162 freq = ieee80211_channel_to_frequency(rxChan,
2163 IEEE80211_BAND_2GHZ);
2164 else
2165 freq = ieee80211_channel_to_frequency(rxChan,
2166 IEEE80211_BAND_5GHZ);
2167
2168 cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
2169
2170 if ((type == SIR_MAC_MGMT_FRAME) && (subType == SIR_MAC_MGMT_ACTION)) {
2171 if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
2172 WLAN_HDD_PUBLIC_ACTION_FRAME) {
2173 /* Public action frame */
2174 if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1]
2175 == SIR_MAC_ACTION_VENDOR_SPECIFIC) &&
2176 cdf_mem_compare(&pbFrames
2177 [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET
2178 + 2], SIR_MAC_P2P_OUI,
2179 SIR_MAC_P2P_OUI_SIZE)) {
2180 /* P2P action frames */
2181 u8 *macFrom =
2182 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET + 6];
2183 actionFrmType =
2184 pbFrames
2185 [WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
2186 hddLog(LOG1, "Rx Action Frame %u",
2187 actionFrmType);
2188#ifdef WLAN_FEATURE_P2P_DEBUG
2189 if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) {
2190 hddLog(CDF_TRACE_LEVEL_ERROR,
2191 "[P2P] unknown[%d] <--- OTA"
2192 " from " MAC_ADDRESS_STR,
2193 actionFrmType,
2194 MAC_ADDR_ARRAY(macFrom));
2195 } else {
2196 hddLog(CDF_TRACE_LEVEL_ERROR,
2197 "[P2P] %s <--- OTA" " from "
2198 MAC_ADDRESS_STR,
2199 p2p_action_frame_type
2200 [actionFrmType],
2201 MAC_ADDR_ARRAY(macFrom));
2202 if ((actionFrmType ==
2203 WLAN_HDD_PROV_DIS_REQ)
2204 && (global_p2p_connection_status ==
2205 P2P_NOT_ACTIVE)) {
2206 global_p2p_connection_status =
2207 P2P_GO_NEG_PROCESS;
2208 hddLog(LOGE,
2209 "[P2P State]Inactive state to "
2210 "GO negotiation progress state");
2211 } else
2212 if ((actionFrmType ==
2213 WLAN_HDD_GO_NEG_CNF)
2214 && (global_p2p_connection_status ==
2215 P2P_GO_NEG_PROCESS)) {
2216 global_p2p_connection_status =
2217 P2P_GO_NEG_COMPLETED;
2218 hddLog(LOGE,
2219 "[P2P State]GO negotiation progress to "
2220 "GO negotiation completed state");
2221 } else
2222 if ((actionFrmType ==
2223 WLAN_HDD_INVITATION_REQ)
2224 && (global_p2p_connection_status ==
2225 P2P_NOT_ACTIVE)) {
2226 global_p2p_connection_status =
2227 P2P_GO_NEG_COMPLETED;
2228 hddLog(LOGE,
2229 "[P2P State]Inactive state to GO negotiation"
2230 " completed state Autonomous GO formation");
2231 }
2232 }
2233#endif
2234 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
2235 pRemainChanCtx = cfgState->remain_on_chan_ctx;
2236 if (pRemainChanCtx != NULL) {
2237 if (actionFrmType == WLAN_HDD_GO_NEG_REQ
2238 || actionFrmType ==
2239 WLAN_HDD_GO_NEG_RESP
2240 || actionFrmType ==
2241 WLAN_HDD_INVITATION_REQ
2242 || actionFrmType ==
2243 WLAN_HDD_DEV_DIS_REQ
2244 || actionFrmType ==
2245 WLAN_HDD_PROV_DIS_REQ) {
2246 hddLog(LOG1,
2247 "Extend RoC timer on reception of Action Frame");
2248
2249 if ((actionFrmType ==
2250 WLAN_HDD_GO_NEG_REQ)
2251 || (actionFrmType ==
2252 WLAN_HDD_GO_NEG_RESP))
2253 extend_time =
2254 2 *
2255 ACTION_FRAME_DEFAULT_WAIT;
2256 else
2257 extend_time =
2258 ACTION_FRAME_DEFAULT_WAIT;
2259
2260 if (completion_done
2261 (&pAdapter->
2262 rem_on_chan_ready_event)) {
2263 if (CDF_TIMER_STATE_RUNNING == cdf_mc_timer_get_current_state(&pRemainChanCtx->hdd_remain_on_chan_timer)) {
2264 cdf_mc_timer_stop
2265 (&pRemainChanCtx->
2266 hdd_remain_on_chan_timer);
2267 status =
2268 cdf_mc_timer_start
2269 (&pRemainChanCtx->
2270 hdd_remain_on_chan_timer,
2271 extend_time);
2272 if (status !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302273 QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002274 hddLog
2275 (LOGE,
2276 "%s: Remain on Channel timer start failed",
2277 __func__);
2278 }
2279 } else {
2280 hddLog(LOG1,
2281 "%s: Rcvd action frame after timer expired",
2282 __func__);
2283 }
2284 } else {
2285 /* Buffer Packet */
2286 if (pRemainChanCtx->
2287 action_pkt_buff.
2288 frame_length == 0) {
2289 pRemainChanCtx->
2290 action_pkt_buff.
2291 frame_length
2292 =
2293 nFrameLength;
2294 pRemainChanCtx->
2295 action_pkt_buff.
2296 freq = freq;
2297 pRemainChanCtx->
2298 action_pkt_buff.
2299 frame_ptr =
2300 cdf_mem_malloc
2301 (nFrameLength);
2302 cdf_mem_copy
2303 (pRemainChanCtx->
2304 action_pkt_buff.
2305 frame_ptr,
2306 pbFrames,
2307 nFrameLength);
2308 hddLog(LOGE,
2309 "%s:"
2310 "Action Pkt Cached successfully !!!",
2311 __func__);
2312 } else {
2313 hddLog(LOGE,
2314 "%s:"
2315 "Frames are pending. dropping frame !!!",
2316 __func__);
2317 }
2318 mutex_unlock(&cfgState->
2319 remain_on_chan_ctx_lock);
2320 return;
2321 }
2322 }
2323 }
2324 mutex_unlock(&cfgState->
2325 remain_on_chan_ctx_lock);
2326
2327 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP)
2328 && (cfgState->actionFrmState ==
2329 HDD_PD_REQ_ACK_PENDING))
2330 || ((actionFrmType == WLAN_HDD_GO_NEG_RESP)
2331 && (cfgState->actionFrmState ==
2332 HDD_GO_NEG_REQ_ACK_PENDING))) {
2333 hddLog(LOG1,
2334 "%s: ACK_PENDING and But received RESP for Action frame ",
2335 __func__);
2336 hdd_send_action_cnf(pAdapter, true);
2337 }
2338 }
2339#ifdef FEATURE_WLAN_TDLS
2340 else if (pbFrames
2341 [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] ==
2342 WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP) {
2343 u8 *mac =
2344 &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET + 6];
2345
2346 hddLog(LOG1,
2347 "[TDLS] TDLS Discovery Response,"
2348 MAC_ADDRESS_STR " RSSI[%d] <--- OTA",
2349 MAC_ADDR_ARRAY(mac), rxRssi);
2350
2351 wlan_hdd_tdls_set_rssi(pAdapter, mac, rxRssi);
2352 wlan_hdd_tdls_recv_discovery_resp(pAdapter,
2353 mac);
2354 }
2355#endif
2356 }
2357
2358 if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
2359 WLAN_HDD_TDLS_ACTION_FRAME) {
2360 actionFrmType =
2361 pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1];
2362 if (actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE) {
2363 hddLog(LOG1,
2364 "[TDLS] unknown[%d] <--- OTA",
2365 actionFrmType);
2366 } else {
2367 hddLog(LOG1,
2368 "[TDLS] %s <--- OTA",
2369 tdls_action_frame_type[actionFrmType]);
2370 }
2371 }
2372
2373 if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
2374 WLAN_HDD_QOS_ACTION_FRAME)
2375 && (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] ==
2376 WLAN_HDD_QOS_MAP_CONFIGURE)) {
2377 sme_update_dsc_pto_up_mapping(pHddCtx->hHal,
2378 pAdapter->hddWmmDscpToUpMap,
2379 pAdapter->sessionId);
2380 }
2381 }
2382 /* Indicate Frame Over Normal Interface */
2383 hddLog(LOG1, FL("Indicate Frame over NL80211 Interface"));
2384
2385#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
2386 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, 0, pbFrames,
2387 nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED);
2388#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
2389 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, 0, pbFrames,
2390 nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED,
2391 GFP_ATOMIC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002392#else
Amar Singhal01098f72015-10-08 11:55:32 -07002393 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, 0,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002394 pbFrames, nFrameLength, GFP_ATOMIC);
2395#endif /* LINUX_VERSION_CODE */
2396}
2397