blob: ea62ef7bdedef00413c9f3dc2d11bf0a13c3c116 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnson3aaa4922017-01-12 08:46:09 -08002 * Copyright (c) 2012-2017 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"
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053044#include "qdf_trace.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080045#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"
Anurag Chouhan6d760662016-02-20 16:05:43 +053051#include "qdf_types.h"
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053052#include "qdf_trace.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053#include "cds_sched.h"
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -080054#include "wlan_policy_mgr_api.h"
yeshwanth sriram guntuka310b3ac2016-11-15 23:25:26 +053055#include "cds_utils.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056
Wu Gao9a704f42017-03-10 18:42:11 +080057#ifdef CONVERGED_P2P_ENABLE
58#include "wlan_p2p_public_struct.h"
59#include "wlan_p2p_ucfg_api.h"
60#include "wlan_cfg80211_p2p.h"
61#else
62#include "wma_api.h"
63#endif
64
Manishekar Chandrasekaran371e5af2016-06-30 23:17:29 +053065/* Ms to Time Unit Micro Sec */
66#define MS_TO_TU_MUS(x) ((x) * 1024)
Archana Ramachandran1e6b9262016-09-30 15:15:10 -070067#define MAX_MUS_VAL (INT_MAX / 1024)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068
Wu Gao9a704f42017-03-10 18:42:11 +080069#ifndef CONVERGED_P2P_ENABLE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080070static uint8_t *hdd_get_action_string(uint16_t MsgType)
71{
72 switch (MsgType) {
73 CASE_RETURN_STRING(SIR_MAC_ACTION_SPECTRUM_MGMT);
74 CASE_RETURN_STRING(SIR_MAC_ACTION_QOS_MGMT);
75 CASE_RETURN_STRING(SIR_MAC_ACTION_DLP);
76 CASE_RETURN_STRING(SIR_MAC_ACTION_PUBLIC_USAGE);
77 CASE_RETURN_STRING(SIR_MAC_ACTION_RRM);
78 CASE_RETURN_STRING(SIR_MAC_ACTION_FAST_BSS_TRNST);
79 CASE_RETURN_STRING(SIR_MAC_ACTION_HT);
80 CASE_RETURN_STRING(SIR_MAC_ACTION_SA_QUERY);
81 CASE_RETURN_STRING(SIR_MAC_ACTION_PROT_DUAL_PUB);
82 CASE_RETURN_STRING(SIR_MAC_ACTION_WNM);
83 CASE_RETURN_STRING(SIR_MAC_ACTION_UNPROT_WNM);
84 CASE_RETURN_STRING(SIR_MAC_ACTION_TDLS);
85 CASE_RETURN_STRING(SIR_MAC_ACITON_MESH);
86 CASE_RETURN_STRING(SIR_MAC_ACTION_MHF);
87 CASE_RETURN_STRING(SIR_MAC_SELF_PROTECTED);
88 CASE_RETURN_STRING(SIR_MAC_ACTION_WME);
89 CASE_RETURN_STRING(SIR_MAC_ACTION_VHT);
90 default:
91 return "UNKNOWN";
92 }
93}
Wu Gao9a704f42017-03-10 18:42:11 +080094#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080095
96#ifdef WLAN_FEATURE_P2P_DEBUG
97#define MAX_P2P_ACTION_FRAME_TYPE 9
98const char *p2p_action_frame_type[] = { "GO Negotiation Request",
99 "GO Negotiation Response",
100 "GO Negotiation Confirmation",
101 "P2P Invitation Request",
102 "P2P Invitation Response",
103 "Device Discoverability Request",
104 "Device Discoverability Response",
105 "Provision Discovery Request",
106 "Provision Discovery Response"};
107
108/* We no need to protect this variable since
109 * there is no chance of race to condition
110 * and also not make any complicating the code
111 * just for debugging log
112 */
Srinivas Girigowda5d5fdc52017-03-24 22:30:57 -0700113enum p2p_connection_status global_p2p_connection_status = P2P_NOT_ACTIVE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800114
115#endif
116#define MAX_TDLS_ACTION_FRAME_TYPE 11
117const char *tdls_action_frame_type[] = { "TDLS Setup Request",
118 "TDLS Setup Response",
119 "TDLS Setup Confirm",
120 "TDLS Teardown",
121 "TDLS Peer Traffic Indication",
122 "TDLS Channel Switch Request",
123 "TDLS Channel Switch Response",
124 "TDLS Peer PSM Request",
125 "TDLS Peer PSM Response",
126 "TDLS Peer Traffic Response",
127 "TDLS Discovery Request"};
128
Wu Gao9a704f42017-03-10 18:42:11 +0800129#ifndef CONVERGED_P2P_ENABLE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800130static bool wlan_hdd_is_type_p2p_action(const u8 *buf)
131{
132 const u8 *ouiPtr;
133
134 if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET] !=
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700135 WLAN_HDD_PUBLIC_ACTION_FRAME)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800136 return false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800137
138 if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET] !=
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700139 WLAN_HDD_VENDOR_SPECIFIC_ACTION)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 return false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800141
142 ouiPtr = &buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET];
143
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700144 if (WPA_GET_BE24(ouiPtr) != WLAN_HDD_WFA_OUI)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800145 return false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146
147 if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET] !=
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700148 WLAN_HDD_WFA_P2P_OUI_TYPE)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800149 return false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800150
151 return true;
152}
153
154static bool hdd_p2p_is_action_type_rsp(const u8 *buf)
155{
Srinivas Girigowda85218af2017-03-25 13:21:40 -0700156 enum action_frm_type actionFrmType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800157
158 if (wlan_hdd_is_type_p2p_action(buf)) {
159 actionFrmType =
160 buf[WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET];
161 if (actionFrmType != WLAN_HDD_INVITATION_REQ
162 && actionFrmType != WLAN_HDD_GO_NEG_REQ
163 && actionFrmType != WLAN_HDD_DEV_DIS_REQ
164 && actionFrmType != WLAN_HDD_PROV_DIS_REQ)
165 return true;
166 }
167
168 return false;
169}
Wu Gao9a704f42017-03-10 18:42:11 +0800170#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800171
172static
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530173QDF_STATUS wlan_hdd_remain_on_channel_callback(tHalHandle hHal, void *pCtx,
174 QDF_STATUS status, uint32_t scan_id)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800175{
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700176 struct hdd_adapter *pAdapter = (struct hdd_adapter *) pCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800177 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
178 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
Jeff Johnson18767622017-08-28 11:46:50 -0700179 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
Srinivas Girigowda85218af2017-03-25 13:21:40 -0700180 enum rem_on_channel_request_type req_type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800181
182 if (!hdd_ctx) {
183 hdd_err("Invalid HDD context");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530184 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185 }
186
187 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
188 pRemainChanCtx = cfgState->remain_on_chan_ctx;
189
190 if (pRemainChanCtx == NULL) {
191 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700192 hdd_warn("No Rem on channel pending for which Rsp is received");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530193 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 }
195
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800196 hdd_debug("Received remain on channel rsp");
Deepthi Gowria0b85532016-10-13 16:14:17 +0530197 if (qdf_mc_timer_stop(&pRemainChanCtx->hdd_remain_on_chan_timer)
198 != QDF_STATUS_SUCCESS)
199 hdd_err("Failed to stop hdd_remain_on_chan_timer");
200 if (qdf_mc_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer)
201 != QDF_STATUS_SUCCESS)
202 hdd_err("Failed to destroy hdd_remain_on_chan_timer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 cfgState->remain_on_chan_ctx = NULL;
204 /*
205 * Resetting the roc in progress early ensures that the subsequent
206 * roc requests are immediately processed without being queued
207 */
208 pAdapter->is_roc_inprogress = false;
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800209 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210 /*
211 * If the allow suspend is done later, the scheduled roc wil prevent
212 * the system from going into suspend and immediately this logic
213 * will allow the system to go to suspend breaking the exising logic.
214 * Basically, the system must not go into suspend while roc is in
215 * progress.
216 */
217 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800218
219 if (REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request) {
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700220 if (cfgState->buf)
221 hdd_debug("Yet to rcv an ack for one of the tx pkt");
222
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800223 cfg80211_remain_on_channel_expired(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800224 pRemainChanCtx->dev->
225 ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226 pRemainChanCtx->
227 cookie,
228 &pRemainChanCtx->chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 GFP_KERNEL);
Deepthi Gowri6acee342016-10-28 15:00:38 +0530230 pAdapter->last_roc_ts =
231 (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 }
Nitesh Shahb75789d2017-02-06 15:24:59 +0530233 req_type = pRemainChanCtx->rem_on_chan_request;
234 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800235
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800236 if ((QDF_STA_MODE == pAdapter->device_mode) ||
237 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
238 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 ) {
240 uint8_t sessionId = pAdapter->sessionId;
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700241
Nitesh Shahb75789d2017-02-06 15:24:59 +0530242 if (REMAIN_ON_CHANNEL_REQUEST == req_type) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800243 sme_deregister_mgmt_frame(hHal, sessionId,
244 (SIR_MAC_MGMT_FRAME << 2) |
245 (SIR_MAC_MGMT_PROBE_REQ << 4),
246 NULL, 0);
247 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800248 } else if ((QDF_SAP_MODE == pAdapter->device_mode) ||
249 (QDF_P2P_GO_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800250 ) {
251 wlansap_de_register_mgmt_frame(
Dustin Brown0a1da142016-09-13 13:31:52 -0700252 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800253 (SIR_MAC_MGMT_FRAME << 2) |
Dustin Brown0a1da142016-09-13 13:31:52 -0700254 (SIR_MAC_MGMT_PROBE_REQ << 4),
255 NULL, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256
257 }
258
Nitesh Shahb75789d2017-02-06 15:24:59 +0530259 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
260 if (pRemainChanCtx) {
261 if (pRemainChanCtx->action_pkt_buff.frame_ptr != NULL
262 && pRemainChanCtx->action_pkt_buff.frame_length != 0) {
263 qdf_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 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800267 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530268 qdf_mem_free(pRemainChanCtx);
Nitesh Shahb75789d2017-02-06 15:24:59 +0530269 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800270 complete(&pAdapter->cancel_rem_on_chan_var);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530271 if (QDF_STATUS_SUCCESS != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272 complete(&pAdapter->rem_on_chan_ready_event);
Nitesh Shaha438c182017-02-13 18:02:25 +0530273
274 /* If we schedule work queue to start new RoC before completing
275 * cancel_rem_on_chan_var then the work queue may immediately get
276 * scheduled and update cfgState->remain_on_chan_ctx which is referred
277 * in mgmt_tx. Due to this update the the mgmt_tx may extend the roc
278 * which was already completed. This will lead to mgmt tx failure.
279 * Always schedule below work queue only after completing the
280 * cancel_rem_on_chan_var event.
281 */
282 schedule_delayed_work(&hdd_ctx->roc_req_work, 0);
283
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530284 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800285}
286
Wu Gao8a45ede2017-04-06 20:04:06 +0800287#ifdef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700288void wlan_hdd_cancel_existing_remain_on_channel(struct hdd_adapter *pAdapter)
Wu Gao8a45ede2017-04-06 20:04:06 +0800289{
290 QDF_STATUS status;
291
292 if (!pAdapter) {
293 hdd_err("null adapter");
294 return;
295 }
296
297 status = ucfg_p2p_cleanup_roc(pAdapter->hdd_vdev);
298 hdd_debug("status:%d", status);
299}
300#else
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700301void wlan_hdd_cancel_existing_remain_on_channel(struct hdd_adapter *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800302{
303 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
304 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
Jeff Johnson18767622017-08-28 11:46:50 -0700305 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800306 unsigned long rc;
Nitesh Shah49f53902017-03-16 16:21:16 +0530307 uint32_t roc_scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800308
309 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
310 if (cfgState->remain_on_chan_ctx != NULL) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800311 hdd_debug("Cancel Existing Remain on Channel");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800312
Anurag Chouhan210db072016-02-22 18:42:15 +0530313 if (QDF_TIMER_STATE_RUNNING == qdf_mc_timer_get_current_state(
Deepthi Gowria0b85532016-10-13 16:14:17 +0530314 &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer)) {
315 if (qdf_mc_timer_stop(&cfgState->remain_on_chan_ctx->
316 hdd_remain_on_chan_timer) != QDF_STATUS_SUCCESS)
317 hdd_err("Failed to stop hdd_remain_on_chan_timer");
318 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800319
320 pRemainChanCtx = cfgState->remain_on_chan_ctx;
321 if (pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress ==
Deepthi Gowria0b85532016-10-13 16:14:17 +0530322 true) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800323 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700324 hdd_err("ROC timer cancellation in progress wait for completion");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800325 rc = wait_for_completion_timeout(&pAdapter->
326 cancel_rem_on_chan_var,
327 msecs_to_jiffies
328 (WAIT_CANCEL_REM_CHAN));
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700329 if (!rc)
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700330 hdd_err("wait on cancel_rem_on_chan_var timed out");
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700331
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800332 return;
333 }
334 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true;
Nitesh Shah49f53902017-03-16 16:21:16 +0530335 roc_scan_id = pRemainChanCtx->scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700337 /* Wait till remain on channel ready indication before
338 * issuing cancel remain on channel request, otherwise
339 * if remain on channel not received and if the driver issues
340 * cancel remain on channel then lim will be in unknown state.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800341 */
342 rc = wait_for_completion_timeout(&pAdapter->
343 rem_on_chan_ready_event,
344 msecs_to_jiffies
345 (WAIT_REM_CHAN_READY));
346 if (!rc) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700347 hdd_err("timeout waiting for remain on channel ready indication");
Abhishek Singh5ea86532016-04-27 14:10:53 +0530348 cds_flush_logs(WLAN_LOG_TYPE_FATAL,
349 WLAN_LOG_INDICATOR_HOST_DRIVER,
350 WLAN_LOG_REASON_HDD_TIME_OUT,
351 true, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352 }
353
354 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
355
356 /* Issue abort remain on chan request to sme.
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700357 * The remain on channel callback will make sure the
358 * remain_on_chan expired event is sent.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800359 */
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800360 if ((QDF_STA_MODE == pAdapter->device_mode) ||
361 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
362 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363 ) {
364 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX
365 (pAdapter),
Nitesh Shah49f53902017-03-16 16:21:16 +0530366 pAdapter->sessionId, roc_scan_id);
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800367 } else if ((QDF_SAP_MODE == pAdapter->device_mode)
368 || (QDF_P2P_GO_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369 ) {
370 wlansap_cancel_remain_on_channel(
Nitesh Shah49f53902017-03-16 16:21:16 +0530371 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), roc_scan_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372 }
373
374 rc = wait_for_completion_timeout(&pAdapter->
375 cancel_rem_on_chan_var,
376 msecs_to_jiffies
377 (WAIT_CANCEL_REM_CHAN));
378
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700379 if (!rc)
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700380 hdd_err("timeout waiting for cancel remain on channel ready indication");
Srinivas Girigowdaef327802017-03-24 23:13:20 -0700381
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800382 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800383 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
384 } else
385 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
386}
Wu Gao8a45ede2017-04-06 20:04:06 +0800387#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700389int wlan_hdd_check_remain_on_channel(struct hdd_adapter *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800390{
391 int status = 0;
392 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
393
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800394 if (QDF_P2P_GO_MODE != pAdapter->device_mode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800395 /* Cancel Existing Remain On Channel */
396 /* If no action frame is pending */
397 if (cfgState->remain_on_chan_ctx != NULL) {
398 /* Check whether Action Frame is pending or not */
399 if (cfgState->buf == NULL) {
400 wlan_hdd_cancel_existing_remain_on_channel
401 (pAdapter);
402 } else {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800403 hdd_debug("Cannot Cancel Existing Remain on Channel");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800404 status = -EBUSY;
405 }
406 }
407 }
408 return status;
409}
410
411/**
412 * wlan_hdd_cancel_pending_roc() - Cancel pending roc
413 * @adapter: HDD adapter
414 *
415 * Cancels any pending remain on channel request
416 *
417 * Return: None
418 */
Wu Gao8a45ede2017-04-06 20:04:06 +0800419#ifndef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700420static void wlan_hdd_cancel_pending_roc(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800421{
422 hdd_remain_on_chan_ctx_t *roc_ctx;
423 unsigned long rc;
424 hdd_cfg80211_state_t *cfg_state = WLAN_HDD_GET_CFG_STATE_PTR(adapter);
Nitesh Shah49f53902017-03-16 16:21:16 +0530425 uint32_t roc_scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800426
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800427 hdd_debug("ROC completion is not received !!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800428
429 mutex_lock(&cfg_state->remain_on_chan_ctx_lock);
430 roc_ctx = cfg_state->remain_on_chan_ctx;
431
Ganesh Kondabattini1c6365c2017-05-11 13:11:41 +0530432 if (!roc_ctx) {
433 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
434 hdd_debug("roc_ctx is NULL, No pending RoC");
435 return;
436 }
437
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800438 if (roc_ctx->hdd_remain_on_chan_cancel_in_progress) {
439 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
440 hdd_debug("roc cancel already in progress");
441 /*
442 * Since a cancel roc is already issued and is
443 * in progress, we need not send another
444 * cancel roc again. Instead we can just wait
445 * for cancel roc completion
446 */
447 goto wait;
448 }
Nitesh Shah49f53902017-03-16 16:21:16 +0530449 roc_scan_id = roc_ctx->scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800450 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
451
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800452 if (adapter->device_mode == QDF_P2P_GO_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453 wlansap_cancel_remain_on_channel((WLAN_HDD_GET_CTX
Nitesh Shah49f53902017-03-16 16:21:16 +0530454 (adapter))->pcds_context, roc_scan_id);
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800455 } else if (adapter->device_mode == QDF_P2P_CLIENT_MODE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800456 || adapter->device_mode ==
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800457 QDF_P2P_DEVICE_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800458 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX
459 (adapter),
Nitesh Shah49f53902017-03-16 16:21:16 +0530460 adapter->sessionId, roc_scan_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800461 }
462
463wait:
464 rc = wait_for_completion_timeout(&adapter->cancel_rem_on_chan_var,
465 msecs_to_jiffies
466 (WAIT_CANCEL_REM_CHAN));
467 if (!rc) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700468 hdd_err("Timeout occurred while waiting for RoC Cancellation");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469 mutex_lock(&cfg_state->remain_on_chan_ctx_lock);
470 roc_ctx = cfg_state->remain_on_chan_ctx;
471 if (roc_ctx != NULL) {
472 cfg_state->remain_on_chan_ctx = NULL;
Deepthi Gowria0b85532016-10-13 16:14:17 +0530473 if (qdf_mc_timer_stop(&roc_ctx->
474 hdd_remain_on_chan_timer)
475 != QDF_STATUS_SUCCESS)
476 hdd_err("Failed to stop hdd_remain_on_chan_timer");
477 if (qdf_mc_timer_destroy(
478 &roc_ctx->hdd_remain_on_chan_timer)
479 != QDF_STATUS_SUCCESS)
480 hdd_err("Failed to destroy hdd_remain_on_chan_timer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800481 if (roc_ctx->action_pkt_buff.frame_ptr != NULL
482 && roc_ctx->action_pkt_buff.frame_length != 0) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530483 qdf_mem_free(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800484 roc_ctx->action_pkt_buff.frame_ptr);
485 roc_ctx->action_pkt_buff.frame_ptr = NULL;
486 roc_ctx->action_pkt_buff.frame_length = 0;
487 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530488 qdf_mem_free(roc_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489 adapter->is_roc_inprogress = false;
490 }
491 mutex_unlock(&cfg_state->remain_on_chan_ctx_lock);
492 }
493}
Wu Gao8a45ede2017-04-06 20:04:06 +0800494#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495
496/* Clean up RoC context at hdd_stop_adapter*/
Wu Gao8a45ede2017-04-06 20:04:06 +0800497#ifdef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700498void wlan_hdd_cleanup_remain_on_channel_ctx(struct hdd_adapter *pAdapter)
Wu Gao8a45ede2017-04-06 20:04:06 +0800499{
500 QDF_STATUS status;
501
502 if (!pAdapter) {
503 hdd_err("null adapter");
504 return;
505 }
506
507 status = ucfg_p2p_cleanup_roc(pAdapter->hdd_vdev);
508 hdd_debug("status:%d", status);
509}
510#else
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700511void wlan_hdd_cleanup_remain_on_channel_ctx(struct hdd_adapter *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800512{
513 uint8_t retry = 0;
514 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
515
516 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
517 while (pAdapter->is_roc_inprogress) {
518 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800519 hdd_debug("ROC in progress for session %d!!!",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700520 pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521 msleep(500);
522 if (retry++ > 3) {
523 wlan_hdd_cancel_pending_roc(pAdapter);
524 /* hold the lock before break from the loop */
525 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
526 break;
527 }
528 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
529 } /* end of while */
530 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
531
532}
Wu Gao8a45ede2017-04-06 20:04:06 +0800533#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534
Jeff Johnsond2291042016-10-05 16:18:50 -0700535static void wlan_hdd_remain_on_chan_timeout(void *data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800536{
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700537 struct hdd_adapter *pAdapter = (struct hdd_adapter *) data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
539 hdd_cfg80211_state_t *cfgState;
Jeff Johnson18767622017-08-28 11:46:50 -0700540 struct hdd_context *hdd_ctx;
Nitesh Shahb75789d2017-02-06 15:24:59 +0530541 uint32_t roc_scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542
c_hpothud5009242016-08-18 12:10:36 +0530543 if ((NULL == pAdapter) ||
544 (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
545 hdd_err("pAdapter is invalid %p !!!", pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546 return;
547 }
548
Komal Seelamaa75f262016-09-29 12:32:13 +0530549 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
551 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
552 pRemainChanCtx = cfgState->remain_on_chan_ctx;
553
554 if (NULL == pRemainChanCtx) {
555 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700556 hdd_err("No Remain on channel is pending");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800557 return;
558 }
559
560 if (true == pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) {
561 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700562 hdd_err("Cancellation already in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800563 return;
564 }
565
566 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true;
Nitesh Shahb75789d2017-02-06 15:24:59 +0530567 roc_scan_id = pRemainChanCtx->scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800568 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800569 hdd_debug("Cancel Remain on Channel on timeout");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800570
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800571 if ((QDF_STA_MODE == pAdapter->device_mode) ||
572 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
573 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574 ) {
575 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter),
Nitesh Shahb75789d2017-02-06 15:24:59 +0530576 pAdapter->sessionId, roc_scan_id);
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800577 } else if ((QDF_SAP_MODE == pAdapter->device_mode) ||
578 (QDF_P2P_GO_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800579 ) {
580 wlansap_cancel_remain_on_channel(
581 (WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
Nitesh Shahb75789d2017-02-06 15:24:59 +0530582 roc_scan_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800583 }
584
Kabilan Kannan6ca98482017-02-14 13:26:15 -0800585 hdd_tdls_notify_p2p_roc(hdd_ctx, P2P_ROC_END);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800586 qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800587 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800588}
589
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700590static int wlan_hdd_execute_remain_on_channel(struct hdd_adapter *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 hdd_remain_on_chan_ctx_t *pRemainChanCtx)
592{
593 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530594 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Jeff Johnson18767622017-08-28 11:46:50 -0700595 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800596 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700597 struct hdd_adapter *pAdapter_temp;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530598 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800599 bool isGoPresent = false;
600 unsigned int duration;
601
602
603 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
604 if (pAdapter->is_roc_inprogress == true) {
605 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700606 hdd_err("remain on channel request is in execution");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800607 return -EBUSY;
608 }
609
610 cfgState->remain_on_chan_ctx = pRemainChanCtx;
611 cfgState->current_freq = pRemainChanCtx->chan.center_freq;
612 pAdapter->is_roc_inprogress = true;
613 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
614
615 /* Initialize Remain on chan timer */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530616 qdf_status =
Anurag Chouhan210db072016-02-22 18:42:15 +0530617 qdf_mc_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530618 QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800619 wlan_hdd_remain_on_chan_timeout, pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530620 if (qdf_status != QDF_STATUS_SUCCESS) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700621 hdd_err("Not able to initialize remain_on_chan timer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800622 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
623 cfgState->remain_on_chan_ctx = NULL;
624 pAdapter->is_roc_inprogress = false;
625 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530626 qdf_mem_free(pRemainChanCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800627 return -EINVAL;
628 }
629
630 status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530631 while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800632 pAdapter_temp = pAdapterNode->pAdapter;
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800633 if (pAdapter_temp->device_mode == QDF_P2P_GO_MODE)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800634 isGoPresent = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800635 status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
636 pAdapterNode = pNext;
637 }
638
639 /* Extending duration for proactive extension logic for RoC */
640 duration = pRemainChanCtx->duration;
Nitesh Shah85234722017-02-17 16:37:45 +0530641 if (duration < HDD_P2P_MAX_ROC_DURATION) {
642 if (isGoPresent == true)
643 duration *= P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT;
644 else
645 duration *= P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT;
646 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647
648 hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800649 qdf_runtime_pm_prevent_suspend(&pHddCtx->runtime_context.roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800650 INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
651
652 /* call sme API to start remain on channel. */
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800653 if ((QDF_STA_MODE == pAdapter->device_mode) ||
654 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
655 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800656 ) {
657 uint8_t sessionId = pAdapter->sessionId;
658 /* call sme API to start remain on channel. */
659
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530660 if (QDF_STATUS_SUCCESS != sme_remain_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800661 WLAN_HDD_GET_HAL_CTX(pAdapter),
662 sessionId,
663 pRemainChanCtx->chan.hw_value, duration,
664 wlan_hdd_remain_on_channel_callback,
665 pAdapter,
666 (pRemainChanCtx->rem_on_chan_request ==
667 REMAIN_ON_CHANNEL_REQUEST) ? true : false,
668 &pRemainChanCtx->scan_id)) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700669 hdd_err("sme_remain_on_channel failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800670 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800671 pAdapter->is_roc_inprogress = false;
Deepthi Gowria0b85532016-10-13 16:14:17 +0530672 pRemainChanCtx = cfgState->remain_on_chan_ctx;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800673 hdd_debug("Freeing ROC ctx cfgState->remain_on_chan_ctx=%p",
Jeff Johnson1a92f8c2016-12-05 13:03:58 -0800674 cfgState->remain_on_chan_ctx);
Deepthi Gowria0b85532016-10-13 16:14:17 +0530675 if (pRemainChanCtx) {
676 if (qdf_mc_timer_destroy(
677 &pRemainChanCtx->
678 hdd_remain_on_chan_timer)
679 != QDF_STATUS_SUCCESS)
680 hdd_err("Failed to destroy hdd_remain_on_chan_timer");
681 qdf_mem_free(pRemainChanCtx);
682 cfgState->remain_on_chan_ctx = NULL;
683 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800684 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800685 qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context.
Komal Seelamaa75f262016-09-29 12:32:13 +0530686 roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800687 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
688 return -EINVAL;
689 }
690
691 if (REMAIN_ON_CHANNEL_REQUEST ==
692 pRemainChanCtx->rem_on_chan_request) {
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530693 if (QDF_STATUS_SUCCESS != sme_register_mgmt_frame(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800694 WLAN_HDD_GET_HAL_CTX(pAdapter),
695 sessionId,
696 (SIR_MAC_MGMT_FRAME << 2) |
697 (SIR_MAC_MGMT_PROBE_REQ << 4),
698 NULL, 0))
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700699 hdd_err("sme_register_mgmt_frame failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800700 }
701
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800702 } else if ((QDF_SAP_MODE == pAdapter->device_mode) ||
703 (QDF_P2P_GO_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800704 /* call sme API to start remain on channel. */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530705 if (QDF_STATUS_SUCCESS != wlansap_remain_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800706 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707 pRemainChanCtx->chan.hw_value,
708 duration, wlan_hdd_remain_on_channel_callback,
709 pAdapter, &pRemainChanCtx->scan_id)) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700710 hdd_err("wlansap_remain_on_channel failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800712 pAdapter->is_roc_inprogress = false;
Deepthi Gowria0b85532016-10-13 16:14:17 +0530713 pRemainChanCtx = cfgState->remain_on_chan_ctx;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800714 hdd_debug("Freeing ROC ctx cfgState->remain_on_chan_ctx=%p",
Jeff Johnson1a92f8c2016-12-05 13:03:58 -0800715 cfgState->remain_on_chan_ctx);
Deepthi Gowria0b85532016-10-13 16:14:17 +0530716 if (pRemainChanCtx) {
717 if (qdf_mc_timer_destroy(
718 &pRemainChanCtx->
719 hdd_remain_on_chan_timer)
720 != QDF_STATUS_SUCCESS)
721 hdd_err("Failed to destroy hdd_remain_on_chan_timer");
722 qdf_mem_free(pRemainChanCtx);
723 cfgState->remain_on_chan_ctx = NULL;
724 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800725 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800726 qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context.
Komal Seelamaa75f262016-09-29 12:32:13 +0530727 roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
729 return -EINVAL;
730 }
731
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530732 if (QDF_STATUS_SUCCESS != wlansap_register_mgmt_frame(
Dustin Brown0a1da142016-09-13 13:31:52 -0700733 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800734 (SIR_MAC_MGMT_FRAME << 2) |
735 (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0)) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700736 hdd_err("wlansap_register_mgmt_frame return fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800737 wlansap_cancel_remain_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800738 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
Dustin Brown0a1da142016-09-13 13:31:52 -0700739 pRemainChanCtx->scan_id);
Prashanth Bhatta87b6dc02017-01-19 15:17:58 -0800740 qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context.
Komal Seelamaa75f262016-09-29 12:32:13 +0530741 roc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
743 return -EINVAL;
744 }
745
746 }
Kabilan Kannan6ca98482017-02-14 13:26:15 -0800747 hdd_tdls_notify_p2p_roc(pHddCtx, P2P_ROC_START);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748 return 0;
749}
750
751/**
752 * wlan_hdd_roc_request_enqueue() - enqueue remain on channel request
753 * @adapter: Pointer to the adapter
754 * @remain_chan_ctx: Pointer to the remain on channel context
755 *
756 * Return: 0 on success, error number otherwise
757 */
Wu Gao9a704f42017-03-10 18:42:11 +0800758#ifndef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700759static int wlan_hdd_roc_request_enqueue(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800760 hdd_remain_on_chan_ctx_t *remain_chan_ctx)
761{
Jeff Johnson18767622017-08-28 11:46:50 -0700762 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800763 hdd_roc_req_t *hdd_roc_req;
Anurag Chouhanffb21542016-02-17 14:33:03 +0530764 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800765
766 /*
767 * "Driver is busy" OR "there is already RoC request inside the queue"
768 * so enqueue this RoC Request and execute sequentially later.
769 */
770
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530771 hdd_roc_req = qdf_mem_malloc(sizeof(*hdd_roc_req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800772
773 if (NULL == hdd_roc_req) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800774 hdd_err("malloc failed for roc req context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775 return -ENOMEM;
776 }
777
778 hdd_roc_req->pAdapter = adapter;
779 hdd_roc_req->pRemainChanCtx = remain_chan_ctx;
780
781 /* Enqueue this RoC request */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530782 qdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530783 status = qdf_list_insert_back(&hdd_ctx->hdd_roc_req_q,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800784 &hdd_roc_req->node);
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530785 qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800786
Anurag Chouhanffb21542016-02-17 14:33:03 +0530787 if (QDF_STATUS_SUCCESS != status) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800788 hdd_err("Not able to enqueue RoC Req context");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530789 qdf_mem_free(hdd_roc_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800790 return -EINVAL;
791 }
792
793 return 0;
794}
Wu Gao9a704f42017-03-10 18:42:11 +0800795#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796
797/**
798 * wlan_hdd_indicate_roc_drop() - Indicate roc drop to userspace
799 * @adapter: HDD adapter
800 * @ctx: Remain on channel context
801 *
802 * Send remain on channel ready and cancel event for the queued
803 * roc that is being dropped. This will ensure that the userspace
804 * will send more roc requests. If this drop is not indicated to
805 * userspace, subsequent roc will not be sent to the driver since
806 * the userspace times out waiting for the remain on channel ready
807 * event.
808 *
809 * Return: None
810 */
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700811static void wlan_hdd_indicate_roc_drop(struct hdd_adapter *adapter,
Jeff Johnsond2291042016-10-05 16:18:50 -0700812 hdd_remain_on_chan_ctx_t *ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813{
814 hdd_debug("indicate roc drop to userspace");
815 cfg80211_ready_on_channel(
816 adapter->dev->ieee80211_ptr,
817 (uintptr_t)ctx,
818 &ctx->chan,
819 ctx->duration, GFP_KERNEL);
820
821 cfg80211_remain_on_channel_expired(
822 ctx->dev->ieee80211_ptr,
823 ctx->cookie,
824 &ctx->chan,
825 GFP_KERNEL);
826}
827
828/**
829 * wlan_hdd_roc_request_dequeue() - dequeue remain on channel request
830 * @work: Pointer to work queue struct
831 *
832 * Return: none
833 */
834void wlan_hdd_roc_request_dequeue(struct work_struct *work)
835{
Anurag Chouhanffb21542016-02-17 14:33:03 +0530836 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800837 int ret = 0;
838 hdd_roc_req_t *hdd_roc_req;
Jeff Johnson18767622017-08-28 11:46:50 -0700839 struct hdd_context *hdd_ctx =
840 container_of(work, struct hdd_context, roc_req_work.work);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841
842 hdd_debug("going to dequeue roc");
843
844 if (0 != (wlan_hdd_validate_context(hdd_ctx)))
845 return;
846
847 /*
848 * The queued roc requests is dequeued and processed one at a time.
849 * Callback 'wlan_hdd_remain_on_channel_callback' ensures
850 * that any pending roc in the queue will be scheduled
851 * on the current roc completion by scheduling the work queue.
852 */
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530853 qdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 if (list_empty(&hdd_ctx->hdd_roc_req_q.anchor)) {
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530855 qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800856 return;
857 }
Anurag Chouhanffb21542016-02-17 14:33:03 +0530858 status = qdf_list_remove_front(&hdd_ctx->hdd_roc_req_q,
859 (qdf_list_node_t **) &hdd_roc_req);
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530860 qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530861 if (QDF_STATUS_SUCCESS != status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862 hdd_debug("unable to remove roc element from list");
863 return;
864 }
865 ret = wlan_hdd_execute_remain_on_channel(
866 hdd_roc_req->pAdapter,
867 hdd_roc_req->pRemainChanCtx);
868 if (ret == -EBUSY) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700869 hdd_err("dropping RoC request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800870 wlan_hdd_indicate_roc_drop(hdd_roc_req->pAdapter,
871 hdd_roc_req->pRemainChanCtx);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530872 qdf_mem_free(hdd_roc_req->pRemainChanCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530874 qdf_mem_free(hdd_roc_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875}
876
Wu Gao9a704f42017-03-10 18:42:11 +0800877#ifndef CONVERGED_P2P_ENABLE
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878static int wlan_hdd_request_remain_on_channel(struct wiphy *wiphy,
879 struct net_device *dev,
880 struct ieee80211_channel *chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800881 unsigned int duration,
882 u64 *cookie,
Srinivas Girigowda85218af2017-03-25 13:21:40 -0700883 enum rem_on_channel_request_type
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 request_type)
885{
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700886 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson18767622017-08-28 11:46:50 -0700887 struct hdd_context *pHddCtx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
889 bool isBusy = false;
890 uint32_t size = 0;
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700891 struct hdd_adapter *sta_adapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800892 int ret;
893 int status = 0;
894
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800895 hdd_debug("Device_mode %s(%d)",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700896 hdd_device_mode_to_string(pAdapter->device_mode),
897 pAdapter->device_mode);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800898 hdd_debug("chan(hw_val)0x%x chan(centerfreq) %d, duration %d",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -0700899 chan->hw_value, chan->center_freq, duration);
Kapil Guptabf4943c2016-10-13 12:15:39 +0530900
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
902 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530903 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 return ret;
Tushnim Bhattacharyya9e81b4c2017-02-15 17:11:14 -0800905 if (hdd_is_connection_in_progress(NULL, NULL)) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800906 hdd_debug("Connection is in progress");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 isBusy = true;
908 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530909 pRemainChanCtx = qdf_mem_malloc(sizeof(hdd_remain_on_chan_ctx_t));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800910 if (NULL == pRemainChanCtx) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800911 hdd_err("Not able to allocate memory for Channel context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800912 return -ENOMEM;
913 }
914
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530915 qdf_mem_copy(&pRemainChanCtx->chan, chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 sizeof(struct ieee80211_channel));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 pRemainChanCtx->duration = duration;
918 pRemainChanCtx->dev = dev;
919 *cookie = (uintptr_t) pRemainChanCtx;
920 pRemainChanCtx->cookie = *cookie;
921 pRemainChanCtx->rem_on_chan_request = request_type;
922 pRemainChanCtx->action_pkt_buff.freq = 0;
923 pRemainChanCtx->action_pkt_buff.frame_ptr = NULL;
924 pRemainChanCtx->action_pkt_buff.frame_length = 0;
925 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = false;
926 if (REMAIN_ON_CHANNEL_REQUEST == request_type) {
Krunal Sonifb84cbd2016-03-10 13:09:07 -0800927 sta_adapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530928 if ((NULL != sta_adapter) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800929 hdd_conn_is_connected(
930 WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter))) {
Anurag Chouhanffb21542016-02-17 14:33:03 +0530931 if (pAdapter->last_roc_ts != 0 &&
Deepthi Gowri6acee342016-10-28 15:00:38 +0530932 (((uint64_t)qdf_mc_timer_get_system_time() -
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800933 pAdapter->last_roc_ts) <
934 pHddCtx->config->p2p_listen_defer_interval)) {
935 if (pRemainChanCtx->duration > HDD_P2P_MAX_ROC_DURATION)
936 pRemainChanCtx->duration =
937 HDD_P2P_MAX_ROC_DURATION;
938
939 wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx);
940 schedule_delayed_work(&pHddCtx->roc_req_work,
941 msecs_to_jiffies(
942 pHddCtx->config->p2p_listen_defer_interval));
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -0800943 hdd_debug("Defer interval is %hu, pAdapter %p",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 pHddCtx->config->p2p_listen_defer_interval,
945 pAdapter);
946 return 0;
947 }
948 }
949 }
950
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530951 qdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +0530952 size = qdf_list_size(&(pHddCtx->hdd_roc_req_q));
Anurag Chouhana37b5b72016-02-21 14:53:42 +0530953 qdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 if ((isBusy == false) && (!size)) {
955 status = wlan_hdd_execute_remain_on_channel(pAdapter,
956 pRemainChanCtx);
957 if (status == -EBUSY) {
958 if (wlan_hdd_roc_request_enqueue(pAdapter,
959 pRemainChanCtx)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530960 qdf_mem_free(pRemainChanCtx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800961 return -EAGAIN;
962 }
963 }
964 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -0800965 }
966
967 if (wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx)) {
968 qdf_mem_free(pRemainChanCtx);
969 return -EAGAIN;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970 }
971
972 /*
973 * If a connection is not in progress (isBusy), before scheduling
974 * the work queue it is necessary to check if a roc in in progress
975 * or not because: if an roc is in progress, the dequeued roc
976 * that will be processed will be dropped. To ensure that this new
977 * roc request is not dropped, it is suggested to check if an roc
978 * is in progress or not. The existing roc completion will provide
979 * the trigger to dequeue the next roc request.
980 */
981 if (isBusy == false && pAdapter->is_roc_inprogress == false) {
982 hdd_debug("scheduling delayed work: no connection/roc active");
983 schedule_delayed_work(&pHddCtx->roc_req_work, 0);
984 }
985 return 0;
986}
Wu Gao9a704f42017-03-10 18:42:11 +0800987#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988
Wu Gao9a704f42017-03-10 18:42:11 +0800989#ifdef CONVERGED_P2P_ENABLE
990static int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy,
991 struct wireless_dev *wdev,
992 struct ieee80211_channel *chan,
993 unsigned int duration,
994 u64 *cookie)
995{
996 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -0700997 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson18767622017-08-28 11:46:50 -0700998 struct hdd_context *hdd_ctx;
Wu Gao9a704f42017-03-10 18:42:11 +0800999 QDF_STATUS status;
1000 int ret;
1001
1002 ENTER();
1003
1004 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
1005 ret = wlan_hdd_validate_context(hdd_ctx);
1006 if (0 != ret)
1007 return ret;
1008
1009 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1010 hdd_err("Command not allowed in FTM mode");
1011 return -EINVAL;
1012 }
1013
1014 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1015 hdd_err("invalid session id: %d", pAdapter->sessionId);
1016 return -EINVAL;
1017 }
1018
1019 status = wlan_cfg80211_roc(pAdapter->hdd_vdev, chan,
1020 duration, cookie);
1021 hdd_info("remain on channel request, status:%d", status);
1022
1023 return qdf_status_to_os_return(status);
1024}
1025#else
Jeff Johnsond2291042016-10-05 16:18:50 -07001026static int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy,
1027 struct wireless_dev *wdev,
1028 struct ieee80211_channel *chan,
1029 unsigned int duration,
1030 u64 *cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001033 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson18767622017-08-28 11:46:50 -07001034 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035 int ret;
1036
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301037 ENTER();
1038
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
1040 ret = wlan_hdd_validate_context(hdd_ctx);
1041 if (0 != ret)
1042 return ret;
1043
Anurag Chouhan6d760662016-02-20 16:05:43 +05301044 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001045 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 return -EINVAL;
1047 }
1048
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301049 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1050 hdd_err("invalid session id: %d", pAdapter->sessionId);
1051 return -EINVAL;
1052 }
1053
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301054 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001055 TRACE_CODE_HDD_REMAIN_ON_CHANNEL,
1056 pAdapter->sessionId, REMAIN_ON_CHANNEL_REQUEST));
Amar Singhal01098f72015-10-08 11:55:32 -07001057
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301058 ret = wlan_hdd_request_remain_on_channel(wiphy, dev, chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059 duration, cookie,
1060 REMAIN_ON_CHANNEL_REQUEST);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301061 EXIT();
1062 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063}
Wu Gao9a704f42017-03-10 18:42:11 +08001064#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001065
1066int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001067 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001068 struct ieee80211_channel *chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001069 unsigned int duration, u64 *cookie)
1070{
1071 int ret;
1072
1073 cds_ssr_protect(__func__);
1074 ret = __wlan_hdd_cfg80211_remain_on_channel(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001075 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001076 chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001077 duration, cookie);
1078 cds_ssr_unprotect(__func__);
1079
1080 return ret;
1081}
1082
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001083void hdd_remain_chan_ready_handler(struct hdd_adapter *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001084 uint32_t scan_id)
1085{
1086 hdd_cfg80211_state_t *cfgState = NULL;
1087 hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301088 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001089
1090 if (NULL == pAdapter) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001091 hdd_err("pAdapter is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001092 return;
1093 }
1094 cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001095 hdd_debug("Ready on chan ind %d", scan_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096
Deepthi Gowri6acee342016-10-28 15:00:38 +05301097 pAdapter->start_roc_ts = (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1099 pRemainChanCtx = cfgState->remain_on_chan_ctx;
1100 if (pRemainChanCtx != NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301101 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001102 TRACE_CODE_HDD_REMAINCHANREADYHANDLER,
1103 pAdapter->sessionId,
1104 pRemainChanCtx->duration));
1105 /* start timer for actual duration */
Anurag Chouhan210db072016-02-22 18:42:15 +05301106 if (QDF_TIMER_STATE_RUNNING ==
1107 qdf_mc_timer_get_current_state(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 &pRemainChanCtx->hdd_remain_on_chan_timer)) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001109 hdd_err("Timer Started before ready event!!!");
Deepthi Gowria0b85532016-10-13 16:14:17 +05301110 if (qdf_mc_timer_stop(&pRemainChanCtx->
1111 hdd_remain_on_chan_timer)
1112 != QDF_STATUS_SUCCESS)
1113 hdd_err("Failed to stop hdd_remain_on_chan_timer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001114 }
1115 status =
Anurag Chouhan210db072016-02-22 18:42:15 +05301116 qdf_mc_timer_start(&pRemainChanCtx->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 hdd_remain_on_chan_timer,
1118 (pRemainChanCtx->duration +
1119 COMPLETE_EVENT_PROPOGATE_TIME));
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001120 if (status != QDF_STATUS_SUCCESS)
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001121 hdd_err("Remain on Channel timer start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001122
1123 if (REMAIN_ON_CHANNEL_REQUEST ==
1124 pRemainChanCtx->rem_on_chan_request) {
1125 cfg80211_ready_on_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126 pAdapter->dev->
1127 ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 (uintptr_t)
1129 pRemainChanCtx,
1130 &pRemainChanCtx->chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001131 pRemainChanCtx->
1132 duration, GFP_KERNEL);
1133 } else if (OFF_CHANNEL_ACTION_TX ==
1134 pRemainChanCtx->rem_on_chan_request) {
1135 complete(&pAdapter->offchannel_tx_event);
1136 }
1137 /* Check for cached action frame */
1138 if (pRemainChanCtx->action_pkt_buff.frame_length != 0) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001139 hdd_debug("Sent cached action frame to supplicant");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
1141 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
1142 pRemainChanCtx->action_pkt_buff.freq, 0,
1143 pRemainChanCtx->action_pkt_buff.frame_ptr,
1144 pRemainChanCtx->action_pkt_buff.frame_length,
1145 NL80211_RXMGMT_FLAG_ANSWERED);
1146#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
1147 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
1148 pRemainChanCtx->action_pkt_buff.freq, 0,
1149 pRemainChanCtx->action_pkt_buff.frame_ptr,
1150 pRemainChanCtx->action_pkt_buff.frame_length,
1151 NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
Amar Singhal01098f72015-10-08 11:55:32 -07001152#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001153 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
1154 pRemainChanCtx->action_pkt_buff.freq,
1155 0,
1156 pRemainChanCtx->action_pkt_buff.
1157 frame_ptr,
1158 pRemainChanCtx->action_pkt_buff.
1159 frame_length, GFP_ATOMIC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160#endif /* LINUX_VERSION_CODE */
1161
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301162 qdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001163 pRemainChanCtx->action_pkt_buff.frame_length = 0;
1164 pRemainChanCtx->action_pkt_buff.freq = 0;
1165 pRemainChanCtx->action_pkt_buff.frame_ptr = NULL;
1166 }
1167 complete(&pAdapter->rem_on_chan_ready_event);
1168 } else {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001169 hdd_debug("No Pending Remain on channel Request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001170 }
1171 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001172}
1173
Wu Gao9a704f42017-03-10 18:42:11 +08001174#ifdef CONVERGED_P2P_ENABLE
1175static int
1176__wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
1177 struct wireless_dev *wdev,
1178 u64 cookie)
1179{
1180 QDF_STATUS status;
1181 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001182 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Wu Gao9a704f42017-03-10 18:42:11 +08001183
1184 ENTER();
1185
1186 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1187 hdd_err("Command not allowed in FTM mode");
1188 return -EINVAL;
1189 }
1190
1191 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1192 hdd_err("invalid session id: %d", pAdapter->sessionId);
1193 return -EINVAL;
1194 }
1195
1196 status = wlan_cfg80211_cancel_roc(pAdapter->hdd_vdev, cookie);
1197 hdd_info("cancel remain on channel, status:%d", status);
1198
1199 return 0;
1200}
1201#else
Jeff Johnsond2291042016-10-05 16:18:50 -07001202static int
1203__wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
1204 struct wireless_dev *wdev,
1205 u64 cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001206{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001208 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001209 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
1210 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
Jeff Johnson18767622017-08-28 11:46:50 -07001211 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001212 int status;
Anurag Chouhanffb21542016-02-17 14:33:03 +05301213 int qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001214 unsigned long rc;
Anurag Chouhanffb21542016-02-17 14:33:03 +05301215 qdf_list_node_t *tmp, *q;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216 hdd_roc_req_t *curr_roc_req;
Nitesh Shahb75789d2017-02-06 15:24:59 +05301217 uint32_t roc_scan_id;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301218 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219
Anurag Chouhan6d760662016-02-20 16:05:43 +05301220 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001221 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001222 return -EINVAL;
1223 }
1224
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301225 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1226 hdd_err("invalid session id: %d", pAdapter->sessionId);
1227 return -EINVAL;
1228 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 status = wlan_hdd_validate_context(pHddCtx);
1230
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301231 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 return status;
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301233 qdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001234 list_for_each_safe(tmp, q, &pHddCtx->hdd_roc_req_q.anchor) {
1235 curr_roc_req = list_entry(tmp, hdd_roc_req_t, node);
1236 if ((uintptr_t) curr_roc_req->pRemainChanCtx == cookie) {
Anurag Chouhanffb21542016-02-17 14:33:03 +05301237 qdf_status = qdf_list_remove_node(&pHddCtx->hdd_roc_req_q,
1238 (qdf_list_node_t *)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001239 curr_roc_req);
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301240 qdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock);
Anurag Chouhanffb21542016-02-17 14:33:03 +05301241 if (qdf_status == QDF_STATUS_SUCCESS) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301242 qdf_mem_free(curr_roc_req->pRemainChanCtx);
1243 qdf_mem_free(curr_roc_req);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001244 }
1245 return 0;
1246 }
1247 }
Anurag Chouhana37b5b72016-02-21 14:53:42 +05301248 qdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001249 /* FIXME cancel currently running remain on chan.
1250 * Need to check cookie and cancel accordingly
1251 */
1252 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1253 pRemainChanCtx = cfgState->remain_on_chan_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001254
Ganesh Kondabattini2da6ac02017-02-08 17:51:07 +05301255 if (pRemainChanCtx) {
Varun Reddy Yeturudd51e8d2017-05-14 14:51:13 -07001256 hdd_debug("action_cookie = %08llx, roc cookie = %08llx, cookie = %08llx",
Ganesh Kondabattini2da6ac02017-02-08 17:51:07 +05301257 cfgState->action_cookie, pRemainChanCtx->cookie,
1258 cookie);
1259
1260 if (pRemainChanCtx->cookie == cookie) {
1261 /* request to cancel on-going roc */
1262 if (cfgState->buf) {
1263 /* Tx frame pending */
1264 if (cfgState->action_cookie != cookie) {
1265 hdd_debug("Cookie matched with RoC cookie but not with tx cookie, indicate expired event for roc");
1266 /* RoC was extended to accomodate the tx frame */
1267 if (REMAIN_ON_CHANNEL_REQUEST ==
1268 pRemainChanCtx->
1269 rem_on_chan_request) {
1270 cfg80211_remain_on_channel_expired(
1271 pRemainChanCtx->dev->
1272 ieee80211_ptr,
1273 pRemainChanCtx->cookie,
1274 &pRemainChanCtx->chan,
1275 GFP_KERNEL);
1276 }
1277 pRemainChanCtx->rem_on_chan_request =
1278 OFF_CHANNEL_ACTION_TX;
1279 pRemainChanCtx->cookie =
1280 cfgState->action_cookie;
Tushnim Bhattacharyyac827df32017-06-05 17:45:03 -07001281 mutex_unlock(&cfgState->
1282 remain_on_chan_ctx_lock);
Ganesh Kondabattini2da6ac02017-02-08 17:51:07 +05301283 return 0;
1284 }
1285 }
1286 } else if (cfgState->buf && cfgState->action_cookie ==
1287 cookie) {
1288 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1289 hdd_debug("Cookie not matched with RoC cookie but matched with tx cookie, cleanup action frame");
1290 /*free the buf and return 0*/
1291 hdd_cleanup_actionframe(pHddCtx, pAdapter);
1292 return 0;
1293 } else {
1294 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1295 hdd_debug("No matching cookie");
1296 return -EINVAL;
1297 }
1298 } else {
1299 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1300 hdd_debug("RoC context is NULL, return success");
1301 return 0;
1302 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001303 if (NULL != cfgState->remain_on_chan_ctx) {
Deepthi Gowria0b85532016-10-13 16:14:17 +05301304 if (qdf_mc_timer_stop(&cfgState->remain_on_chan_ctx->
1305 hdd_remain_on_chan_timer)
1306 != QDF_STATUS_SUCCESS)
1307 hdd_err("Failed to stop hdd_remain_on_chan_timer");
Jeff Johnson68755312017-02-10 11:46:55 -08001308 if (pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001309 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001310 hdd_debug("ROC timer cancellation in progress, wait for completion");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311 rc = wait_for_completion_timeout(&pAdapter->
1312 cancel_rem_on_chan_var,
1313 msecs_to_jiffies
1314 (WAIT_CANCEL_REM_CHAN));
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001315 if (!rc)
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001316 hdd_err("wait on cancel_rem_on_chan_var timed out");
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001317
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001318 return 0;
Jeff Johnson68755312017-02-10 11:46:55 -08001319 }
1320 pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001321 }
Nitesh Shahb75789d2017-02-06 15:24:59 +05301322 roc_scan_id = pRemainChanCtx->scan_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001323 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1324
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001325 /* wait until remain on channel ready event received
Jeff Johnson3aaa4922017-01-12 08:46:09 -08001326 * for already issued remain on channel request
1327 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001328 rc = wait_for_completion_timeout(&pAdapter->rem_on_chan_ready_event,
1329 msecs_to_jiffies(WAIT_REM_CHAN_READY));
1330 if (!rc) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001331 hdd_err("timeout waiting for remain on channel ready indication");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001332
Prashanth Bhatta9e143052015-12-04 11:56:47 -08001333 if (cds_is_driver_recovering()) {
1334 hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
1335 cds_get_driver_state());
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001336 return -EAGAIN;
1337 }
Abhishek Singh5ea86532016-04-27 14:10:53 +05301338 cds_flush_logs(WLAN_LOG_TYPE_FATAL,
1339 WLAN_LOG_INDICATOR_HOST_DRIVER,
1340 WLAN_LOG_REASON_HDD_TIME_OUT,
1341 true, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001342 }
1343 INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
1344 /* Issue abort remain on chan request to sme.
1345 * The remain on channel callback will make sure the remain_on_chan
1346 * expired event is sent.
1347 */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001348 if ((QDF_STA_MODE == pAdapter->device_mode) ||
1349 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
1350 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001351 ) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001352 uint8_t sessionId = pAdapter->sessionId;
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001353
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001354 sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter),
Nitesh Shahb75789d2017-02-06 15:24:59 +05301355 sessionId, roc_scan_id);
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001356 } else if ((QDF_SAP_MODE == pAdapter->device_mode) ||
1357 (QDF_P2P_GO_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001358 ) {
1359 wlansap_cancel_remain_on_channel(
Nitesh Shahb75789d2017-02-06 15:24:59 +05301360 WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), roc_scan_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001361
1362 } else {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001363 hdd_err("Invalid device_mode %s(%d)",
1364 hdd_device_mode_to_string(pAdapter->device_mode),
1365 pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001366 return -EIO;
1367 }
1368 rc = wait_for_completion_timeout(&pAdapter->cancel_rem_on_chan_var,
1369 msecs_to_jiffies
1370 (WAIT_CANCEL_REM_CHAN));
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001371 if (!rc)
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001372 hdd_err("wait on cancel_rem_on_chan_var timed out");
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001373
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001374 hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001375
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301376 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377 return 0;
1378}
Wu Gao9a704f42017-03-10 18:42:11 +08001379#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380
1381int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382 struct wireless_dev *wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001383 u64 cookie)
1384{
1385 int ret;
1386
1387 cds_ssr_protect(__func__);
1388 ret = __wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389 wdev,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001390 cookie);
1391 cds_ssr_unprotect(__func__);
1392
1393 return ret;
1394}
1395
Wu Gao9a704f42017-03-10 18:42:11 +08001396#ifdef CONVERGED_P2P_ENABLE
1397static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1398 struct ieee80211_channel *chan, bool offchan,
1399 unsigned int wait,
1400 const u8 *buf, size_t len, bool no_cck,
1401 bool dont_wait_for_ack, u64 *cookie)
1402{
1403 QDF_STATUS status;
1404 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001405 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Wu Gao9a704f42017-03-10 18:42:11 +08001406
1407 ENTER();
1408
1409 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1410 hdd_err("Command not allowed in FTM mode");
1411 return -EINVAL;
1412 }
1413
1414 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1415 hdd_err("invalid session id: %d", pAdapter->sessionId);
1416 return -EINVAL;
1417 }
1418
1419 status = wlan_cfg80211_mgmt_tx(pAdapter->hdd_vdev, chan,
1420 offchan, wait, buf, len, no_cck,
1421 dont_wait_for_ack, cookie);
1422 hdd_info("mgmt tx, status:%d", status);
1423
1424 return 0;
1425}
1426#else
Jeff Johnsond2291042016-10-05 16:18:50 -07001427static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1428 struct ieee80211_channel *chan, bool offchan,
1429 unsigned int wait,
1430 const u8 *buf, size_t len, bool no_cck,
1431 bool dont_wait_for_ack, u64 *cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001433 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001434 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001435 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
1436 hdd_remain_on_chan_ctx_t *pRemainChanCtx;
Jeff Johnson18767622017-08-28 11:46:50 -07001437 struct hdd_context *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001438 uint16_t extendedWait = 0;
1439 uint8_t type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]);
1440 uint8_t subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
Srinivas Girigowda85218af2017-03-25 13:21:40 -07001441 enum action_frm_type actionFrmType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442 bool noack = 0;
1443 int status;
1444 unsigned long rc;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001445 struct hdd_adapter *goAdapter;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 uint16_t current_freq;
Naveen Rawat5b34c952016-02-05 17:08:25 -08001447 uint8_t home_ch = 0;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301448 ENTER();
1449
Anurag Chouhan6d760662016-02-20 16:05:43 +05301450 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001451 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452 return -EINVAL;
1453 }
1454
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05301455 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1456 hdd_err("invalid session id: %d", pAdapter->sessionId);
1457 return -EINVAL;
1458 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301459 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001460 TRACE_CODE_HDD_ACTION, pAdapter->sessionId,
1461 pAdapter->device_mode));
1462 status = wlan_hdd_validate_context(pHddCtx);
1463
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301464 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001465 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001466
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001467 hdd_debug("Device_mode %s(%d) type: %d, wait: %d, offchan: %d, category: %d, actionId: %d",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001468 hdd_device_mode_to_string(pAdapter->device_mode),
1469 pAdapter->device_mode, type, wait, offchan,
1470 buf[WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET +
1471 WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET],
1472 buf[WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET +
1473 WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474
1475#ifdef WLAN_FEATURE_P2P_DEBUG
1476 if ((type == SIR_MAC_MGMT_FRAME) &&
1477 (subType == SIR_MAC_MGMT_ACTION) &&
1478 wlan_hdd_is_type_p2p_action(&buf
1479 [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])) {
1480 actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1481 if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001482 hdd_debug("[P2P] unknown[%d] ---> OTA to " MAC_ADDRESS_STR,
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001483 actionFrmType,
1484 MAC_ADDR_ARRAY(&buf
1485 [WLAN_HDD_80211_FRM_DA_OFFSET]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001486 } else {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001487 hdd_debug("[P2P] %s ---> OTA to "
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001488 MAC_ADDRESS_STR,
1489 p2p_action_frame_type[actionFrmType],
1490 MAC_ADDR_ARRAY(&buf
1491 [WLAN_HDD_80211_FRM_DA_OFFSET]));
1492 if ((actionFrmType == WLAN_HDD_PROV_DIS_REQ)
1493 && (global_p2p_connection_status == P2P_NOT_ACTIVE)) {
1494 global_p2p_connection_status = P2P_GO_NEG_PROCESS;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001495 hdd_debug("[P2P State]Inactive state to GO negotiation progress state");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496 } else if ((actionFrmType == WLAN_HDD_GO_NEG_CNF) &&
1497 (global_p2p_connection_status ==
1498 P2P_GO_NEG_PROCESS)) {
1499 global_p2p_connection_status =
1500 P2P_GO_NEG_COMPLETED;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001501 hdd_debug("[P2P State]GO nego progress to GO nego completed state");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001502 }
1503 }
1504 }
1505#endif
1506
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001507 noack = dont_wait_for_ack;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508
1509 /* If the wait is coming as 0 with off channel set */
1510 /* then set the wait to 200 ms */
1511 if (offchan && !wait) {
1512 wait = ACTION_FRAME_DEFAULT_WAIT;
1513 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1514 if (cfgState->remain_on_chan_ctx) {
Deepthi Gowri6acee342016-10-28 15:00:38 +05301515 uint64_t current_time =
1516 (uint64_t)qdf_mc_timer_get_system_time();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001517 int remaining_roc_time =
1518 ((int) cfgState->remain_on_chan_ctx->duration -
1519 (current_time - pAdapter->start_roc_ts));
1520
1521 if (remaining_roc_time > ACTION_FRAME_DEFAULT_WAIT)
1522 wait = remaining_roc_time;
1523 }
1524 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1525 }
1526
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001527 if ((QDF_STA_MODE == pAdapter->device_mode) &&
Jeff Johnson3aaa4922017-01-12 08:46:09 -08001528 (type == SIR_MAC_MGMT_FRAME &&
1529 subType == SIR_MAC_MGMT_PROBE_RSP)) {
1530 /*
1531 * Drop Probe response received
1532 * from supplicant in sta mode
1533 */
1534 goto err_rem_channel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001535 }
1536
Jeff Johnson3aaa4922017-01-12 08:46:09 -08001537 /*
1538 * Call sme API to send out a action frame.
1539 * OR can we send it directly through data path??
1540 * After tx completion send tx status back.
1541 */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001542 if ((QDF_SAP_MODE == pAdapter->device_mode) ||
1543 (QDF_P2P_GO_MODE == pAdapter->device_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001544 ) {
1545 if (type == SIR_MAC_MGMT_FRAME) {
1546 if (subType == SIR_MAC_MGMT_PROBE_RSP) {
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001547 /* Drop Probe response recieved from supplicant,
1548 * as for GO and SAP PE itself
1549 * sends probe response
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001550 */
1551 goto err_rem_channel;
1552 } else if ((subType == SIR_MAC_MGMT_DISASSOC) ||
1553 (subType == SIR_MAC_MGMT_DEAUTH)) {
Jeff Johnson3aaa4922017-01-12 08:46:09 -08001554 /*
1555 * During EAP failure or P2P Group
1556 * Remove supplicant is sending
1557 * del_station command to driver. From
1558 * del_station function, Driver will
1559 * send deauth frame to p2p client. No
1560 * need to send disassoc frame from
1561 * here. so Drop the frame here and
1562 * send tx indication back to
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001563 * supplicant.
1564 */
1565 uint8_t dstMac[ETH_ALEN] = { 0 };
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001566
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001567 memcpy(&dstMac,
1568 &buf[WLAN_HDD_80211_FRM_DA_OFFSET],
1569 ETH_ALEN);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001570 hdd_debug("Deauth/Disassoc received for STA:"
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001571 MAC_ADDRESS_STR,
1572 MAC_ADDR_ARRAY(dstMac));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001573 goto err_rem_channel;
1574 }
1575 }
1576 }
1577
1578 if (NULL != cfgState->buf) {
1579 if (!noack) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001580 hdd_err("Previous P2P Action frame packet pending");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581 hdd_cleanup_actionframe(pAdapter->pHddCtx, pAdapter);
1582 } else {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001583 hdd_err("Pending Action frame packet return EBUSY");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001584 return -EBUSY;
1585 }
1586 }
1587
1588 if (subType == SIR_MAC_MGMT_ACTION) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001589 hdd_debug("Action frame tx request : %s",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001590 hdd_get_action_string(buf
1591 [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET]));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001592 }
1593
Vidyullatha Kanchanapally87b224f2016-05-24 15:49:44 +05301594 if ((pAdapter->device_mode == QDF_SAP_MODE) &&
1595 (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))) {
Naveen Rawat5b34c952016-02-05 17:08:25 -08001596 home_ch = pAdapter->sessionCtx.ap.operatingChannel;
Vidyullatha Kanchanapally87b224f2016-05-24 15:49:44 +05301597 } else if ((pAdapter->device_mode == QDF_STA_MODE) &&
1598 (pAdapter->sessionCtx.station.conn_info.connState ==
1599 eConnectionState_Associated)) {
Naveen Rawat5b34c952016-02-05 17:08:25 -08001600 home_ch =
1601 pAdapter->sessionCtx.station.conn_info.operationChannel;
1602 } else {
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001603 goAdapter = hdd_get_adapter(pAdapter->pHddCtx, QDF_P2P_GO_MODE);
Vidyullatha Kanchanapally87b224f2016-05-24 15:49:44 +05301604 if (goAdapter &&
1605 (test_bit(SOFTAP_BSS_STARTED, &goAdapter->event_flags)))
Naveen Rawat5b34c952016-02-05 17:08:25 -08001606 home_ch = goAdapter->sessionCtx.ap.operatingChannel;
1607 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608
Archana Ramachandrandc7f2c92016-06-27 11:44:13 -07001609 if (chan &&
1610 (ieee80211_frequency_to_channel(chan->center_freq) ==
1611 home_ch)) {
Naveen Rawat5b34c952016-02-05 17:08:25 -08001612 /* if adapter is already on requested ch, no need for ROC */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613 wait = 0;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001614 hdd_debug("Adapter already on requested ch. No ROC needed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615 goto send_frame;
1616 }
1617
Archana Ramachandrandc7f2c92016-06-27 11:44:13 -07001618 if (offchan && wait && chan) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 int status;
Srinivas Girigowda85218af2017-03-25 13:21:40 -07001620 enum rem_on_channel_request_type req_type = OFF_CHANNEL_ACTION_TX;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621 /* In case of P2P Client mode if we are already */
1622 /* on the same channel then send the frame directly */
1623
1624 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1625 pRemainChanCtx = cfgState->remain_on_chan_ctx;
1626 if ((type == SIR_MAC_MGMT_FRAME) &&
1627 (subType == SIR_MAC_MGMT_ACTION) &&
1628 hdd_p2p_is_action_type_rsp(&buf
1629 [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])
1630 && cfgState->remain_on_chan_ctx
1631 && cfgState->current_freq == chan->center_freq) {
Anurag Chouhan210db072016-02-22 18:42:15 +05301632 if (QDF_TIMER_STATE_RUNNING ==
1633 qdf_mc_timer_get_current_state(&cfgState->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 remain_on_chan_ctx->
1635 hdd_remain_on_chan_timer)) {
Deepthi Gowri1f835212016-08-30 19:37:05 +05301636
1637 /* In the latest wpa_supplicant, the wait time
1638 * for go negotiation response is set to 100ms,
1639 * due to which, there could be a possibility
1640 * that, if the go negotaition confirmation
1641 * frame is not received within 100 msec, ROC
1642 * would be timeout and resulting in connection
1643 * failures as the device will not be on the
1644 * listen channel anymore to receive the conf
1645 * frame. Also wpa_supplicant has set the wait
1646 * to 50msec for go negotiation confirmation,
1647 * invitation response and prov discovery rsp
1648 * frames. So increase the wait time for all
1649 * these frames.
1650 */
1651 actionFrmType = buf
1652 [WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
1653 if (actionFrmType == WLAN_HDD_GO_NEG_RESP ||
1654 actionFrmType == WLAN_HDD_PROV_DIS_RESP)
1655 wait = wait + ACTION_FRAME_RSP_WAIT;
1656 else if (actionFrmType ==
1657 WLAN_HDD_GO_NEG_CNF ||
1658 actionFrmType ==
1659 WLAN_HDD_INVITATION_RESP)
1660 wait = wait + ACTION_FRAME_ACK_WAIT;
1661
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001662 hdd_debug("Extending the wait time %d for actionFrmType=%d",
Jeff Johnson1a92f8c2016-12-05 13:03:58 -08001663 wait, actionFrmType);
Deepthi Gowri1f835212016-08-30 19:37:05 +05301664
Deepthi Gowria0b85532016-10-13 16:14:17 +05301665 if (qdf_mc_timer_stop(&cfgState->
1666 remain_on_chan_ctx->
1667 hdd_remain_on_chan_timer)
1668 != QDF_STATUS_SUCCESS)
1669 hdd_err("Failed to stop hdd_remain_on_chan_timer");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670 status =
Anurag Chouhan210db072016-02-22 18:42:15 +05301671 qdf_mc_timer_start(&cfgState->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 remain_on_chan_ctx->
1673 hdd_remain_on_chan_timer,
1674 wait);
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001675 if (status != QDF_STATUS_SUCCESS)
1676 hdd_warn("Remain on Channel timer start failed");
1677
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001678 mutex_unlock(&cfgState->
1679 remain_on_chan_ctx_lock);
1680 goto send_frame;
1681 } else {
1682 if (pRemainChanCtx->
1683 hdd_remain_on_chan_cancel_in_progress ==
1684 true) {
1685 mutex_unlock(&cfgState->
1686 remain_on_chan_ctx_lock);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001687 hdd_debug("action frame tx: waiting for completion of ROC ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688
1689 rc = wait_for_completion_timeout
1690 (&pAdapter->cancel_rem_on_chan_var,
1691 msecs_to_jiffies
1692 (WAIT_CANCEL_REM_CHAN));
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001693 if (!rc)
1694 hdd_warn("wait on cancel_rem_on_chan_var timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 } else
1696 mutex_unlock(&cfgState->
1697 remain_on_chan_ctx_lock);
1698 }
1699 } else
1700 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1701
Deepthi Gowri0a151cb2016-10-13 14:31:41 +05301702 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
Nitesh Shaha438c182017-02-13 18:02:25 +05301703 pRemainChanCtx = cfgState->remain_on_chan_ctx;
1704
1705 /* At this point if remain_on_chan_ctx exists but timer not
1706 * running means that roc workqueue requested a new RoC and it
Nitesh Shah00231512017-03-03 21:05:22 +05301707 * is in progress. So wait for Ready on channel indication
1708 */
Nitesh Shaha438c182017-02-13 18:02:25 +05301709 if ((pRemainChanCtx) &&
1710 (QDF_TIMER_STATE_RUNNING !=
1711 qdf_mc_timer_get_current_state(
1712 &pRemainChanCtx->hdd_remain_on_chan_timer))) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001713 hdd_debug("remain_on_chan_ctx exists but RoC timer not running. wait for ready on channel");
Nitesh Shaha438c182017-02-13 18:02:25 +05301714 rc = wait_for_completion_timeout(&pAdapter->
1715 rem_on_chan_ready_event,
1716 msecs_to_jiffies
1717 (WAIT_REM_CHAN_READY));
1718 if (!rc)
1719 hdd_err("timeout waiting for remain on channel ready indication");
1720 }
1721
1722 if ((pRemainChanCtx != NULL) &&
1723 (cfgState->current_freq == chan->center_freq)) {
Deepthi Gowri0a151cb2016-10-13 14:31:41 +05301724 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001725 hdd_debug("action frame: extending the wait time");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001726 extendedWait = (uint16_t) wait;
1727 goto send_frame;
1728 }
1729
Deepthi Gowri0a151cb2016-10-13 14:31:41 +05301730 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731 INIT_COMPLETION(pAdapter->offchannel_tx_event);
1732
1733 status = wlan_hdd_request_remain_on_channel(wiphy, dev, chan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734 wait, cookie,
1735 req_type);
1736 if (0 != status) {
1737 if ((-EBUSY == status) &&
1738 (cfgState->current_freq == chan->center_freq)) {
1739 goto send_frame;
1740 }
1741 goto err_rem_channel;
1742 }
1743 /* This will extend timer in LIM when sending Any action frame
1744 * It will cover remain on channel timer till next action frame
1745 * in rx direction.
1746 */
1747 extendedWait = (uint16_t) wait;
1748 /* Wait for driver to be ready on the requested channel */
1749 rc = wait_for_completion_timeout(&pAdapter->offchannel_tx_event,
1750 msecs_to_jiffies
1751 (WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX));
1752 if (!rc) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001753 hdd_err("wait on offchannel_tx_event timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001754 goto err_rem_channel;
1755 }
1756 } else if (offchan) {
Jeff Johnson3aaa4922017-01-12 08:46:09 -08001757 /*
1758 * Check before sending action frame
1759 * whether we already remain on channel
1760 */
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001761 if (NULL == cfgState->remain_on_chan_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001762 goto err_rem_channel;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001763send_frame:
1764
1765 if (!noack) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301766 cfgState->buf = qdf_mem_malloc(len); /* buf; */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767 if (cfgState->buf == NULL)
1768 return -ENOMEM;
1769
1770 cfgState->len = len;
1771
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301772 qdf_mem_copy(cfgState->buf, buf, len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001773
1774 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
1775
1776 if (cfgState->remain_on_chan_ctx) {
1777 cfgState->action_cookie =
1778 cfgState->remain_on_chan_ctx->cookie;
1779 *cookie = cfgState->action_cookie;
1780 } else {
1781 *cookie = (uintptr_t) cfgState->buf;
1782 cfgState->action_cookie = *cookie;
1783 }
1784
1785 mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
1786 }
1787
1788 /*
1789 * Firmware needs channel information for action frames
1790 * which are not sent on the current operating channel of VDEV
1791 */
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001792 if ((QDF_P2P_DEVICE_MODE == pAdapter->device_mode) ||
1793 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
1794 (QDF_P2P_GO_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001795 if (chan && (chan->center_freq != 0))
1796 current_freq = chan->center_freq;
1797 else
1798 current_freq = cfgState->current_freq;
1799 } else {
1800 current_freq = 0;
1801 }
1802
Jeff Johnson19caeb12015-12-10 12:29:44 -08001803 INIT_COMPLETION(pAdapter->tx_action_cnf_event);
1804
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001805 if ((QDF_STA_MODE == pAdapter->device_mode) ||
1806 (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
Krishna Kumaar Natarajan9c323a82016-09-23 09:27:11 -07001807 (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001808 uint8_t sessionId = pAdapter->sessionId;
1809
1810 if ((type == SIR_MAC_MGMT_FRAME) &&
1811 (subType == SIR_MAC_MGMT_ACTION) &&
Krishna Kumaar Natarajan9c323a82016-09-23 09:27:11 -07001812 wlan_hdd_is_type_p2p_action(&buf
1813 [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001814 actionFrmType =
1815 buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001816 hdd_debug("Tx Action Frame %u", actionFrmType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 if (actionFrmType == WLAN_HDD_PROV_DIS_REQ) {
1818 cfgState->actionFrmState =
1819 HDD_PD_REQ_ACK_PENDING;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001820 hdd_debug("HDD_PD_REQ_ACK_PENDING");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001821 } else if (actionFrmType == WLAN_HDD_GO_NEG_REQ) {
1822 cfgState->actionFrmState =
1823 HDD_GO_NEG_REQ_ACK_PENDING;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001824 hdd_debug("HDD_GO_NEG_REQ_ACK_PENDING");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 }
1826 }
1827
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301828 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001829 sme_send_action(WLAN_HDD_GET_HAL_CTX(pAdapter),
1830 sessionId, buf, len, extendedWait, noack,
1831 current_freq)) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001832 hdd_err("sme_send_action returned fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833 goto err;
1834 }
Krunal Sonifb84cbd2016-03-10 13:09:07 -08001835 } else if (QDF_SAP_MODE == pAdapter->device_mode ||
1836 QDF_P2P_GO_MODE == pAdapter->device_mode) {
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301837 if (QDF_STATUS_SUCCESS !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001838 wlansap_send_action(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001839 buf, len, 0, current_freq)) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07001840 hdd_err("wlansap_send_action returned fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841 goto err;
1842 }
1843 }
1844
1845 return 0;
1846err:
1847 if (!noack) {
1848 hdd_send_action_cnf(pAdapter, false);
1849 }
1850 return 0;
1851err_rem_channel:
1852 *cookie = (uintptr_t) cfgState;
1853 cfg80211_mgmt_tx_status(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001854 pAdapter->dev->ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855 *cookie, buf, len, false, GFP_KERNEL);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301856 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857 return 0;
1858}
Wu Gao9a704f42017-03-10 18:42:11 +08001859#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001860
1861#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1862int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1863 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
Amar Singhal01098f72015-10-08 11:55:32 -07001864#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001865int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1866 struct ieee80211_channel *chan, bool offchan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001867 unsigned int wait,
1868 const u8 *buf, size_t len, bool no_cck,
1869 bool dont_wait_for_ack, u64 *cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870#endif /* LINUX_VERSION_CODE */
1871{
1872 int ret;
1873
1874 cds_ssr_protect(__func__);
1875
1876#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1877 ret = __wlan_hdd_mgmt_tx(wiphy, wdev, params->chan, params->offchan,
1878 params->wait, params->buf, params->len,
1879 params->no_cck, params->dont_wait_for_ack,
1880 cookie);
Amar Singhal01098f72015-10-08 11:55:32 -07001881#else
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001882 ret = __wlan_hdd_mgmt_tx(wiphy, wdev, chan, offchan,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883 wait, buf, len, no_cck,
1884 dont_wait_for_ack, cookie);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001885#endif /* LINUX_VERSION_CODE */
1886 cds_ssr_unprotect(__func__);
1887
1888 return ret;
1889}
1890
Wu Gao9a704f42017-03-10 18:42:11 +08001891#ifdef CONVERGED_P2P_ENABLE
1892static int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
1893 struct wireless_dev *wdev,
1894 u64 cookie)
1895{
1896 QDF_STATUS status;
1897 struct net_device *dev = wdev->netdev;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001898 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Wu Gao9a704f42017-03-10 18:42:11 +08001899
1900 ENTER();
1901
1902 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1903 hdd_err("Command not allowed in FTM mode");
1904 return -EINVAL;
1905 }
1906
1907 if (wlan_hdd_validate_session_id(pAdapter->sessionId)) {
1908 hdd_err("invalid session id: %d", pAdapter->sessionId);
1909 return -EINVAL;
1910 }
1911
1912 status = wlan_cfg80211_mgmt_tx_cancel(pAdapter->hdd_vdev,
1913 cookie);
1914 hdd_info("cancel mgmt tx, status:%d", status);
1915
1916 return 0;
1917}
1918#else
Jeff Johnsond2291042016-10-05 16:18:50 -07001919static int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
1920 struct wireless_dev *wdev,
1921 u64 cookie)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001922{
1923 return wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, wdev, cookie);
1924}
Wu Gao9a704f42017-03-10 18:42:11 +08001925#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001926
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
1928 struct wireless_dev *wdev, u64 cookie)
1929{
1930 int ret;
1931
1932 cds_ssr_protect(__func__);
1933 ret = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, cookie);
1934 cds_ssr_unprotect(__func__);
1935
1936 return ret;
1937}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001938
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001939void hdd_send_action_cnf(struct hdd_adapter *pAdapter, bool actionSendSuccess)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001940{
1941 hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
1942
1943 cfgState->actionFrmState = HDD_IDLE;
1944
Srinivas Girigowdaef327802017-03-24 23:13:20 -07001945 if (NULL == cfgState->buf)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001946 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001947
Gowri, Deepthi62da33e2016-09-02 16:01:26 +05301948 if (cfgState->is_go_neg_ack_received) {
1949
1950 cfgState->is_go_neg_ack_received = 0;
1951 /* Sometimes its possible that host may receive the ack for GO
1952 * negotiation req after sending go negotaition confirmation,
1953 * in such case drop the ack received for the go negotiation
1954 * request, so that supplicant waits for the confirmation ack
1955 * from firmware.
1956 */
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001957 hdd_debug("Drop the pending ack received in cfgState->actionFrmState %d",
Gowri, Deepthi62da33e2016-09-02 16:01:26 +05301958 cfgState->actionFrmState);
1959 return;
1960 }
1961
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08001962 hdd_debug("Send Action cnf, actionSendSuccess %d",
Gowri, Deepthi62da33e2016-09-02 16:01:26 +05301963 actionSendSuccess);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001964 /*
1965 * buf is the same pointer it passed us to send. Since we are sending
1966 * it through control path, we use different buffers.
1967 * In case of mac80211, they just push it to the skb and pass the same
1968 * data while sending tx ack status.
Jeff Johnson3aaa4922017-01-12 08:46:09 -08001969 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 cfg80211_mgmt_tx_status(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001971 pAdapter->dev->ieee80211_ptr,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001972 cfgState->action_cookie,
1973 cfgState->buf, cfgState->len,
1974 actionSendSuccess, GFP_KERNEL);
1975
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301976 qdf_mem_free(cfgState->buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001977 cfgState->buf = NULL;
1978
1979 complete(&pAdapter->tx_action_cnf_event);
1980}
1981
1982/**
Selvaraj, Sridhar4577a9b2016-09-04 15:17:07 +05301983 * hdd_send_action_cnf_cb - action confirmation callback
1984 * @session_id: SME session ID
1985 * @tx_completed: ack status
1986 *
1987 * This function invokes hdd_sendActionCnf to update ack status to
1988 * supplicant.
1989 */
1990void hdd_send_action_cnf_cb(uint32_t session_id, bool tx_completed)
1991{
Jeff Johnson18767622017-08-28 11:46:50 -07001992 struct hdd_context *hdd_ctx;
Jeff Johnsonfbb54522017-08-29 14:25:27 -07001993 struct hdd_adapter *adapter;
Selvaraj, Sridhar4577a9b2016-09-04 15:17:07 +05301994
1995 ENTER();
1996
1997 /* Get the HDD context.*/
1998 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1999 if (0 != wlan_hdd_validate_context(hdd_ctx))
2000 return;
2001
2002 adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, session_id);
2003 if (NULL == adapter) {
Jeff Johnson1a92f8c2016-12-05 13:03:58 -08002004 hdd_err("adapter not found");
Selvaraj, Sridhar4577a9b2016-09-04 15:17:07 +05302005 return;
2006 }
2007
2008 if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) {
Jeff Johnson1a92f8c2016-12-05 13:03:58 -08002009 hdd_err("adapter has invalid magic");
Selvaraj, Sridhar4577a9b2016-09-04 15:17:07 +05302010 return;
2011 }
2012
2013 hdd_send_action_cnf(adapter, tx_completed);
2014}
2015
2016/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017 * hdd_set_p2p_noa
2018 *
2019 ***FUNCTION:
2020 * This function is called from hdd_hostapd_ioctl function when Driver
2021 * get P2P_SET_NOA comand from wpa_supplicant using private ioctl
2022 *
2023 ***LOGIC:
2024 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
2025 *
2026 ***ASSUMPTIONS:
2027 *
2028 *
2029 ***NOTE:
2030 *
2031 * @param dev Pointer to net device structure
2032 * @param command Pointer to command
2033 *
2034 * @return Status
2035 */
2036
2037int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command)
2038{
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002039 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040 tP2pPsConfig NoA;
Manishekar Chandrasekaran371e5af2016-06-30 23:17:29 +05302041 int count, duration, interval;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002042 char *param;
2043 int ret;
2044
2045 param = strnchr(command, strlen(command), ' ');
2046 if (param == NULL) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002047 hdd_err("strnchr failed to find delimeter");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 return -EINVAL;
2049 }
2050 param++;
Manishekar Chandrasekaran371e5af2016-06-30 23:17:29 +05302051 ret = sscanf(param, "%d %d %d", &count, &interval, &duration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002052 if (ret != 3) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002053 hdd_err("P2P_SET GO NoA: fail to read params, ret=%d",
2054 ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 return -EINVAL;
2056 }
Archana Ramachandran1e6b9262016-09-30 15:15:10 -07002057 if (count < 0 || interval < 0 || duration < 0 ||
2058 interval > MAX_MUS_VAL || duration > MAX_MUS_VAL) {
2059 hdd_err("Invalid NOA parameters");
2060 return -EINVAL;
2061 }
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002062 hdd_debug("P2P_SET GO NoA: count=%d interval=%d duration=%d",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002063 count, interval, duration);
Manishekar Chandrasekaran371e5af2016-06-30 23:17:29 +05302064 duration = MS_TO_TU_MUS(duration);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002065 /* PS Selection
2066 * Periodic NoA (2)
2067 * Single NOA (4)
2068 */
2069 NoA.opp_ps = 0;
2070 NoA.ctWindow = 0;
2071 if (count == 1) {
2072 NoA.duration = 0;
2073 NoA.single_noa_duration = duration;
2074 NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA;
2075 } else {
2076 NoA.duration = duration;
2077 NoA.single_noa_duration = 0;
2078 NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA;
2079 }
Manishekar Chandrasekaran371e5af2016-06-30 23:17:29 +05302080 NoA.interval = MS_TO_TU_MUS(interval);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002081 NoA.count = count;
2082 NoA.sessionid = pAdapter->sessionId;
2083
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002084 hdd_debug("P2P_PS_ATTR:oppPS %d ctWindow %d duration %d "
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002085 "interval %d count %d single noa duration %d "
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002086 "PsSelection %x", NoA.opp_ps,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002087 NoA.ctWindow, NoA.duration, NoA.interval,
2088 NoA.count, NoA.single_noa_duration, NoA.psSelection);
2089
Wu Gao9a704f42017-03-10 18:42:11 +08002090 return wlan_hdd_set_power_save(pAdapter, &NoA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091}
2092
2093/**
2094 * hdd_set_p2p_opps
2095 *
2096 ***FUNCTION:
2097 * This function is called from hdd_hostapd_ioctl function when Driver
2098 * get P2P_SET_PS comand from wpa_supplicant using private ioctl
2099 *
2100 ***LOGIC:
2101 * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer
2102 *
2103 ***ASSUMPTIONS:
2104 *
2105 *
2106 ***NOTE:
2107 *
2108 * @param dev Pointer to net device structure
2109 * @param command Pointer to command
2110 *
2111 * @return Status
2112 */
2113
2114int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command)
2115{
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002116 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302117 tP2pPsConfig noa;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002118 char *param;
2119 int legacy_ps, opp_ps, ctwindow;
2120 int ret;
2121
2122 param = strnchr(command, strlen(command), ' ');
2123 if (param == NULL) {
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302124 hdd_err("strnchr failed to find delimiter");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002125 return -EINVAL;
2126 }
2127 param++;
2128 ret = sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow);
2129 if (ret != 3) {
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302130 hdd_err("P2P_SET GO PS: fail to read params, ret=%d", ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002131 return -EINVAL;
2132 }
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302133
2134 if ((opp_ps != -1) && (opp_ps != 0) && (opp_ps != 1)) {
2135 hdd_err("Invalid opp_ps value:%d", opp_ps);
2136 return -EINVAL;
2137 }
2138
2139 /* P2P spec: 3.3.2 Power Management and discovery:
2140 * CTWindow should be at least 10 TU.
2141 * P2P spec: Table 27 - CTWindow and OppPS Parameters field format:
2142 * CTWindow and OppPS Parameters together is 8 bits.
2143 * CTWindow uses 7 bits (0-6, Bit 7 is for OppPS)
2144 * 0 indicates that there shall be no CTWindow
2145 */
2146 if ((ctwindow != -1) && (ctwindow != 0) &&
2147 (!((ctwindow >= 10) && (ctwindow <= 127)))) {
2148 hdd_err("Invalid CT window value:%d", ctwindow);
2149 return -EINVAL;
2150 }
2151
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002152 hdd_debug("P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d",
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302153 legacy_ps, opp_ps, ctwindow);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002154
2155 /* PS Selection
2156 * Opportunistic Power Save (1)
2157 */
2158
Srinivas Girigowdaef327802017-03-24 23:13:20 -07002159 /* From wpa_cli user need to use separate command to set ctWindow and
2160 * Opps when user want to set ctWindow during that time other parameters
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161 * values are coming from wpa_supplicant as -1.
2162 * Example : User want to set ctWindow with 30 then wpa_cli command :
2163 * P2P_SET ctwindow 30
2164 * Command Received at hdd_hostapd_ioctl is as below:
2165 * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30)
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302166 *
2167 * e.g., 1: P2P_SET_PS 1 1 30
2168 * Driver sets the Opps and CTwindow as 30 and send it to FW.
2169 * e.g., 2: P2P_SET_PS 1 -1 15
2170 * Driver caches the CTwindow value but not send the command to FW.
2171 * e.g., 3: P2P_SET_PS 1 1 -1
2172 * Driver sends the command to FW with Opps enabled and CT window as
2173 * 15 (last cached CTWindow value).
2174 * (or) : P2P_SET_PS 1 1 20
2175 * Driver sends the command to FW with opps enabled and CT window
2176 * as 20.
2177 *
2178 * legacy_ps param remains unused until required in the future.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002179 */
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302180 if (ctwindow != -1)
2181 adapter->ctw = ctwindow;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002182
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302183 /* Send command to FW when OppPS is either enabled(1)/disbaled(0) */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002184 if (opp_ps != -1) {
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302185 adapter->ops = opp_ps;
2186 noa.opp_ps = adapter->ops;
2187 noa.ctWindow = adapter->ctw;
2188 noa.duration = 0;
2189 noa.single_noa_duration = 0;
2190 noa.interval = 0;
2191 noa.count = 0;
2192 noa.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC;
2193 noa.sessionid = adapter->sessionId;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002194
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302195 hdd_debug("P2P_PS_ATTR: oppPS %d ctWindow %d duration %d interval %d count %d single noa duration %d PsSelection %x",
2196 noa.opp_ps, noa.ctWindow,
2197 noa.duration, noa.interval, noa.count,
2198 noa.single_noa_duration,
2199 noa.psSelection);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002200
Wu Gao9a704f42017-03-10 18:42:11 +08002201 wlan_hdd_set_power_save(adapter, &noa);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202 }
Manishekar Chandrasekaran0575bee2016-07-11 15:25:47 +05302203
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002204 return 0;
2205}
2206
2207int hdd_set_p2p_ps(struct net_device *dev, void *msgData)
2208{
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002209 struct hdd_adapter *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002210 tP2pPsConfig NoA;
Srinivas Girigowda5d5fdc52017-03-24 22:30:57 -07002211 struct p2p_app_set_ps *pappNoA = (struct p2p_app_set_ps *) msgData;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002212
2213 NoA.opp_ps = pappNoA->opp_ps;
2214 NoA.ctWindow = pappNoA->ctWindow;
2215 NoA.duration = pappNoA->duration;
2216 NoA.interval = pappNoA->interval;
2217 NoA.count = pappNoA->count;
2218 NoA.single_noa_duration = pappNoA->single_noa_duration;
2219 NoA.psSelection = pappNoA->psSelection;
2220 NoA.sessionid = pAdapter->sessionId;
2221
Wu Gao9a704f42017-03-10 18:42:11 +08002222 return wlan_hdd_set_power_save(pAdapter, &NoA);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002223}
2224
2225static uint8_t wlan_hdd_get_session_type(enum nl80211_iftype type)
2226{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002227 switch (type) {
2228 case NL80211_IFTYPE_AP:
Dustin Brown0a1da142016-09-13 13:31:52 -07002229 return QDF_SAP_MODE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002230 case NL80211_IFTYPE_P2P_GO:
Dustin Brown0a1da142016-09-13 13:31:52 -07002231 return QDF_P2P_GO_MODE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002232 case NL80211_IFTYPE_P2P_CLIENT:
Dustin Brown0a1da142016-09-13 13:31:52 -07002233 return QDF_P2P_CLIENT_MODE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002234 case NL80211_IFTYPE_STATION:
Dustin Brown0a1da142016-09-13 13:31:52 -07002235 return QDF_STA_MODE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002236 default:
Dustin Brown0a1da142016-09-13 13:31:52 -07002237 return QDF_STA_MODE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002238 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002239}
2240
Ryan Hsu07495ea2016-01-21 15:25:39 -08002241/**
2242 * __wlan_hdd_add_virtual_intf() - Add virtual interface
2243 * @wiphy: wiphy pointer
2244 * @name: User-visible name of the interface
2245 * @name_assign_type: the name of assign type of the netdev
2246 * @nl80211_iftype: (virtual) interface types
2247 * @flags: moniter configuraiton flags (not used)
2248 * @vif_params: virtual interface parameters (not used)
2249 *
Arun Khandavallic67110c2016-08-18 16:18:51 +05302250 * Return: the pointer of wireless dev, otherwise ERR_PTR.
Ryan Hsu07495ea2016-01-21 15:25:39 -08002251 */
Jeff Johnsond2291042016-10-05 16:18:50 -07002252static
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002253struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
2254 const char *name,
Ryan Hsu07495ea2016-01-21 15:25:39 -08002255 unsigned char name_assign_type,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002256 enum nl80211_iftype type,
2257 u32 *flags,
2258 struct vif_params *params)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002259{
Jeff Johnson18767622017-08-28 11:46:50 -07002260 struct hdd_context *pHddCtx = (struct hdd_context *) wiphy_priv(wiphy);
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002261 struct hdd_adapter *pAdapter = NULL;
Jeff Johnson37588942017-08-15 16:11:41 -07002262 struct hdd_scan_info *scan_info = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002263 int ret;
Peng Xu45486ea2015-11-12 16:37:44 -08002264 uint8_t session_type;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265
2266 ENTER();
2267
Anurag Chouhan6d760662016-02-20 16:05:43 +05302268 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002269 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002270 return ERR_PTR(-EINVAL);
2271 }
2272
2273 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302274 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002275 return ERR_PTR(ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002276
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302277 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002278 TRACE_CODE_HDD_ADD_VIRTUAL_INTF, NO_SESSION, type));
2279 /*
Krunal Sonifb84cbd2016-03-10 13:09:07 -08002280 * Allow addition multiple interfaces for QDF_P2P_GO_MODE,
2281 * QDF_SAP_MODE, QDF_P2P_CLIENT_MODE and QDF_STA_MODE
Peng Xu45486ea2015-11-12 16:37:44 -08002282 * session type.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002283 */
Peng Xu45486ea2015-11-12 16:37:44 -08002284 session_type = wlan_hdd_get_session_type(type);
Dustin Brown0a1da142016-09-13 13:31:52 -07002285 if (hdd_get_adapter(pHddCtx, session_type) != NULL
Krunal Sonifb84cbd2016-03-10 13:09:07 -08002286 && QDF_SAP_MODE != session_type
2287 && QDF_P2P_GO_MODE != session_type
Krunal Sonifb84cbd2016-03-10 13:09:07 -08002288 && QDF_P2P_CLIENT_MODE != session_type
2289 && QDF_STA_MODE != session_type) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002290 hdd_err("Interface type %d already exists. Two interfaces of same type are not supported currently.",
2291 type);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002292 return ERR_PTR(-EINVAL);
2293 }
2294
Krunal Sonifb84cbd2016-03-10 13:09:07 -08002295 pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE);
Hanumanth Reddy Pothulad9491f42016-10-24 19:08:38 +05302296 if ((pAdapter != NULL) &&
2297 !(wlan_hdd_validate_session_id(pAdapter->sessionId))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002298 scan_info = &pAdapter->scan_info;
2299 if (scan_info->mScanPending) {
Abhishek Singh69ccb512017-04-25 11:58:16 +05302300 wlan_abort_scan(pHddCtx->hdd_pdev, INVAL_PDEV_ID,
2301 pAdapter->sessionId, INVALID_SCAN_ID, false);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002302 hdd_debug("Abort Scan while adding virtual interface");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002303 }
2304 }
2305
2306 pAdapter = NULL;
2307 if (pHddCtx->config->isP2pDeviceAddrAdministrated &&
2308 ((NL80211_IFTYPE_P2P_GO == type) ||
2309 (NL80211_IFTYPE_P2P_CLIENT == type))) {
2310 /*
2311 * Generate the P2P Interface Address. this address must be
2312 * different from the P2P Device Address.
2313 */
Anurag Chouhan6d760662016-02-20 16:05:43 +05302314 struct qdf_mac_addr p2pDeviceAddress =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002315 pHddCtx->p2pDeviceAddress;
2316 p2pDeviceAddress.bytes[4] ^= 0x80;
2317 pAdapter = hdd_open_adapter(pHddCtx,
Dustin Brown0a1da142016-09-13 13:31:52 -07002318 session_type,
Ryan Hsu07495ea2016-01-21 15:25:39 -08002319 name, p2pDeviceAddress.bytes,
2320 name_assign_type,
2321 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002322 } else {
Ryan Hsu07495ea2016-01-21 15:25:39 -08002323 pAdapter = hdd_open_adapter(pHddCtx,
Dustin Brown0a1da142016-09-13 13:31:52 -07002324 session_type,
Ryan Hsu07495ea2016-01-21 15:25:39 -08002325 name,
2326 wlan_hdd_get_intf_addr(pHddCtx),
2327 name_assign_type,
2328 true);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002329 }
2330
2331 if (NULL == pAdapter) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002332 hdd_err("hdd_open_adapter failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002333 return ERR_PTR(-ENOSPC);
2334 }
Nirav Shahbd36b062016-07-18 11:12:59 +05302335
Arun Khandavalli99286452016-08-22 12:13:41 +05302336 /*
2337 * Add interface can be requested from the upper layer at any time
2338 * check the statemachine for modules state and if they are closed
2339 * open the modules.
2340 */
2341 ret = hdd_wlan_start_modules(pHddCtx, pAdapter, false);
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302342 if (ret) {
2343 hdd_err("Failed to start the wlan_modules");
2344 goto close_adapter;
2345 }
Arun Khandavalli99286452016-08-22 12:13:41 +05302346
Arun Khandavalli812d0692016-09-01 19:11:56 +05302347 /*
2348 * Once the support for session creation/deletion from
2349 * hdd_hostapd_open/hdd_host_stop is in place.
2350 * The support for starting adapter from here can be removed.
2351 */
2352 if (NL80211_IFTYPE_AP == type || (NL80211_IFTYPE_P2P_GO == type)) {
Arun Khandavallic67110c2016-08-18 16:18:51 +05302353 ret = hdd_start_adapter(pAdapter);
2354 if (ret) {
2355 hdd_err("Failed to start %s", name);
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302356 goto stop_modules;
Arun Khandavallic67110c2016-08-18 16:18:51 +05302357 }
2358 }
2359
Nirav Shahbd36b062016-07-18 11:12:59 +05302360 if (pHddCtx->rps)
2361 hdd_send_rps_ind(pAdapter);
2362
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002363 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002364 return pAdapter->dev->ieee80211_ptr;
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302365
2366stop_modules:
2367 /*
2368 * Find if any iface is up. If there is not iface which is up
2369 * start the timer to close the modules
2370 */
2371 if (hdd_check_for_opened_interfaces(pHddCtx)) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002372 hdd_debug("Closing all modules from the add_virt_iface");
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302373 qdf_mc_timer_start(&pHddCtx->iface_change_timer,
Rajeev Kumar512f48a2017-03-09 14:02:51 -08002374 pHddCtx->config->iface_change_wait_time);
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302375 } else
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002376 hdd_debug("Other interfaces are still up dont close modules!");
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302377
2378close_adapter:
Ashish Kumar Dhanotiya40f528c2017-03-03 14:36:17 +05302379 hdd_close_adapter(pHddCtx, pAdapter, true);
Ashish Kumar Dhanotiya486c13a2017-03-03 12:57:56 +05302380
2381 return ERR_PTR(-EINVAL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002382}
2383
Dustin Brown9ed30a52017-08-16 13:59:38 -07002384#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
2385struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
2386 const char *name,
2387 unsigned char name_assign_type,
2388 enum nl80211_iftype type,
2389 struct vif_params *params)
2390{
2391 struct wireless_dev *wdev;
2392
2393 cds_ssr_protect(__func__);
2394 wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type,
2395 type, &params->flags, params);
2396 cds_ssr_unprotect(__func__);
2397
2398 return wdev;
2399}
2400#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || defined(WITH_BACKPORTS)
Ryan Hsu07495ea2016-01-21 15:25:39 -08002401/**
2402 * wlan_hdd_add_virtual_intf() - Add virtual interface wrapper
2403 * @wiphy: wiphy pointer
2404 * @name: User-visible name of the interface
2405 * @name_assign_type: the name of assign type of the netdev
2406 * @nl80211_iftype: (virtual) interface types
2407 * @flags: monitor mode configuration flags (not used)
2408 * @vif_params: virtual interface parameters (not used)
2409 *
Arun Khandavallic67110c2016-08-18 16:18:51 +05302410 * Return: the pointer of wireless dev, otherwise ERR_PTR.
Ryan Hsu07495ea2016-01-21 15:25:39 -08002411 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002412struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
2413 const char *name,
Ryan Hsu07495ea2016-01-21 15:25:39 -08002414 unsigned char name_assign_type,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002415 enum nl80211_iftype type,
2416 u32 *flags,
2417 struct vif_params *params)
2418{
2419 struct wireless_dev *wdev;
2420
2421 cds_ssr_protect(__func__);
Ryan Hsu07495ea2016-01-21 15:25:39 -08002422 wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type,
2423 type, flags, params);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002424 cds_ssr_unprotect(__func__);
2425 return wdev;
Ryan Hsu07495ea2016-01-21 15:25:39 -08002426
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002427}
Ryan Hsu07495ea2016-01-21 15:25:39 -08002428#else
2429/**
2430 * wlan_hdd_add_virtual_intf() - Add virtual interface wrapper
2431 * @wiphy: wiphy pointer
2432 * @name: User-visible name of the interface
2433 * @nl80211_iftype: (virtual) interface types
2434 * @flags: monitor mode configuration flags (not used)
2435 * @vif_params: virtual interface parameters (not used)
2436 *
Arun Khandavallic67110c2016-08-18 16:18:51 +05302437 * Return: the pointer of wireless dev, otherwise ERR_PTR.
Ryan Hsu07495ea2016-01-21 15:25:39 -08002438 */
2439struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy,
2440 const char *name,
2441 enum nl80211_iftype type,
2442 u32 *flags,
2443 struct vif_params *params)
2444{
2445 struct wireless_dev *wdev;
2446 unsigned char name_assign_type = 0;
2447
2448 cds_ssr_protect(__func__);
2449 wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type,
2450 type, flags, params);
2451 cds_ssr_unprotect(__func__);
2452 return wdev;
2453
2454}
2455#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002456
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002457int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002458{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002459 struct net_device *dev = wdev->netdev;
Jeff Johnson18767622017-08-28 11:46:50 -07002460 struct hdd_context *pHddCtx = (struct hdd_context *) wiphy_priv(wiphy);
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002461 struct hdd_adapter *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002462 int status;
Srinivas Girigowdaef327802017-03-24 23:13:20 -07002463
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002464 ENTER();
2465
Anurag Chouhan6d760662016-02-20 16:05:43 +05302466 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002467 hdd_err("Command not allowed in FTM mode");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002468 return -EINVAL;
2469 }
2470
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302471 MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002472 TRACE_CODE_HDD_DEL_VIRTUAL_INTF,
2473 pVirtAdapter->sessionId, pVirtAdapter->device_mode));
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002474 hdd_debug("Device_mode %s(%d)",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002475 hdd_device_mode_to_string(pVirtAdapter->device_mode),
2476 pVirtAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002477
2478 status = wlan_hdd_validate_context(pHddCtx);
2479
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05302480 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002481 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002482
Mukul Sharma24699bd2017-04-03 19:50:44 +05302483 /* check state machine state and kickstart modules if they are closed */
Arun Khandavalli99286452016-08-22 12:13:41 +05302484 status = hdd_wlan_start_modules(pHddCtx, pVirtAdapter, false);
2485 if (status)
2486 return status;
2487
Mukul Sharma24699bd2017-04-03 19:50:44 +05302488 if (pVirtAdapter->device_mode == QDF_SAP_MODE &&
2489 wlan_sap_is_pre_cac_active(pHddCtx->hHal)) {
Manishekar Chandrasekaran9e8c7be2016-08-03 14:57:14 +05302490 hdd_clean_up_pre_cac_interface(pHddCtx);
Mukul Sharma24699bd2017-04-03 19:50:44 +05302491 } else {
2492 wlan_hdd_release_intf_addr(pHddCtx,
2493 pVirtAdapter->macAddressCurrent.bytes);
2494 hdd_stop_adapter(pHddCtx, pVirtAdapter, true);
2495 hdd_close_adapter(pHddCtx, pVirtAdapter, true);
Manishekar Chandrasekaran9e8c7be2016-08-03 14:57:14 +05302496 }
2497
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002498 EXIT();
Mukul Sharma24699bd2017-04-03 19:50:44 +05302499
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002500 return 0;
2501}
2502
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002503int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002504{
2505 int ret;
2506
2507 cds_ssr_protect(__func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002508 ret = __wlan_hdd_del_virtual_intf(wiphy, wdev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002509 cds_ssr_unprotect(__func__);
2510
2511 return ret;
2512}
2513
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002514#ifdef WLAN_FEATURE_P2P_DEBUG
2515/*
2516 * wlan_hdd_p2p_action_debug() - Log P2P state and update global status
2517 * @actionFrmType: action frame type
2518 * @macFrom: peer mac address
2519 *
2520 * return: void
2521 */
Srinivas Girigowda85218af2017-03-25 13:21:40 -07002522static void wlan_hdd_p2p_action_debug(enum action_frm_type actionFrmType,
2523 uint8_t *macFrom)
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002524{
2525 if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002526 hdd_debug("[P2P] unknown[%d] <--- OTA from " MAC_ADDRESS_STR,
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002527 actionFrmType, MAC_ADDR_ARRAY(macFrom));
2528 } else {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002529 hdd_debug("[P2P] %s <--- OTA from " MAC_ADDRESS_STR,
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002530 p2p_action_frame_type[actionFrmType],
2531 MAC_ADDR_ARRAY(macFrom));
2532 if ((actionFrmType == WLAN_HDD_PROV_DIS_REQ)
2533 && (global_p2p_connection_status == P2P_NOT_ACTIVE)) {
2534 global_p2p_connection_status = P2P_GO_NEG_PROCESS;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002535 hdd_debug("[P2P State]Inactive state to GO negotiation progress state");
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002536 } else
2537 if ((actionFrmType == WLAN_HDD_GO_NEG_CNF)
2538 && (global_p2p_connection_status == P2P_GO_NEG_PROCESS)) {
2539 global_p2p_connection_status = P2P_GO_NEG_COMPLETED;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002540 hdd_debug("[P2P State]GO negotiation progress to GO negotiation completed state");
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002541 } else
2542 if ((actionFrmType == WLAN_HDD_INVITATION_REQ)
2543 && (global_p2p_connection_status == P2P_NOT_ACTIVE)) {
2544 global_p2p_connection_status = P2P_GO_NEG_COMPLETED;
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002545 hdd_debug("[P2P State]Inactive state to GO negotiation completed state Autonomous GO formation");
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002546 }
2547 }
2548}
2549#else
2550/*
2551 * wlan_hdd_p2p_action_debug() - dummy
2552 * @actionFrmType: action frame type
2553 * @macFrom: peer mac address
2554 *
2555 * return: void
2556 */
Srinivas Girigowda85218af2017-03-25 13:21:40 -07002557static void wlan_hdd_p2p_action_debug(enum action_frm_type actionFrmType,
2558 uint8_t *macFrom)
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002559{
2560
2561}
2562#endif
2563
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002564void __hdd_indicate_mgmt_frame(struct hdd_adapter *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002565 uint32_t nFrameLength,
2566 uint8_t *pbFrames,
2567 uint8_t frameType, uint32_t rxChan, int8_t rxRssi)
2568{
2569 uint16_t freq;
2570 uint16_t extend_time;
2571 uint8_t type = 0;
2572 uint8_t subType = 0;
Srinivas Girigowda85218af2017-03-25 13:21:40 -07002573 enum action_frm_type actionFrmType;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002574 hdd_cfg80211_state_t *cfgState = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302575 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002576 hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL;
Jeff Johnson18767622017-08-28 11:46:50 -07002577 struct hdd_context *pHddCtx;
Samuel Ahn065e6492016-09-30 22:48:09 +05302578 uint8_t broadcast = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002579
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002580 hdd_debug("Frame Type = %d Frame Length = %d",
Samuel Ahn065e6492016-09-30 22:48:09 +05302581 frameType, nFrameLength);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002582
2583 if (NULL == pAdapter) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002584 hdd_err("pAdapter is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002585 return;
2586 }
2587 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2588
2589 if (0 == nFrameLength) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002590 hdd_err("Frame Length is Invalid ZERO");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002591 return;
2592 }
2593
2594 if (NULL == pbFrames) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002595 hdd_err("pbFrames is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002596 return;
2597 }
2598
2599 type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
2600 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
2601
2602 /* Get pAdapter from Destination mac address of the frame */
Sreelakshmi Konamki2b1cd522017-05-26 11:32:44 +05302603 if ((type == SIR_MAC_MGMT_FRAME) &&
2604 (subType != SIR_MAC_MGMT_PROBE_REQ) &&
2605 !qdf_is_macaddr_broadcast(
2606 (struct qdf_mac_addr *)&pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET])) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002607 pAdapter =
Samuel Ahn065e6492016-09-30 22:48:09 +05302608 hdd_get_adapter_by_macaddr(pHddCtx,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002609 &pbFrames
2610 [WLAN_HDD_80211_FRM_DA_OFFSET]);
2611 if (NULL == pAdapter) {
2612 /*
2613 * Under assumtion that we don't receive any action
2614 * frame with BCST as destination,
2615 * we are dropping action frame
2616 */
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002617 hdd_err("pAdapter for action frame is NULL Macaddr = "
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002618 MAC_ADDRESS_STR,
2619 MAC_ADDR_ARRAY(&pbFrames
2620 [WLAN_HDD_80211_FRM_DA_OFFSET]));
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002621 hdd_debug("Frame Type = %d Frame Length = %d subType = %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002622 frameType, nFrameLength, subType);
Jeff Johnson3aaa4922017-01-12 08:46:09 -08002623 /*
2624 * We will receive broadcast management frames
2625 * in OCB mode
2626 */
Samuel Ahn065e6492016-09-30 22:48:09 +05302627 pAdapter = hdd_get_adapter(pHddCtx, QDF_OCB_MODE);
2628 if (NULL == pAdapter || !qdf_is_macaddr_broadcast(
2629 (struct qdf_mac_addr *)&pbFrames
2630 [WLAN_HDD_80211_FRM_DA_OFFSET])) {
2631 /*
Jeff Johnson3aaa4922017-01-12 08:46:09 -08002632 * Under assumtion that we don't
2633 * receive any action frame with BCST
2634 * as destination, we are dropping
2635 * action frame
2636 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002637 return;
Samuel Ahn065e6492016-09-30 22:48:09 +05302638 }
2639
2640 broadcast = 1;
2641
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002642 }
2643 }
2644
2645 if (NULL == pAdapter->dev) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002646 hdd_err("pAdapter->dev is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002647 return;
2648 }
2649
2650 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002651 hdd_err("pAdapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002652 return;
2653 }
2654
2655 /* Channel indicated may be wrong. TODO */
2656 /* Indicate an action frame. */
2657 if (rxChan <= MAX_NO_OF_2_4_CHANNELS)
2658 freq = ieee80211_channel_to_frequency(rxChan,
Dustin Browna30892e2016-10-12 17:28:36 -07002659 NL80211_BAND_2GHZ);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002660 else
2661 freq = ieee80211_channel_to_frequency(rxChan,
Dustin Browna30892e2016-10-12 17:28:36 -07002662 NL80211_BAND_5GHZ);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002663
2664 cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter);
2665
Samuel Ahn065e6492016-09-30 22:48:09 +05302666 if ((type == SIR_MAC_MGMT_FRAME) &&
2667 (subType == SIR_MAC_MGMT_ACTION) && !broadcast) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002668 if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
2669 WLAN_HDD_PUBLIC_ACTION_FRAME) {
2670 /* Public action frame */
2671 if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1]
2672 == SIR_MAC_ACTION_VENDOR_SPECIFIC) &&
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302673 !qdf_mem_cmp(&pbFrames
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002674 [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET
2675 + 2], SIR_MAC_P2P_OUI,
2676 SIR_MAC_P2P_OUI_SIZE)) {
2677 /* P2P action frames */
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002678 uint8_t *macFrom = &pbFrames
Abhishek Singh437606a2016-04-27 13:51:49 +05302679 [WLAN_HDD_80211_PEER_ADDR_OFFSET];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002680 actionFrmType =
2681 pbFrames
2682 [WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET];
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002683 hdd_debug("Rx Action Frame %u",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002684 actionFrmType);
Sandeep Puligillad180c5e2016-06-06 12:06:21 -07002685
2686 wlan_hdd_p2p_action_debug(actionFrmType,
2687 macFrom);
2688
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002689 mutex_lock(&cfgState->remain_on_chan_ctx_lock);
2690 pRemainChanCtx = cfgState->remain_on_chan_ctx;
2691 if (pRemainChanCtx != NULL) {
2692 if (actionFrmType == WLAN_HDD_GO_NEG_REQ
2693 || actionFrmType ==
2694 WLAN_HDD_GO_NEG_RESP
2695 || actionFrmType ==
2696 WLAN_HDD_INVITATION_REQ
2697 || actionFrmType ==
2698 WLAN_HDD_DEV_DIS_REQ
2699 || actionFrmType ==
2700 WLAN_HDD_PROV_DIS_REQ) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002701 hdd_debug("Extend RoC timer on reception of Action Frame");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002702
2703 if ((actionFrmType ==
2704 WLAN_HDD_GO_NEG_REQ)
2705 || (actionFrmType ==
2706 WLAN_HDD_GO_NEG_RESP))
2707 extend_time =
2708 2 *
2709 ACTION_FRAME_DEFAULT_WAIT;
2710 else
2711 extend_time =
2712 ACTION_FRAME_DEFAULT_WAIT;
2713
2714 if (completion_done
2715 (&pAdapter->
2716 rem_on_chan_ready_event)) {
Anurag Chouhan210db072016-02-22 18:42:15 +05302717 if (QDF_TIMER_STATE_RUNNING == qdf_mc_timer_get_current_state(&pRemainChanCtx->hdd_remain_on_chan_timer)) {
2718 qdf_mc_timer_stop
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002719 (&pRemainChanCtx->
2720 hdd_remain_on_chan_timer);
2721 status =
Anurag Chouhan210db072016-02-22 18:42:15 +05302722 qdf_mc_timer_start
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002723 (&pRemainChanCtx->
2724 hdd_remain_on_chan_timer,
2725 extend_time);
2726 if (status !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302727 QDF_STATUS_SUCCESS) {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002728 hdd_err("Remain on Channel timer start failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002729 }
2730 } else {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002731 hdd_debug("Rcvd action frame after timer expired");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 }
2733 } else {
2734 /* Buffer Packet */
2735 if (pRemainChanCtx->
2736 action_pkt_buff.
2737 frame_length == 0) {
2738 pRemainChanCtx->
2739 action_pkt_buff.
2740 frame_length
2741 =
2742 nFrameLength;
2743 pRemainChanCtx->
2744 action_pkt_buff.
2745 freq = freq;
2746 pRemainChanCtx->
2747 action_pkt_buff.
2748 frame_ptr =
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302749 qdf_mem_malloc
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002750 (nFrameLength);
Anurag Chouhan600c3a02016-03-01 10:33:54 +05302751 qdf_mem_copy
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002752 (pRemainChanCtx->
2753 action_pkt_buff.
2754 frame_ptr,
2755 pbFrames,
2756 nFrameLength);
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002757 hdd_debug("Action Pkt Cached successfully !!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002758 } else {
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002759 hdd_err("Frames are pending. dropping frame !!!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002760 }
2761 mutex_unlock(&cfgState->
2762 remain_on_chan_ctx_lock);
2763 return;
2764 }
2765 }
2766 }
2767 mutex_unlock(&cfgState->
2768 remain_on_chan_ctx_lock);
2769
2770 if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP)
2771 && (cfgState->actionFrmState ==
2772 HDD_PD_REQ_ACK_PENDING))
2773 || ((actionFrmType == WLAN_HDD_GO_NEG_RESP)
2774 && (cfgState->actionFrmState ==
2775 HDD_GO_NEG_REQ_ACK_PENDING))) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002776 hdd_debug("ACK_PENDING and But received RESP for Action frame ");
Gowri, Deepthi62da33e2016-09-02 16:01:26 +05302777 cfgState->is_go_neg_ack_received = 1;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002778 hdd_send_action_cnf(pAdapter, true);
2779 }
2780 }
2781#ifdef FEATURE_WLAN_TDLS
2782 else if (pbFrames
2783 [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] ==
2784 WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP) {
Abhishek Singh437606a2016-04-27 13:51:49 +05302785 u8 *mac = &pbFrames
2786 [WLAN_HDD_80211_PEER_ADDR_OFFSET];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002787
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002788 hdd_debug("[TDLS] TDLS Discovery Response,"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002789 MAC_ADDRESS_STR " RSSI[%d] <--- OTA",
2790 MAC_ADDR_ARRAY(mac), rxRssi);
2791
2792 wlan_hdd_tdls_set_rssi(pAdapter, mac, rxRssi);
2793 wlan_hdd_tdls_recv_discovery_resp(pAdapter,
2794 mac);
Abhishek Singh437606a2016-04-27 13:51:49 +05302795 cds_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS,
2796 SIR_MAC_ACTION_RX, SIR_MAC_MGMT_ACTION,
2797 WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP,
2798 &pbFrames[WLAN_HDD_80211_PEER_ADDR_OFFSET]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002799 }
2800#endif
2801 }
2802
2803 if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
2804 WLAN_HDD_TDLS_ACTION_FRAME) {
2805 actionFrmType =
2806 pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1];
2807 if (actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE) {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002808 hdd_debug("[TDLS] unknown[%d] <--- OTA",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002809 actionFrmType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002810 } else {
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002811 hdd_debug("[TDLS] %s <--- OTA",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002812 tdls_action_frame_type[actionFrmType]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002813 }
Abhishek Singh437606a2016-04-27 13:51:49 +05302814 cds_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS,
2815 SIR_MAC_ACTION_RX, SIR_MAC_MGMT_ACTION,
2816 actionFrmType,
2817 &pbFrames[WLAN_HDD_80211_PEER_ADDR_OFFSET]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002818 }
2819
2820 if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] ==
2821 WLAN_HDD_QOS_ACTION_FRAME)
2822 && (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] ==
2823 WLAN_HDD_QOS_MAP_CONFIGURE)) {
2824 sme_update_dsc_pto_up_mapping(pHddCtx->hHal,
2825 pAdapter->hddWmmDscpToUpMap,
2826 pAdapter->sessionId);
2827 }
2828 }
2829 /* Indicate Frame Over Normal Interface */
Srinivas Girigowdac7f00d42017-03-06 18:01:35 -08002830 hdd_debug("Indicate Frame over NL80211 sessionid : %d, idx :%d",
Archana Ramachandrandfb6f852016-08-19 17:25:29 -07002831 pAdapter->sessionId, pAdapter->dev->ifindex);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002832
2833#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
Samuel Ahn065e6492016-09-30 22:48:09 +05302834 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
2835 freq, rxRssi * 100, pbFrames,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002836 nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED);
2837#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
Samuel Ahn065e6492016-09-30 22:48:09 +05302838 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr,
2839 freq, rxRssi * 100, pbFrames,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002840 nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED,
2841 GFP_ATOMIC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002842#else
Samuel Ahn065e6492016-09-30 22:48:09 +05302843 cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq,
2844 rxRssi * 100,
2845 pbFrames, nFrameLength, GFP_ATOMIC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002846#endif /* LINUX_VERSION_CODE */
2847}
2848
Wu Gao9a704f42017-03-10 18:42:11 +08002849#ifdef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002850int wlan_hdd_set_power_save(struct hdd_adapter *adapter,
Wu Gao9a704f42017-03-10 18:42:11 +08002851 tpP2pPsConfig pnoa)
2852{
2853 struct wlan_objmgr_psoc *psoc;
Jeff Johnson18767622017-08-28 11:46:50 -07002854 struct hdd_context *hdd_ctx;
Wu Gao9a704f42017-03-10 18:42:11 +08002855 struct p2p_ps_config ps_config;
2856 QDF_STATUS status;
2857
2858 if (!adapter || !pnoa) {
2859 hdd_err("null param, adapter:%p, pnoa:%p",
2860 adapter, pnoa);
2861 return -EINVAL;
2862 }
2863
2864 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2865 psoc = hdd_ctx->hdd_psoc;
2866 if (!psoc) {
2867 hdd_err("psoc is null");
2868 return -EINVAL;
2869 }
2870
2871 ps_config.opp_ps = pnoa->opp_ps;
2872 ps_config.ct_window = pnoa->ctWindow;
2873 ps_config.duration = pnoa->duration;
2874 ps_config.interval = pnoa->interval;
2875 ps_config.count = pnoa->count;
2876 ps_config.single_noa_duration = pnoa->single_noa_duration;
2877 ps_config.ps_selection = pnoa->psSelection;
2878 ps_config.vdev_id = pnoa->sessionid;
2879
2880 hdd_info("opp ps:%d, ct window:%d, duration:%d, interval:%d, count:%d, single noa duration:%d, ps selection:%d, vdev id:%d",
2881 ps_config.opp_ps, ps_config.ct_window,
2882 ps_config.duration, ps_config.interval,
2883 ps_config.count, ps_config.single_noa_duration,
2884 ps_config.ps_selection, ps_config.vdev_id);
2885
2886 status = ucfg_p2p_set_ps(psoc, &ps_config);
2887 hdd_info("p2p set power save, status:%d", status);
2888
2889 return qdf_status_to_os_return(status);
2890}
2891#else
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002892int wlan_hdd_set_power_save(struct hdd_adapter *adapter,
Wu Gao9a704f42017-03-10 18:42:11 +08002893 tpP2pPsConfig pnoa)
2894{
2895 tHalHandle handle;
2896 QDF_STATUS status;
2897
2898 if (!adapter || !pnoa) {
2899 hdd_err("null param, adapter:%p, pnoa:%p",
2900 adapter, pnoa);
2901 return -EINVAL;
2902 }
2903
2904 handle = WLAN_HDD_GET_HAL_CTX(adapter);
2905 status = sme_p2p_set_ps(handle, pnoa);
2906 hdd_info("p2p set power save, status:%d", status);
2907
2908 return qdf_status_to_os_return(status);
2909}
2910#endif
2911
2912#ifdef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002913int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter,
Wu Gao9a704f42017-03-10 18:42:11 +08002914 struct sir_p2p_lo_start *params)
2915{
2916 struct wlan_objmgr_psoc *psoc;
2917 struct p2p_lo_start lo_start;
Jeff Johnson18767622017-08-28 11:46:50 -07002918 struct hdd_context *hdd_ctx;
Wu Gao9a704f42017-03-10 18:42:11 +08002919 QDF_STATUS status;
2920
2921 if (!adapter || !params) {
2922 hdd_err("null param, adapter:%p, params:%p",
2923 adapter, params);
2924 return -EINVAL;
2925 }
2926
2927 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2928 psoc = hdd_ctx->hdd_psoc;
2929 if (!psoc) {
2930 hdd_err("psoc is null");
2931 return -EINVAL;
2932 }
2933
2934 lo_start.vdev_id = params->vdev_id;
2935 lo_start.ctl_flags = params->ctl_flags;
2936 lo_start.freq = params->freq;
2937 lo_start.period = params->period;
2938 lo_start.interval = params->interval;
2939 lo_start.count = params->count;
2940 lo_start.device_types = params->device_types;
2941 lo_start.dev_types_len = params->dev_types_len;
2942 lo_start.probe_resp_tmplt = params->probe_resp_tmplt;
2943 lo_start.probe_resp_len = params->probe_resp_len;
2944
2945 status = ucfg_p2p_lo_start(psoc, &lo_start);
2946 hdd_info("p2p listen offload start, status:%d", status);
2947
2948 return qdf_status_to_os_return(status);
2949}
2950#else
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002951int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter,
Wu Gao9a704f42017-03-10 18:42:11 +08002952 struct sir_p2p_lo_start *params)
2953{
2954 QDF_STATUS status;
2955
2956 if (!params) {
2957 hdd_err("params is null, params:%p", params);
2958 return -EINVAL;
2959 }
2960
2961 status = wma_p2p_lo_start(params);
2962 hdd_info("p2p listen offload start, status:%d", status);
2963
2964 return qdf_status_to_os_return(status);
2965}
2966#endif
2967
2968#ifdef CONVERGED_P2P_ENABLE
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002969int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter)
Wu Gao9a704f42017-03-10 18:42:11 +08002970{
2971 struct wlan_objmgr_psoc *psoc;
Jeff Johnson18767622017-08-28 11:46:50 -07002972 struct hdd_context *hdd_ctx;
Wu Gao9a704f42017-03-10 18:42:11 +08002973 uint32_t vdev_id;
2974 QDF_STATUS status;
2975
2976 if (!adapter) {
2977 hdd_err("adapter is null, adapter:%p", adapter);
2978 return -EINVAL;
2979 }
2980
2981 vdev_id = (uint32_t)adapter->sessionId;
2982 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2983 psoc = hdd_ctx->hdd_psoc;
2984 if (!psoc) {
2985 hdd_err("psoc is null");
2986 return -EINVAL;
2987 }
2988
2989 status = ucfg_p2p_lo_stop(psoc, vdev_id);
2990 hdd_info("p2p listen offload stop, status:%d", status);
2991
2992 return qdf_status_to_os_return(status);
2993}
2994#else
Jeff Johnsonfbb54522017-08-29 14:25:27 -07002995int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter)
Wu Gao9a704f42017-03-10 18:42:11 +08002996{
2997 QDF_STATUS status;
2998
2999 if (!adapter) {
3000 hdd_err("adapter is null, adapter:%p", adapter);
3001 return -EINVAL;
3002 }
3003
3004 status = wma_p2p_lo_stop(adapter->sessionId);
3005 hdd_info("p2p listen offload stop, status:%d", status);
3006
3007 return qdf_status_to_os_return(status);
3008}
3009#endif
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003010
3011/**
3012 * wlan_hdd_update_mcc_adaptive_scheduler() - Function to update
3013 * MAS value to FW
3014 * @adapter: adapter object data
3015 * @is_enable: 0-Disable, 1-Enable MAS
3016 *
3017 * This function passes down the value of MAS to UMAC
3018 *
3019 * Return: 0 for success else non zero
3020 *
3021 */
3022static int32_t wlan_hdd_update_mcc_adaptive_scheduler(
Jeff Johnsonfbb54522017-08-29 14:25:27 -07003023 struct hdd_adapter *adapter, bool is_enable)
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003024{
Jeff Johnson18767622017-08-28 11:46:50 -07003025 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003026
3027 if (hdd_ctx == NULL) {
3028 hdd_err("HDD context is null");
3029 return -EINVAL;
3030 }
3031
3032 hdd_info("enable/disable MAS :%d", is_enable);
3033 if (hdd_ctx->config &&
3034 hdd_ctx->config->enableMCCAdaptiveScheduler) {
3035 /* Todo check where to set the MCC apative SCHED for read */
3036
3037 if (QDF_STATUS_SUCCESS != sme_set_mas(is_enable)) {
3038 hdd_err("Failed to enable/disable MAS");
3039 return -EAGAIN;
3040 }
3041 }
3042
3043 return 0;
3044}
3045
3046/**
3047 * wlan_hdd_update_mcc_p2p_quota() - Function to Update P2P
3048 * quota to FW
3049 * @adapter: Pointer to HDD adapter
3050 * @is_set: 0-reset, 1-set
3051 *
3052 * This function passes down the value of MAS to UMAC
3053 *
3054 * Return: none
3055 *
3056 */
Jeff Johnsonfbb54522017-08-29 14:25:27 -07003057static void wlan_hdd_update_mcc_p2p_quota(struct hdd_adapter *adapter,
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003058 bool is_set)
3059{
3060
3061 hdd_info("Set/reset P2P quota: %d", is_set);
3062 if (is_set) {
3063 if (adapter->device_mode == QDF_STA_MODE)
3064 wlan_hdd_set_mcc_p2p_quota(adapter,
3065 100 - HDD_DEFAULT_MCC_P2P_QUOTA
3066 );
3067 else if (adapter->device_mode == QDF_P2P_GO_MODE)
3068 wlan_hdd_go_set_mcc_p2p_quota(adapter,
3069 HDD_DEFAULT_MCC_P2P_QUOTA);
3070 else
3071 wlan_hdd_set_mcc_p2p_quota(adapter,
3072 HDD_DEFAULT_MCC_P2P_QUOTA);
3073 } else {
3074 if (adapter->device_mode == QDF_P2P_GO_MODE)
3075 wlan_hdd_go_set_mcc_p2p_quota(adapter,
3076 HDD_RESET_MCC_P2P_QUOTA);
3077 else
3078 wlan_hdd_set_mcc_p2p_quota(adapter,
3079 HDD_RESET_MCC_P2P_QUOTA);
3080 }
3081}
3082
Jeff Johnsonfbb54522017-08-29 14:25:27 -07003083int32_t wlan_hdd_set_mas(struct hdd_adapter *adapter, uint8_t mas_value)
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003084{
3085 int32_t ret = 0;
3086
3087 if (!adapter) {
3088 hdd_err("Adapter is NULL");
3089 return -EINVAL;
3090 }
3091
3092 if (mas_value) {
3093 hdd_info("Miracast is ON. Disable MAS and configure P2P quota");
3094 ret = wlan_hdd_update_mcc_adaptive_scheduler(
3095 adapter, false);
3096 if (0 != ret) {
3097 hdd_err("Failed to disable MAS");
3098 goto done;
3099 }
3100
3101 /* Config p2p quota */
3102 wlan_hdd_update_mcc_p2p_quota(adapter, true);
3103 } else {
3104 hdd_info("Miracast is OFF. Enable MAS and reset P2P quota");
3105 wlan_hdd_update_mcc_p2p_quota(adapter, false);
3106
3107 ret = wlan_hdd_update_mcc_adaptive_scheduler(
3108 adapter, true);
3109 if (0 != ret) {
3110 hdd_err("Failed to enable MAS");
3111 goto done;
3112 }
3113 }
3114
3115done:
3116 return ret;
3117}
3118
3119/**
3120 * set_first_connection_operating_channel() - Function to set
3121 * first connection oerating channel
3122 * @adapter: adapter data
3123 * @set_value: Quota value for the interface
3124 * @dev_mode: Device mode
3125 * This function is used to set the first adapter operating
3126 * channel
3127 *
3128 * Return: operating channel updated in set value
3129 *
3130 */
3131static uint32_t set_first_connection_operating_channel(
Jeff Johnson18767622017-08-28 11:46:50 -07003132 struct hdd_context *hdd_ctx, uint32_t set_value,
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003133 enum tQDF_ADAPTER_MODE dev_mode)
3134{
3135 uint8_t operating_channel;
3136
3137 operating_channel = hdd_get_operating_channel(
3138 hdd_ctx, dev_mode);
3139 if (!operating_channel) {
3140 hdd_err(" First adpter operating channel is invalid");
3141 return -EINVAL;
3142 }
3143
3144 hdd_info("First connection channel No.:%d and quota:%dms",
3145 operating_channel, set_value);
3146 /* Move the time quota for first channel to bits 15-8 */
3147 set_value = set_value << 8;
3148
3149 /*
3150 * Store the channel number of 1st channel at bits 7-0
3151 * of the bit vector
3152 */
3153 return set_value | operating_channel;
3154}
3155
3156/**
3157 * set_second_connection_operating_channel() - Function to set
3158 * second connection oerating channel
3159 * @adapter: adapter data
3160 * @set_value: Quota value for the interface
3161 * @vdev_id: vdev id
3162 *
3163 * This function is used to set the first adapter operating
3164 * channel
3165 *
3166 * Return: operating channel updated in set value
3167 *
3168 */
3169static uint32_t set_second_connection_operating_channel(
Jeff Johnson18767622017-08-28 11:46:50 -07003170 struct hdd_context *hdd_ctx, uint32_t set_value,
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003171 uint8_t vdev_id)
3172{
3173 uint8_t operating_channel;
3174
3175 operating_channel = policy_mgr_get_mcc_operating_channel(
3176 hdd_ctx->hdd_psoc, vdev_id);
3177
3178 if (operating_channel == 0) {
3179 hdd_err("Second adapter operating channel is invalid");
3180 return -EINVAL;
3181 }
3182
3183 hdd_info("Second connection channel No.:%d and quota:%dms",
3184 operating_channel, set_value);
3185 /*
3186 * Now move the time quota and channel number of the
3187 * 1st adapter to bits 23-16 and bits 15-8 of the bit
3188 * vector, respectively.
3189 */
3190 set_value = set_value << 8;
3191
3192 /*
3193 * Set the channel number for 2nd MCC vdev at bits
3194 * 7-0 of set_value
3195 */
3196 return set_value | operating_channel;
3197}
3198
3199/**
3200 * wlan_hdd_set_mcc_p2p_quota() - Function to set quota for P2P
3201 * @psoc: PSOC object information
3202 * @set_value: Qouta value for the interface
3203 * @operating_channel First adapter operating channel
3204 * @vdev_id vdev id
3205 *
3206 * This function is used to set the quota for P2P cases
3207 *
3208 * Return: Configuration message posting status, SUCCESS or Fail
3209 *
3210 */
Jeff Johnsonfbb54522017-08-29 14:25:27 -07003211int wlan_hdd_set_mcc_p2p_quota(struct hdd_adapter *adapter,
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003212 uint32_t set_value)
3213{
3214 int32_t ret = 0;
3215 uint32_t concurrent_state;
Jeff Johnson18767622017-08-28 11:46:50 -07003216 struct hdd_context *hdd_ctx;
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003217
3218 if (!adapter) {
3219 hdd_err("Invalid adapter");
3220 return -EFAULT;
3221 }
3222 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3223 if (hdd_ctx == NULL) {
3224 hdd_err("HDD context is null");
3225 return -EINVAL;
3226 }
3227
3228 concurrent_state = policy_mgr_get_concurrency_mode(
3229 hdd_ctx->hdd_psoc);
3230 /*
3231 * Check if concurrency mode is active.
3232 * Need to modify this code to support MCC modes other than STA/P2P
3233 */
3234 if ((concurrent_state ==
3235 (QDF_STA_MASK | QDF_P2P_CLIENT_MASK)) ||
3236 (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_MASK))) {
3237 hdd_info("STA & P2P are both enabled");
3238
3239 /*
3240 * The channel numbers for both adapters and the time
3241 * quota for the 1st adapter, i.e., one specified in cmd
3242 * are formatted as a bit vector then passed on to WMA
3243 * +***********************************************************+
3244 * |bit 31-24 | bit 23-16 | bits 15-8 | bits 7-0 |
3245 * | Unused | Quota for | chan. # for | chan. # for |
3246 * | | 1st chan. | 1st chan. | 2nd chan. |
3247 * +***********************************************************+
3248 */
3249
3250 set_value = set_first_connection_operating_channel(
3251 hdd_ctx, set_value, adapter->device_mode);
3252
3253
3254 set_value = set_second_connection_operating_channel(
3255 hdd_ctx, set_value, adapter->sessionId);
3256
3257
3258 ret = wlan_hdd_send_p2p_quota(adapter, set_value);
3259 } else {
3260 hdd_info("MCC is not active. Exit w/o setting latency");
3261 }
3262
3263 return ret;
3264}
3265
Jeff Johnsonfbb54522017-08-29 14:25:27 -07003266int wlan_hdd_go_set_mcc_p2p_quota(struct hdd_adapter *hostapd_adapter,
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003267 uint32_t set_value)
3268{
3269 return wlan_hdd_set_mcc_p2p_quota(hostapd_adapter, set_value);
3270}
3271
Jeff Johnsonfbb54522017-08-29 14:25:27 -07003272void wlan_hdd_set_mcc_latency(struct hdd_adapter *adapter, int set_value)
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003273{
3274 uint32_t concurrent_state;
Jeff Johnson18767622017-08-28 11:46:50 -07003275 struct hdd_context *hdd_ctx;
Archana Ramachandranb8c04f92017-03-17 20:05:47 -07003276
3277 if (!adapter) {
3278 hdd_err("Invalid adapter");
3279 return;
3280 }
3281
3282 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3283 if (hdd_ctx == NULL) {
3284 hdd_err("HDD context is null");
3285 return;
3286 }
3287
3288 concurrent_state = policy_mgr_get_concurrency_mode(
3289 hdd_ctx->hdd_psoc);
3290 /**
3291 * Check if concurrency mode is active.
3292 * Need to modify this code to support MCC modes other than STA/P2P
3293 */
3294 if ((concurrent_state ==
3295 (QDF_STA_MASK | QDF_P2P_CLIENT_MASK)) ||
3296 (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_MASK))) {
3297 hdd_info("STA & P2P are both enabled");
3298 /*
3299 * The channel number and latency are formatted in
3300 * a bit vector then passed on to WMA layer.
3301 * +**********************************************+
3302 * |bits 31-16 | bits 15-8 | bits 7-0 |
3303 * | Unused | latency - Chan. 1 | channel no. |
3304 * +**********************************************+
3305 */
3306 set_value = set_first_connection_operating_channel(
3307 hdd_ctx, set_value, adapter->device_mode);
3308
3309 wlan_hdd_send_mcc_latency(adapter, set_value);
3310 } else {
3311 hdd_info("MCC is not active. Exit w/o setting latency");
3312 }
3313}