xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: wlan_hdd_twt.c
22*5113495bSYour Name  *
23*5113495bSYour Name  * WLAN Host Device Driver file for TWT (Target Wake Time) support.
24*5113495bSYour Name  *
25*5113495bSYour Name  */
26*5113495bSYour Name 
27*5113495bSYour Name #include "wmi.h"
28*5113495bSYour Name #include "wmi_unified_priv.h"
29*5113495bSYour Name #include "wmi_unified_twt_param.h"
30*5113495bSYour Name #include "wlan_hdd_twt.h"
31*5113495bSYour Name #include "wlan_hdd_main.h"
32*5113495bSYour Name #include "wlan_hdd_cfg.h"
33*5113495bSYour Name #include "wlan_hdd_hostapd.h"
34*5113495bSYour Name #include "sme_api.h"
35*5113495bSYour Name #include "wma_twt.h"
36*5113495bSYour Name #include "osif_sync.h"
37*5113495bSYour Name #include "wlan_osif_request_manager.h"
38*5113495bSYour Name #include "cfg_ucfg_api.h"
39*5113495bSYour Name #include <wlan_cp_stats_mc_ucfg_api.h>
40*5113495bSYour Name #include <wlan_mlme_twt_ucfg_api.h>
41*5113495bSYour Name #include <target_if.h>
42*5113495bSYour Name #include "wlan_hdd_object_manager.h"
43*5113495bSYour Name #include "osif_twt_ext_req.h"
44*5113495bSYour Name #include "wlan_mlo_mgr_sta.h"
45*5113495bSYour Name #include "wlan_twt_ucfg_ext_api.h"
46*5113495bSYour Name #include "wlan_twt_ucfg_ext_cfg.h"
47*5113495bSYour Name #include "osif_twt_internal.h"
48*5113495bSYour Name 
49*5113495bSYour Name const struct nla_policy
50*5113495bSYour Name wlan_hdd_wifi_twt_config_policy[
51*5113495bSYour Name 	QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = {
52*5113495bSYour Name 		[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION] = {
53*5113495bSYour Name 			.type = NLA_U8},
54*5113495bSYour Name 		[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS] = {
55*5113495bSYour Name 			.type = NLA_NESTED},
56*5113495bSYour Name };
57*5113495bSYour Name 
58*5113495bSYour Name #if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED)
hdd_get_twt_requestor(struct wlan_objmgr_psoc * psoc,bool * val)59*5113495bSYour Name QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val)
60*5113495bSYour Name {
61*5113495bSYour Name 	return ucfg_twt_cfg_get_requestor(psoc, val);
62*5113495bSYour Name }
63*5113495bSYour Name 
hdd_get_twt_responder(struct wlan_objmgr_psoc * psoc,bool * val)64*5113495bSYour Name QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val)
65*5113495bSYour Name {
66*5113495bSYour Name 	return ucfg_twt_cfg_get_responder(psoc, val);
67*5113495bSYour Name }
68*5113495bSYour Name 
hdd_update_tgt_twt_cap(struct hdd_context * hdd_ctx,struct wma_tgt_cfg * cfg)69*5113495bSYour Name void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
70*5113495bSYour Name 			    struct wma_tgt_cfg *cfg)
71*5113495bSYour Name {
72*5113495bSYour Name 	ucfg_twt_update_psoc_config(hdd_ctx->psoc);
73*5113495bSYour Name }
74*5113495bSYour Name 
hdd_send_twt_responder_enable_cmd(struct hdd_context * hdd_ctx)75*5113495bSYour Name QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx)
76*5113495bSYour Name {
77*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
78*5113495bSYour Name 
79*5113495bSYour Name 	osif_twt_send_responder_enable_cmd(hdd_ctx->psoc, pdev_id);
80*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
81*5113495bSYour Name }
82*5113495bSYour Name 
wlan_twt_concurrency_update(struct hdd_context * hdd_ctx)83*5113495bSYour Name void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx)
84*5113495bSYour Name {
85*5113495bSYour Name 	if (wlan_hdd_is_twt_pmo_allowed(hdd_ctx))
86*5113495bSYour Name 		qdf_sched_work(0, &hdd_ctx->twt_en_dis_work);
87*5113495bSYour Name }
88*5113495bSYour Name 
hdd_twt_update_work_handler(void * data)89*5113495bSYour Name void hdd_twt_update_work_handler(void *data)
90*5113495bSYour Name {
91*5113495bSYour Name 	struct hdd_context *hdd_ctx = (struct hdd_context *)data;
92*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
93*5113495bSYour Name 	int ret;
94*5113495bSYour Name 
95*5113495bSYour Name 	ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
96*5113495bSYour Name 	if (ret)
97*5113495bSYour Name 		return;
98*5113495bSYour Name 
99*5113495bSYour Name 	osif_twt_concurrency_update_handler(hdd_ctx->psoc, hdd_ctx->pdev);
100*5113495bSYour Name 
101*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
102*5113495bSYour Name }
103*5113495bSYour Name 
hdd_send_twt_requestor_enable_cmd(struct hdd_context * hdd_ctx)104*5113495bSYour Name QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx)
105*5113495bSYour Name {
106*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
107*5113495bSYour Name 
108*5113495bSYour Name 	osif_twt_send_requestor_enable_cmd(hdd_ctx->psoc, pdev_id);
109*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
110*5113495bSYour Name }
111*5113495bSYour Name 
hdd_twt_del_dialog_in_ps_disable(struct hdd_context * hdd_ctx,struct qdf_mac_addr * mac_addr,uint8_t vdev_id)112*5113495bSYour Name void hdd_twt_del_dialog_in_ps_disable(struct hdd_context *hdd_ctx,
113*5113495bSYour Name 				      struct qdf_mac_addr *mac_addr,
114*5113495bSYour Name 				      uint8_t vdev_id)
115*5113495bSYour Name {
116*5113495bSYour Name 	return osif_twt_teardown_in_ps_disable(hdd_ctx->psoc, mac_addr,
117*5113495bSYour Name 					       vdev_id);
118*5113495bSYour Name }
119*5113495bSYour Name 
hdd_send_twt_role_disable_cmd(struct hdd_context * hdd_ctx,enum twt_role role)120*5113495bSYour Name void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx,
121*5113495bSYour Name 				   enum twt_role role)
122*5113495bSYour Name {
123*5113495bSYour Name 	uint32_t reason;
124*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
125*5113495bSYour Name 
126*5113495bSYour Name 	reason = HOST_TWT_DISABLE_REASON_NONE;
127*5113495bSYour Name 	osif_twt_send_responder_disable_cmd(hdd_ctx->psoc, pdev_id, reason);
128*5113495bSYour Name }
129*5113495bSYour Name 
hdd_test_config_twt_setup_session(struct hdd_adapter * adapter,struct nlattr ** tb)130*5113495bSYour Name int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter,
131*5113495bSYour Name 				      struct nlattr **tb)
132*5113495bSYour Name {
133*5113495bSYour Name 	return 0;
134*5113495bSYour Name }
135*5113495bSYour Name 
wlan_hdd_twt_deinit(struct hdd_context * hdd_ctx)136*5113495bSYour Name void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)
137*5113495bSYour Name {
138*5113495bSYour Name 	qdf_flush_work(&hdd_ctx->twt_en_dis_work);
139*5113495bSYour Name 	qdf_destroy_work(NULL, &hdd_ctx->twt_en_dis_work);
140*5113495bSYour Name }
141*5113495bSYour Name 
142*5113495bSYour Name void
hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info * link_info)143*5113495bSYour Name hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info *link_info)
144*5113495bSYour Name {
145*5113495bSYour Name }
146*5113495bSYour Name 
hdd_test_config_twt_terminate_session(struct hdd_adapter * adapter,struct nlattr ** tb)147*5113495bSYour Name int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter,
148*5113495bSYour Name 					  struct nlattr **tb)
149*5113495bSYour Name {
150*5113495bSYour Name 	return 0;
151*5113495bSYour Name }
152*5113495bSYour Name 
hdd_send_twt_responder_disable_cmd(struct hdd_context * hdd_ctx,uint32_t reason)153*5113495bSYour Name QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx,
154*5113495bSYour Name 					      uint32_t reason)
155*5113495bSYour Name {
156*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
157*5113495bSYour Name 
158*5113495bSYour Name 	osif_twt_send_responder_disable_cmd(hdd_ctx->psoc, pdev_id, reason);
159*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
160*5113495bSYour Name }
161*5113495bSYour Name 
wlan_hdd_twt_init(struct hdd_context * hdd_ctx)162*5113495bSYour Name void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
163*5113495bSYour Name {
164*5113495bSYour Name 	osif_twt_send_requestor_enable_cmd(hdd_ctx->psoc, 0);
165*5113495bSYour Name 	qdf_create_work(0, &hdd_ctx->twt_en_dis_work,
166*5113495bSYour Name 			hdd_twt_update_work_handler, hdd_ctx);
167*5113495bSYour Name }
168*5113495bSYour Name 
169*5113495bSYour Name /**
170*5113495bSYour Name  * hdd_twt_terminate_session - Process TWT terminate
171*5113495bSYour Name  * operation in the received vendor command and
172*5113495bSYour Name  * send it to firmware
173*5113495bSYour Name  * @adapter: adapter pointer
174*5113495bSYour Name  * @vdev: associated vdev object
175*5113495bSYour Name  * @twt_param_attr: nl attributes
176*5113495bSYour Name  *
177*5113495bSYour Name  * Handles QCA_WLAN_TWT_TERMINATE
178*5113495bSYour Name  *
179*5113495bSYour Name  * Return: 0 on success, negative value on failure
180*5113495bSYour Name  */
hdd_twt_terminate_session(struct hdd_adapter * adapter,struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)181*5113495bSYour Name static int hdd_twt_terminate_session(struct hdd_adapter *adapter,
182*5113495bSYour Name 				     struct wlan_objmgr_vdev *vdev,
183*5113495bSYour Name 				     struct nlattr *twt_param_attr)
184*5113495bSYour Name {
185*5113495bSYour Name 	enum QDF_OPMODE device_mode = adapter->device_mode;
186*5113495bSYour Name 
187*5113495bSYour Name 	switch (device_mode) {
188*5113495bSYour Name 	case QDF_STA_MODE:
189*5113495bSYour Name 		return osif_twt_sta_teardown_req(vdev, twt_param_attr);
190*5113495bSYour Name 	case QDF_SAP_MODE:
191*5113495bSYour Name 		return osif_twt_sap_teardown_req(vdev, twt_param_attr);
192*5113495bSYour Name 	default:
193*5113495bSYour Name 		hdd_err_rl("TWT terminate is not supported on %s",
194*5113495bSYour Name 			   qdf_opmode_str(adapter->device_mode));
195*5113495bSYour Name 		return -EOPNOTSUPP;
196*5113495bSYour Name 	}
197*5113495bSYour Name }
198*5113495bSYour Name 
hdd_twt_configure(struct hdd_adapter * adapter,struct nlattr ** tb)199*5113495bSYour Name static int hdd_twt_configure(struct hdd_adapter *adapter,
200*5113495bSYour Name 			     struct nlattr **tb)
201*5113495bSYour Name {
202*5113495bSYour Name 	enum qca_wlan_twt_operation twt_oper;
203*5113495bSYour Name 	struct nlattr *twt_oper_attr;
204*5113495bSYour Name 	struct nlattr *twt_param_attr;
205*5113495bSYour Name 	uint32_t id;
206*5113495bSYour Name 	int ret = 0;
207*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
208*5113495bSYour Name 
209*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION;
210*5113495bSYour Name 	twt_oper_attr = tb[id];
211*5113495bSYour Name 
212*5113495bSYour Name 	if (!twt_oper_attr) {
213*5113495bSYour Name 		hdd_err("TWT operation NOT specified");
214*5113495bSYour Name 		return -EINVAL;
215*5113495bSYour Name 	}
216*5113495bSYour Name 
217*5113495bSYour Name 	twt_oper = nla_get_u8(twt_oper_attr);
218*5113495bSYour Name 
219*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS;
220*5113495bSYour Name 	twt_param_attr = tb[id];
221*5113495bSYour Name 
222*5113495bSYour Name 	if (!twt_param_attr &&
223*5113495bSYour Name 	    twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES &&
224*5113495bSYour Name 	    twt_oper != QCA_WLAN_TWT_SUSPEND) {
225*5113495bSYour Name 		hdd_err("TWT parameters NOT specified");
226*5113495bSYour Name 		return -EINVAL;
227*5113495bSYour Name 	}
228*5113495bSYour Name 
229*5113495bSYour Name 	hdd_debug("TWT Operation 0x%x", twt_oper);
230*5113495bSYour Name 
231*5113495bSYour Name 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_TWT_ID);
232*5113495bSYour Name 	if (!vdev) {
233*5113495bSYour Name 		hdd_err("vdev is NULL");
234*5113495bSYour Name 		return -EINVAL;
235*5113495bSYour Name 	}
236*5113495bSYour Name 
237*5113495bSYour Name 	switch (twt_oper) {
238*5113495bSYour Name 	case QCA_WLAN_TWT_SET:
239*5113495bSYour Name 		ret = osif_twt_setup_req(vdev, twt_param_attr);
240*5113495bSYour Name 		break;
241*5113495bSYour Name 	case QCA_WLAN_TWT_GET:
242*5113495bSYour Name 		ret = osif_twt_get_session_req(vdev, twt_param_attr);
243*5113495bSYour Name 		break;
244*5113495bSYour Name 	case QCA_WLAN_TWT_TERMINATE:
245*5113495bSYour Name 		ret = hdd_twt_terminate_session(adapter, vdev, twt_param_attr);
246*5113495bSYour Name 		break;
247*5113495bSYour Name 	case QCA_WLAN_TWT_SUSPEND:
248*5113495bSYour Name 		ret = osif_twt_pause_req(vdev, twt_param_attr);
249*5113495bSYour Name 		break;
250*5113495bSYour Name 	case QCA_WLAN_TWT_RESUME:
251*5113495bSYour Name 		ret = osif_twt_resume_req(vdev, twt_param_attr);
252*5113495bSYour Name 		break;
253*5113495bSYour Name 	case QCA_WLAN_TWT_NUDGE:
254*5113495bSYour Name 		ret = osif_twt_nudge_req(vdev, twt_param_attr);
255*5113495bSYour Name 		break;
256*5113495bSYour Name 	case QCA_WLAN_TWT_GET_CAPABILITIES:
257*5113495bSYour Name 		ret = osif_twt_get_capabilities(vdev);
258*5113495bSYour Name 		break;
259*5113495bSYour Name 	case QCA_WLAN_TWT_GET_STATS:
260*5113495bSYour Name 		ret = osif_twt_get_session_traffic_stats(vdev, twt_param_attr);
261*5113495bSYour Name 		break;
262*5113495bSYour Name 	case QCA_WLAN_TWT_CLEAR_STATS:
263*5113495bSYour Name 		ret = osif_twt_clear_session_traffic_stats(vdev,
264*5113495bSYour Name 							   twt_param_attr);
265*5113495bSYour Name 		break;
266*5113495bSYour Name 	case QCA_WLAN_TWT_SET_PARAM:
267*5113495bSYour Name 		ret = osif_twt_set_param(vdev, twt_param_attr);
268*5113495bSYour Name 		break;
269*5113495bSYour Name 	default:
270*5113495bSYour Name 		hdd_err("Invalid TWT Operation");
271*5113495bSYour Name 		ret = -EINVAL;
272*5113495bSYour Name 		break;
273*5113495bSYour Name 	}
274*5113495bSYour Name 
275*5113495bSYour Name 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_TWT_ID);
276*5113495bSYour Name 	return ret;
277*5113495bSYour Name }
278*5113495bSYour Name #elif defined(WLAN_SUPPORT_TWT)
279*5113495bSYour Name 
280*5113495bSYour Name #define TWT_DISABLE_COMPLETE_TIMEOUT 1000
281*5113495bSYour Name #define TWT_ENABLE_COMPLETE_TIMEOUT  1000
282*5113495bSYour Name #define TWT_ACK_COMPLETE_TIMEOUT 1000
283*5113495bSYour Name #define TWT_WORK_RESCHED_WAIT_TIME 30
284*5113495bSYour Name 
285*5113495bSYour Name #define TWT_FLOW_TYPE_ANNOUNCED 0
286*5113495bSYour Name #define TWT_FLOW_TYPE_UNANNOUNCED 1
287*5113495bSYour Name 
288*5113495bSYour Name #define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX       0xFFFF
289*5113495bSYour Name #define TWT_SETUP_WAKE_DURATION_MAX             0xFFFF
290*5113495bSYour Name #define TWT_SETUP_WAKE_INTVL_EXP_MAX            31
291*5113495bSYour Name #define TWT_WAKE_INTVL_MULTIPLICATION_FACTOR    1024
292*5113495bSYour Name #define TWT_WAKE_DURATION_MULTIPLICATION_FACTOR 256
293*5113495bSYour Name #define TWT_MAX_NEXT_TWT_SIZE                   3
294*5113495bSYour Name 
295*5113495bSYour Name static const struct nla_policy
296*5113495bSYour Name qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = {
297*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 },
298*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG },
299*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 },
300*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG },
301*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID] = {.type = NLA_U8 },
302*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 },
303*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG },
304*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 },
305*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 },
306*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 },
307*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 },
308*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 },
309*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 },
310*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 },
311*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA] = {.type = NLA_U32 },
312*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
313*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID] = {.type = NLA_U8 },
314*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION] = {
315*5113495bSYour Name 							.type = NLA_U8 },
316*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE] = {.type = NLA_U8 },
317*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF] = {.type = NLA_U64 },
318*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT] = {.type = NLA_U32 },
319*5113495bSYour Name };
320*5113495bSYour Name 
321*5113495bSYour Name static const struct nla_policy
322*5113495bSYour Name qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1] = {
323*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID] = {.type = NLA_U8 },
324*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT] = {.type = NLA_U8 },
325*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE] = {.type = NLA_U32 },
326*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 },
327*5113495bSYour Name };
328*5113495bSYour Name 
329*5113495bSYour Name static const struct nla_policy
330*5113495bSYour Name qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1] = {
331*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 },
332*5113495bSYour Name };
333*5113495bSYour Name 
334*5113495bSYour Name static const struct nla_policy
335*5113495bSYour Name qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = {
336*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 },
337*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME] = {.type = NLA_U32 },
338*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE] = {.type = NLA_U32 },
339*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
340*5113495bSYour Name };
341*5113495bSYour Name 
342*5113495bSYour Name static const struct nla_policy
343*5113495bSYour Name qca_wlan_vendor_twt_set_param_policy[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1] = {
344*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE] = {.type = NLA_U8 },
345*5113495bSYour Name };
346*5113495bSYour Name 
347*5113495bSYour Name static
348*5113495bSYour Name int hdd_send_twt_del_dialog_cmd(struct hdd_context *hdd_ctx,
349*5113495bSYour Name 				struct wmi_twt_del_dialog_param *twt_params);
350*5113495bSYour Name 
351*5113495bSYour Name /**
352*5113495bSYour Name  * hdd_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd
353*5113495bSYour Name  * @req_type: twt setup request type
354*5113495bSYour Name  * @twt_cmd: pointer to store twt command
355*5113495bSYour Name  *
356*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
357*5113495bSYour Name  */
358*5113495bSYour Name static QDF_STATUS
hdd_twt_setup_req_type_to_cmd(u8 req_type,enum WMI_HOST_TWT_COMMAND * twt_cmd)359*5113495bSYour Name hdd_twt_setup_req_type_to_cmd(u8 req_type, enum WMI_HOST_TWT_COMMAND *twt_cmd)
360*5113495bSYour Name {
361*5113495bSYour Name 	if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST) {
362*5113495bSYour Name 		*twt_cmd = WMI_HOST_TWT_COMMAND_REQUEST_TWT;
363*5113495bSYour Name 	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST) {
364*5113495bSYour Name 		*twt_cmd = WMI_HOST_TWT_COMMAND_SUGGEST_TWT;
365*5113495bSYour Name 	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND) {
366*5113495bSYour Name 		*twt_cmd = WMI_HOST_TWT_COMMAND_DEMAND_TWT;
367*5113495bSYour Name 	} else {
368*5113495bSYour Name 		hdd_err_rl("Invalid TWT_SETUP_REQ_TYPE %d", req_type);
369*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
370*5113495bSYour Name 	}
371*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
372*5113495bSYour Name }
373*5113495bSYour Name 
374*5113495bSYour Name /**
375*5113495bSYour Name  * hdd_twt_get_add_dialog_values() - Get TWT add dialog parameter
376*5113495bSYour Name  * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
377*5113495bSYour Name  * @tb: nl attributes
378*5113495bSYour Name  * @params: wmi twt add dialog parameters
379*5113495bSYour Name  *
380*5113495bSYour Name  * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX
381*5113495bSYour Name  *
382*5113495bSYour Name  * Return: 0 or -EINVAL.
383*5113495bSYour Name  */
384*5113495bSYour Name static
hdd_twt_get_add_dialog_values(struct nlattr ** tb,struct wmi_twt_add_dialog_param * params)385*5113495bSYour Name int hdd_twt_get_add_dialog_values(struct nlattr **tb,
386*5113495bSYour Name 				  struct wmi_twt_add_dialog_param *params)
387*5113495bSYour Name {
388*5113495bSYour Name 	uint32_t wake_intvl_exp, result;
389*5113495bSYour Name 	int cmd_id;
390*5113495bSYour Name 	QDF_STATUS qdf_status;
391*5113495bSYour Name 
392*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
393*5113495bSYour Name 	if (tb[cmd_id]) {
394*5113495bSYour Name 		params->dialog_id = nla_get_u8(tb[cmd_id]);
395*5113495bSYour Name 		if (params->dialog_id > TWT_MAX_DIALOG_ID) {
396*5113495bSYour Name 			hdd_err_rl("Flow id (%u) invalid", params->dialog_id);
397*5113495bSYour Name 			return -EINVAL;
398*5113495bSYour Name 		}
399*5113495bSYour Name 	} else {
400*5113495bSYour Name 		params->dialog_id = 0;
401*5113495bSYour Name 		hdd_debug("TWT_SETUP_FLOW_ID not specified. set to zero");
402*5113495bSYour Name 	}
403*5113495bSYour Name 
404*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
405*5113495bSYour Name 	if (!tb[cmd_id]) {
406*5113495bSYour Name 		hdd_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must");
407*5113495bSYour Name 		return -EINVAL;
408*5113495bSYour Name 	}
409*5113495bSYour Name 	wake_intvl_exp = nla_get_u8(tb[cmd_id]);
410*5113495bSYour Name 	if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) {
411*5113495bSYour Name 		hdd_err_rl("Invalid wake_intvl_exp %u > %u",
412*5113495bSYour Name 			   wake_intvl_exp,
413*5113495bSYour Name 			   TWT_SETUP_WAKE_INTVL_EXP_MAX);
414*5113495bSYour Name 		return -EINVAL;
415*5113495bSYour Name 	}
416*5113495bSYour Name 
417*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
418*5113495bSYour Name 	params->flag_bcast = nla_get_flag(tb[cmd_id]);
419*5113495bSYour Name 
420*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
421*5113495bSYour Name 	if (tb[cmd_id]) {
422*5113495bSYour Name 		params->dialog_id = nla_get_u8(tb[cmd_id]);
423*5113495bSYour Name 		hdd_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id);
424*5113495bSYour Name 	}
425*5113495bSYour Name 
426*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION;
427*5113495bSYour Name 	if (tb[cmd_id]) {
428*5113495bSYour Name 		params->b_twt_recommendation = nla_get_u8(tb[cmd_id]);
429*5113495bSYour Name 		hdd_debug("TWT_SETUP_BCAST_RECOMM %d",
430*5113495bSYour Name 			  params->b_twt_recommendation);
431*5113495bSYour Name 	}
432*5113495bSYour Name 
433*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE;
434*5113495bSYour Name 	if (tb[cmd_id]) {
435*5113495bSYour Name 		params->b_twt_persistence = nla_get_u8(tb[cmd_id]);
436*5113495bSYour Name 		hdd_debug("TWT_SETUP_BCAST_PERSIS %d",
437*5113495bSYour Name 			  params->b_twt_persistence);
438*5113495bSYour Name 	}
439*5113495bSYour Name 
440*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE;
441*5113495bSYour Name 	if (!tb[cmd_id]) {
442*5113495bSYour Name 		hdd_err_rl("TWT_SETUP_REQ_TYPE is must");
443*5113495bSYour Name 		return -EINVAL;
444*5113495bSYour Name 	}
445*5113495bSYour Name 	qdf_status = hdd_twt_setup_req_type_to_cmd(nla_get_u8(tb[cmd_id]),
446*5113495bSYour Name 						   &params->twt_cmd);
447*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status))
448*5113495bSYour Name 		return qdf_status_to_os_return(qdf_status);
449*5113495bSYour Name 
450*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
451*5113495bSYour Name 	params->flag_trigger = nla_get_flag(tb[cmd_id]);
452*5113495bSYour Name 
453*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
454*5113495bSYour Name 	if (!tb[cmd_id]) {
455*5113495bSYour Name 		hdd_err_rl("TWT_SETUP_FLOW_TYPE is must");
456*5113495bSYour Name 		return -EINVAL;
457*5113495bSYour Name 	}
458*5113495bSYour Name 	params->flag_flow_type = nla_get_u8(tb[cmd_id]);
459*5113495bSYour Name 	if (params->flag_flow_type != TWT_FLOW_TYPE_ANNOUNCED &&
460*5113495bSYour Name 	    params->flag_flow_type != TWT_FLOW_TYPE_UNANNOUNCED)
461*5113495bSYour Name 		return -EINVAL;
462*5113495bSYour Name 
463*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
464*5113495bSYour Name 	params->flag_protection = nla_get_flag(tb[cmd_id]);
465*5113495bSYour Name 
466*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
467*5113495bSYour Name 	if (tb[cmd_id])
468*5113495bSYour Name 		params->sp_offset_us = nla_get_u32(tb[cmd_id]);
469*5113495bSYour Name 
470*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
471*5113495bSYour Name 	if (!tb[cmd_id]) {
472*5113495bSYour Name 		hdd_err_rl("TWT_SETUP_WAKE_DURATION is must");
473*5113495bSYour Name 		return -EINVAL;
474*5113495bSYour Name 	}
475*5113495bSYour Name 	params->wake_dura_us = TWT_WAKE_DURATION_MULTIPLICATION_FACTOR *
476*5113495bSYour Name 			       nla_get_u32(tb[cmd_id]);
477*5113495bSYour Name 	if (params->wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) {
478*5113495bSYour Name 		hdd_err_rl("Invalid wake_dura_us %u",
479*5113495bSYour Name 			   params->wake_dura_us);
480*5113495bSYour Name 		return -EINVAL;
481*5113495bSYour Name 	}
482*5113495bSYour Name 
483*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION;
484*5113495bSYour Name 	if (tb[cmd_id])
485*5113495bSYour Name 		params->min_wake_dura_us = nla_get_u32(tb[cmd_id]);
486*5113495bSYour Name 
487*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION;
488*5113495bSYour Name 	if (tb[cmd_id])
489*5113495bSYour Name 		params->max_wake_dura_us = nla_get_u32(tb[cmd_id]);
490*5113495bSYour Name 
491*5113495bSYour Name 	if (params->min_wake_dura_us > params->max_wake_dura_us) {
492*5113495bSYour Name 		hdd_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero",
493*5113495bSYour Name 			   params->min_wake_dura_us, params->max_wake_dura_us);
494*5113495bSYour Name 		params->min_wake_dura_us = 0;
495*5113495bSYour Name 		params->max_wake_dura_us = 0;
496*5113495bSYour Name 	}
497*5113495bSYour Name 
498*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
499*5113495bSYour Name 	if (!tb[cmd_id]) {
500*5113495bSYour Name 		hdd_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
501*5113495bSYour Name 		return -EINVAL;
502*5113495bSYour Name 	}
503*5113495bSYour Name 	params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
504*5113495bSYour Name 
505*5113495bSYour Name 	/*
506*5113495bSYour Name 	 * If mantissa in microsecond is present then take precedence over
507*5113495bSYour Name 	 * mantissa in TU. And send mantissa in microsecond to firmware.
508*5113495bSYour Name 	 */
509*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
510*5113495bSYour Name 	if (tb[cmd_id]) {
511*5113495bSYour Name 		params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
512*5113495bSYour Name 	}
513*5113495bSYour Name 
514*5113495bSYour Name 	if (params->wake_intvl_mantis >
515*5113495bSYour Name 	    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
516*5113495bSYour Name 		hdd_err_rl("Invalid wake_intvl_mantis %u",
517*5113495bSYour Name 			   params->wake_intvl_mantis);
518*5113495bSYour Name 		return -EINVAL;
519*5113495bSYour Name 	}
520*5113495bSYour Name 
521*5113495bSYour Name 	if (wake_intvl_exp && params->wake_intvl_mantis) {
522*5113495bSYour Name 		result = 2 << (wake_intvl_exp - 1);
523*5113495bSYour Name 		if (result >
524*5113495bSYour Name 		    (UINT_MAX / params->wake_intvl_mantis)) {
525*5113495bSYour Name 			hdd_err_rl("Invalid exp %d mantissa %d",
526*5113495bSYour Name 				   wake_intvl_exp,
527*5113495bSYour Name 				   params->wake_intvl_mantis);
528*5113495bSYour Name 			return -EINVAL;
529*5113495bSYour Name 		}
530*5113495bSYour Name 		params->wake_intvl_us =
531*5113495bSYour Name 			params->wake_intvl_mantis * result;
532*5113495bSYour Name 	} else {
533*5113495bSYour Name 		params->wake_intvl_us = params->wake_intvl_mantis;
534*5113495bSYour Name 	}
535*5113495bSYour Name 
536*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL;
537*5113495bSYour Name 	if (tb[cmd_id])
538*5113495bSYour Name 		params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]);
539*5113495bSYour Name 
540*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL;
541*5113495bSYour Name 	if (tb[cmd_id])
542*5113495bSYour Name 		params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]);
543*5113495bSYour Name 
544*5113495bSYour Name 	if (params->min_wake_intvl_us > params->max_wake_intvl_us) {
545*5113495bSYour Name 		hdd_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero",
546*5113495bSYour Name 			   params->min_wake_intvl_us,
547*5113495bSYour Name 			   params->max_wake_intvl_us);
548*5113495bSYour Name 		params->min_wake_dura_us = 0;
549*5113495bSYour Name 		params->max_wake_dura_us = 0;
550*5113495bSYour Name 	}
551*5113495bSYour Name 
552*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
553*5113495bSYour Name 	if (tb[cmd_id])
554*5113495bSYour Name 		params->wake_time_tsf = nla_get_u64(tb[cmd_id]);
555*5113495bSYour Name 	else
556*5113495bSYour Name 		params->wake_time_tsf = 0;
557*5113495bSYour Name 
558*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT;
559*5113495bSYour Name 	if (tb[cmd_id])
560*5113495bSYour Name 		params->announce_timeout_us = nla_get_u32(tb[cmd_id]);
561*5113495bSYour Name 	else
562*5113495bSYour Name 		params->announce_timeout_us = 0;
563*5113495bSYour Name 
564*5113495bSYour Name 	hdd_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d",
565*5113495bSYour Name 		  params->dialog_id, params->vdev_id, params->wake_intvl_us,
566*5113495bSYour Name 		  params->min_wake_intvl_us, params->max_wake_intvl_us,
567*5113495bSYour Name 		  params->wake_intvl_mantis);
568*5113495bSYour Name 
569*5113495bSYour Name 	hdd_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d",
570*5113495bSYour Name 		  params->wake_dura_us, params->min_wake_dura_us,
571*5113495bSYour Name 		  params->max_wake_dura_us, params->sp_offset_us,
572*5113495bSYour Name 		  params->twt_cmd);
573*5113495bSYour Name 	hdd_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d wake_tsf 0x%llx",
574*5113495bSYour Name 		  params->flag_bcast, params->flag_trigger,
575*5113495bSYour Name 		  params->flag_flow_type,
576*5113495bSYour Name 		  params->flag_protection,
577*5113495bSYour Name 		  params->wake_time_tsf);
578*5113495bSYour Name 	hdd_debug("twt: peer mac_addr "
579*5113495bSYour Name 		  QDF_MAC_ADDR_FMT,
580*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params->peer_macaddr));
581*5113495bSYour Name 	hdd_debug("twt: announce timeout(in us) %u",
582*5113495bSYour Name 		  params->announce_timeout_us);
583*5113495bSYour Name 
584*5113495bSYour Name 	return 0;
585*5113495bSYour Name }
586*5113495bSYour Name 
hdd_test_config_twt_setup_session(struct hdd_adapter * adapter,struct nlattr ** tb)587*5113495bSYour Name int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter,
588*5113495bSYour Name 				      struct nlattr **tb)
589*5113495bSYour Name {
590*5113495bSYour Name 	struct nlattr *twt_session;
591*5113495bSYour Name 	int tmp, rc;
592*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx = NULL;
593*5113495bSYour Name 	struct wmi_twt_add_dialog_param params = {0};
594*5113495bSYour Name 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
595*5113495bSYour Name 	uint32_t congestion_timeout = 0;
596*5113495bSYour Name 	int ret = 0;
597*5113495bSYour Name 	int cmd_id;
598*5113495bSYour Name 	QDF_STATUS qdf_status;
599*5113495bSYour Name 
600*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE &&
601*5113495bSYour Name 	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
602*5113495bSYour Name 		return -EOPNOTSUPP;
603*5113495bSYour Name 	}
604*5113495bSYour Name 
605*5113495bSYour Name 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
606*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
607*5113495bSYour Name 		hdd_err_rl("Invalid state, vdev %d mode %d",
608*5113495bSYour Name 			   adapter->deflink->vdev_id, adapter->device_mode);
609*5113495bSYour Name 		return -EINVAL;
610*5113495bSYour Name 	}
611*5113495bSYour Name 
612*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes,
613*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
614*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
615*5113495bSYour Name 
616*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP;
617*5113495bSYour Name 	nla_for_each_nested(twt_session, tb[cmd_id], tmp) {
618*5113495bSYour Name 		rc = wlan_cfg80211_nla_parse(tb2,
619*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
620*5113495bSYour Name 					     nla_data(twt_session),
621*5113495bSYour Name 					     nla_len(twt_session),
622*5113495bSYour Name 					     qca_wlan_vendor_twt_add_dialog_policy);
623*5113495bSYour Name 		if (rc) {
624*5113495bSYour Name 			hdd_err_rl("Invalid twt ATTR");
625*5113495bSYour Name 			return -EINVAL;
626*5113495bSYour Name 		}
627*5113495bSYour Name 
628*5113495bSYour Name 		ret = hdd_twt_get_add_dialog_values(tb2, &params);
629*5113495bSYour Name 		if (ret)
630*5113495bSYour Name 			return ret;
631*5113495bSYour Name 
632*5113495bSYour Name 		ucfg_mlme_get_twt_congestion_timeout(adapter->hdd_ctx->psoc,
633*5113495bSYour Name 						     &congestion_timeout);
634*5113495bSYour Name 		if (congestion_timeout) {
635*5113495bSYour Name 			ret = qdf_status_to_os_return(
636*5113495bSYour Name 			hdd_send_twt_requestor_disable_cmd(adapter->hdd_ctx,
637*5113495bSYour Name 							   0));
638*5113495bSYour Name 			if (ret) {
639*5113495bSYour Name 				hdd_err("Failed to disable TWT");
640*5113495bSYour Name 				return ret;
641*5113495bSYour Name 			}
642*5113495bSYour Name 
643*5113495bSYour Name 			ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0);
644*5113495bSYour Name 
645*5113495bSYour Name 			qdf_status = hdd_send_twt_requestor_enable_cmd(
646*5113495bSYour Name 							adapter->hdd_ctx);
647*5113495bSYour Name 
648*5113495bSYour Name 			ret = qdf_status_to_os_return(qdf_status);
649*5113495bSYour Name 			if (ret) {
650*5113495bSYour Name 				hdd_err("Failed to Enable TWT");
651*5113495bSYour Name 				return ret;
652*5113495bSYour Name 			}
653*5113495bSYour Name 		}
654*5113495bSYour Name 
655*5113495bSYour Name 		ret = qdf_status_to_os_return(sme_test_config_twt_setup(&params));
656*5113495bSYour Name 	}
657*5113495bSYour Name 	return ret;
658*5113495bSYour Name }
659*5113495bSYour Name 
hdd_test_config_twt_terminate_session(struct hdd_adapter * adapter,struct nlattr ** tb)660*5113495bSYour Name int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter,
661*5113495bSYour Name 					  struct nlattr **tb)
662*5113495bSYour Name {
663*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx = NULL;
664*5113495bSYour Name 	struct wmi_twt_del_dialog_param params = {0};
665*5113495bSYour Name 	int ret_val;
666*5113495bSYour Name 
667*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE &&
668*5113495bSYour Name 	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
669*5113495bSYour Name 		return -EOPNOTSUPP;
670*5113495bSYour Name 	}
671*5113495bSYour Name 
672*5113495bSYour Name 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
673*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
674*5113495bSYour Name 		hdd_err_rl("Invalid state, vdev %d mode %d",
675*5113495bSYour Name 			   adapter->deflink->vdev_id, adapter->device_mode);
676*5113495bSYour Name 		return -EINVAL;
677*5113495bSYour Name 	}
678*5113495bSYour Name 
679*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr,
680*5113495bSYour Name 		     hdd_sta_ctx->conn_info.bssid.bytes,
681*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
682*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
683*5113495bSYour Name 	params.dialog_id = 0;
684*5113495bSYour Name 	hdd_debug("twt_terminate: vdev_id %d", params.vdev_id);
685*5113495bSYour Name 
686*5113495bSYour Name 	ret_val = qdf_status_to_os_return(sme_test_config_twt_terminate(&params));
687*5113495bSYour Name 	return ret_val;
688*5113495bSYour Name }
689*5113495bSYour Name 
690*5113495bSYour Name static
hdd_twt_check_all_twt_support(struct wlan_objmgr_psoc * psoc,uint32_t dialog_id)691*5113495bSYour Name QDF_STATUS hdd_twt_check_all_twt_support(struct wlan_objmgr_psoc *psoc,
692*5113495bSYour Name 					 uint32_t dialog_id)
693*5113495bSYour Name {
694*5113495bSYour Name 	bool is_all_twt_tgt_cap_enabled = false;
695*5113495bSYour Name 	QDF_STATUS status;
696*5113495bSYour Name 
697*5113495bSYour Name 	/* Cap check is check NOT required if id is for a single session*/
698*5113495bSYour Name 	if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)
699*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
700*5113495bSYour Name 
701*5113495bSYour Name 	status = ucfg_mlme_get_twt_all_twt_tgt_cap(
702*5113495bSYour Name 						psoc,
703*5113495bSYour Name 						&is_all_twt_tgt_cap_enabled);
704*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
705*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
706*5113495bSYour Name 
707*5113495bSYour Name 	if (!is_all_twt_tgt_cap_enabled) {
708*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
709*5113495bSYour Name 		return QDF_STATUS_E_NOSUPPORT;
710*5113495bSYour Name 	}
711*5113495bSYour Name 
712*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
713*5113495bSYour Name }
714*5113495bSYour Name 
715*5113495bSYour Name /**
716*5113495bSYour Name  * hdd_twt_get_params_resp_len() - Calculates the length
717*5113495bSYour Name  * of twt get_params nl response
718*5113495bSYour Name  * @params: twt session stats parameters
719*5113495bSYour Name  *
720*5113495bSYour Name  * Return: Length of get params nl response
721*5113495bSYour Name  */
722*5113495bSYour Name static uint32_t
hdd_twt_get_params_resp_len(struct wmi_host_twt_session_stats_info * params)723*5113495bSYour Name hdd_twt_get_params_resp_len(struct wmi_host_twt_session_stats_info *params)
724*5113495bSYour Name {
725*5113495bSYour Name 	uint32_t len = nla_total_size(0);
726*5113495bSYour Name 
727*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR */
728*5113495bSYour Name 	len += nla_total_size(QDF_MAC_ADDR_SIZE);
729*5113495bSYour Name 
730*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
731*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
732*5113495bSYour Name 
733*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST */
734*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
735*5113495bSYour Name 
736*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER */
737*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
738*5113495bSYour Name 
739*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE */
740*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
741*5113495bSYour Name 
742*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION */
743*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
744*5113495bSYour Name 
745*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED */
746*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
747*5113495bSYour Name 
748*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION */
749*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
750*5113495bSYour Name 
751*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA */
752*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
753*5113495bSYour Name 
754*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/
755*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
756*5113495bSYour Name 
757*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF */
758*5113495bSYour Name 	len += nla_total_size(sizeof(u64));
759*5113495bSYour Name 
760*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE */
761*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
762*5113495bSYour Name 
763*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE */
764*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
765*5113495bSYour Name 
766*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA */
767*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
768*5113495bSYour Name 
769*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */
770*5113495bSYour Name 	if (params->pm_responder_bit_valid)
771*5113495bSYour Name 		len += nla_total_size(sizeof(u8));
772*5113495bSYour Name 
773*5113495bSYour Name 	return len;
774*5113495bSYour Name }
775*5113495bSYour Name 
776*5113495bSYour Name /**
777*5113495bSYour Name  * hdd_get_converted_twt_state() - Convert the internal twt state
778*5113495bSYour Name  * to qca_wlan_twt_setup_state type.
779*5113495bSYour Name  * @state: Internal TWT state to be converted.
780*5113495bSYour Name  *
781*5113495bSYour Name  * Return: qca_wlan_twt_setup_state type state
782*5113495bSYour Name  */
783*5113495bSYour Name static enum qca_wlan_twt_setup_state
hdd_get_converted_twt_state(enum wlan_twt_session_state state)784*5113495bSYour Name hdd_get_converted_twt_state(enum wlan_twt_session_state state)
785*5113495bSYour Name {
786*5113495bSYour Name 	switch (state) {
787*5113495bSYour Name 	case WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED:
788*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
789*5113495bSYour Name 	case WLAN_TWT_SETUP_STATE_ACTIVE:
790*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_ACTIVE;
791*5113495bSYour Name 	case WLAN_TWT_SETUP_STATE_SUSPEND:
792*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_SUSPEND;
793*5113495bSYour Name 	default:
794*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
795*5113495bSYour Name 	}
796*5113495bSYour Name }
797*5113495bSYour Name 
798*5113495bSYour Name /**
799*5113495bSYour Name  * hdd_twt_pack_get_params_resp_nlmsg()- Packs and sends twt get_params response
800*5113495bSYour Name  * @psoc: Pointer to Global psoc
801*5113495bSYour Name  * @reply_skb: pointer to response skb buffer
802*5113495bSYour Name  * @params: Pointer to twt peer session parameters
803*5113495bSYour Name  * @num_twt_session: total number of valid twt session
804*5113495bSYour Name  *
805*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
806*5113495bSYour Name  */
807*5113495bSYour Name static QDF_STATUS
hdd_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc * psoc,struct sk_buff * reply_skb,struct wmi_host_twt_session_stats_info * params,int num_twt_session)808*5113495bSYour Name hdd_twt_pack_get_params_resp_nlmsg(
809*5113495bSYour Name 				struct wlan_objmgr_psoc *psoc,
810*5113495bSYour Name 				struct sk_buff *reply_skb,
811*5113495bSYour Name 				struct wmi_host_twt_session_stats_info *params,
812*5113495bSYour Name 				int num_twt_session)
813*5113495bSYour Name {
814*5113495bSYour Name 	struct nlattr *config_attr, *nla_params;
815*5113495bSYour Name 	enum wlan_twt_session_state state;
816*5113495bSYour Name 	enum qca_wlan_twt_setup_state converted_state;
817*5113495bSYour Name 	uint64_t tsf_val;
818*5113495bSYour Name 	uint32_t wake_duration;
819*5113495bSYour Name 	uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu;
820*5113495bSYour Name 	int i, attr;
821*5113495bSYour Name 
822*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
823*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
824*5113495bSYour Name 	if (!config_attr) {
825*5113495bSYour Name 		hdd_err("TWT: get_params nla_nest_start error");
826*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
827*5113495bSYour Name 	}
828*5113495bSYour Name 
829*5113495bSYour Name 	for (i = 0; i < num_twt_session; i++) {
830*5113495bSYour Name 		if (params[i].event_type != HOST_TWT_SESSION_SETUP &&
831*5113495bSYour Name 		    params[i].event_type != HOST_TWT_SESSION_UPDATE)
832*5113495bSYour Name 			continue;
833*5113495bSYour Name 
834*5113495bSYour Name 		nla_params = nla_nest_start(reply_skb, i);
835*5113495bSYour Name 		if (!nla_params) {
836*5113495bSYour Name 			hdd_err("TWT: get_params nla_nest_start error");
837*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
838*5113495bSYour Name 		}
839*5113495bSYour Name 
840*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
841*5113495bSYour Name 		if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
842*5113495bSYour Name 			    params[i].peer_mac)) {
843*5113495bSYour Name 			hdd_err("TWT: get_params failed to put mac_addr");
844*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
845*5113495bSYour Name 		}
846*5113495bSYour Name 		hdd_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT,
847*5113495bSYour Name 			  QDF_MAC_ADDR_REF(params[i].peer_mac));
848*5113495bSYour Name 
849*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
850*5113495bSYour Name 		if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) {
851*5113495bSYour Name 			hdd_err("TWT: get_params failed to put dialog_id");
852*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
853*5113495bSYour Name 		}
854*5113495bSYour Name 
855*5113495bSYour Name 		if (params[i].bcast) {
856*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
857*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
858*5113495bSYour Name 				hdd_err("TWT: get_params fail to put bcast");
859*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
860*5113495bSYour Name 			}
861*5113495bSYour Name 		}
862*5113495bSYour Name 
863*5113495bSYour Name 		if (params[i].trig) {
864*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
865*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
866*5113495bSYour Name 				hdd_err("TWT: get_params fail to put Trigger");
867*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
868*5113495bSYour Name 			}
869*5113495bSYour Name 		}
870*5113495bSYour Name 
871*5113495bSYour Name 		if (params[i].announ) {
872*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
873*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
874*5113495bSYour Name 				hdd_err("TWT: get_params fail to put Announce");
875*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
876*5113495bSYour Name 			}
877*5113495bSYour Name 		}
878*5113495bSYour Name 
879*5113495bSYour Name 		if (params[i].protection) {
880*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
881*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
882*5113495bSYour Name 				hdd_err("TWT: get_params fail to put Protect");
883*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
884*5113495bSYour Name 			}
885*5113495bSYour Name 		}
886*5113495bSYour Name 
887*5113495bSYour Name 		if (params[i].pm_responder_bit_valid) {
888*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE;
889*5113495bSYour Name 			if (nla_put_u8(reply_skb, attr,
890*5113495bSYour Name 				       params[i].pm_responder_bit)) {
891*5113495bSYour Name 				hdd_err("TWT: fail to put pm responder mode");
892*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
893*5113495bSYour Name 			}
894*5113495bSYour Name 		}
895*5113495bSYour Name 
896*5113495bSYour Name 		if (!params[i].info_frame_disabled) {
897*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED;
898*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
899*5113495bSYour Name 				hdd_err("TWT: get_params put Info Enable fail");
900*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
901*5113495bSYour Name 			}
902*5113495bSYour Name 		}
903*5113495bSYour Name 
904*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
905*5113495bSYour Name 		wake_duration = (params[i].wake_dura_us /
906*5113495bSYour Name 				 TWT_WAKE_DURATION_MULTIPLICATION_FACTOR);
907*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, wake_duration)) {
908*5113495bSYour Name 			hdd_err("TWT: get_params failed to put Wake duration");
909*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
910*5113495bSYour Name 		}
911*5113495bSYour Name 
912*5113495bSYour Name 		wake_intvl_mantis_us = params[i].wake_intvl_us;
913*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
914*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_us)) {
915*5113495bSYour Name 			hdd_err("TWT: get_params failed to put Wake Interval in us");
916*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
917*5113495bSYour Name 		}
918*5113495bSYour Name 		wake_intvl_mantis_tu = params[i].wake_intvl_us /
919*5113495bSYour Name 				       TWT_WAKE_INTVL_MULTIPLICATION_FACTOR;
920*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
921*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) {
922*5113495bSYour Name 			hdd_err("TWT: get_params failed to put Wake Interval");
923*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
924*5113495bSYour Name 		}
925*5113495bSYour Name 
926*5113495bSYour Name 		hdd_debug("TWT: Send mantissa_us:%d, mantissa_tu:%d to userspace",
927*5113495bSYour Name 			   wake_intvl_mantis_us, wake_intvl_mantis_tu);
928*5113495bSYour Name 
929*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
930*5113495bSYour Name 		if (nla_put_u8(reply_skb, attr, 0)) {
931*5113495bSYour Name 			hdd_err("TWT: get_params put Wake Interval Exp failed");
932*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
933*5113495bSYour Name 		}
934*5113495bSYour Name 
935*5113495bSYour Name 		tsf_val = ((uint64_t)params[i].sp_tsf_us_hi << 32) |
936*5113495bSYour Name 			   params[i].sp_tsf_us_lo;
937*5113495bSYour Name 
938*5113495bSYour Name 		hdd_debug("TWT: get_params dialog_id %d TSF = 0x%llx",
939*5113495bSYour Name 			  params[i].dialog_id, tsf_val);
940*5113495bSYour Name 
941*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
942*5113495bSYour Name 		if (hdd_wlan_nla_put_u64(reply_skb, attr, tsf_val)) {
943*5113495bSYour Name 			hdd_err("TWT: get_params failed to put TSF Value");
944*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
945*5113495bSYour Name 		}
946*5113495bSYour Name 
947*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE;
948*5113495bSYour Name 		state = ucfg_mlme_get_twt_session_state(
949*5113495bSYour Name 				psoc, (struct qdf_mac_addr *)params[i].peer_mac,
950*5113495bSYour Name 				params[i].dialog_id);
951*5113495bSYour Name 		converted_state = hdd_get_converted_twt_state(state);
952*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, converted_state)) {
953*5113495bSYour Name 			hdd_err("TWT: get_params failed to put TWT state");
954*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
955*5113495bSYour Name 		}
956*5113495bSYour Name 
957*5113495bSYour Name 		nla_nest_end(reply_skb, nla_params);
958*5113495bSYour Name 	}
959*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
960*5113495bSYour Name 
961*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
962*5113495bSYour Name }
963*5113495bSYour Name 
964*5113495bSYour Name /**
965*5113495bSYour Name  * hdd_twt_pack_get_params_resp()- Obtains twt session parameters of a peer
966*5113495bSYour Name  * and sends response to the user space via nl layer
967*5113495bSYour Name  * @hdd_ctx: hdd context
968*5113495bSYour Name  * @params: Pointer to store twt peer session parameters
969*5113495bSYour Name  * @num_twt_session: number of twt session
970*5113495bSYour Name  *
971*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
972*5113495bSYour Name  */
973*5113495bSYour Name static QDF_STATUS
hdd_twt_pack_get_params_resp(struct hdd_context * hdd_ctx,struct wmi_host_twt_session_stats_info * params,int num_twt_session)974*5113495bSYour Name hdd_twt_pack_get_params_resp(struct hdd_context *hdd_ctx,
975*5113495bSYour Name 			     struct wmi_host_twt_session_stats_info *params,
976*5113495bSYour Name 			     int num_twt_session)
977*5113495bSYour Name {
978*5113495bSYour Name 	struct sk_buff *reply_skb;
979*5113495bSYour Name 	uint32_t skb_len = NLMSG_HDRLEN, i;
980*5113495bSYour Name 	QDF_STATUS qdf_status;
981*5113495bSYour Name 
982*5113495bSYour Name 	/* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */
983*5113495bSYour Name 	skb_len += NLA_HDRLEN;
984*5113495bSYour Name 
985*5113495bSYour Name 	/* Length of twt session parameters */
986*5113495bSYour Name 	for (i = 0; i < num_twt_session; i++) {
987*5113495bSYour Name 		if (params[i].event_type == HOST_TWT_SESSION_SETUP ||
988*5113495bSYour Name 		    params[i].event_type == HOST_TWT_SESSION_UPDATE)
989*5113495bSYour Name 			skb_len += hdd_twt_get_params_resp_len(params + i);
990*5113495bSYour Name 	}
991*5113495bSYour Name 
992*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
993*5113495bSYour Name 							     skb_len);
994*5113495bSYour Name 	if (!reply_skb) {
995*5113495bSYour Name 		hdd_err("TWT: get_params alloc reply skb failed");
996*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
997*5113495bSYour Name 	}
998*5113495bSYour Name 
999*5113495bSYour Name 	qdf_status = hdd_twt_pack_get_params_resp_nlmsg(hdd_ctx->psoc,
1000*5113495bSYour Name 							reply_skb, params,
1001*5113495bSYour Name 							num_twt_session);
1002*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status))
1003*5113495bSYour Name 		goto fail;
1004*5113495bSYour Name 
1005*5113495bSYour Name 	if (wlan_cfg80211_vendor_cmd_reply(reply_skb))
1006*5113495bSYour Name 		qdf_status = QDF_STATUS_E_INVAL;
1007*5113495bSYour Name 	return qdf_status;
1008*5113495bSYour Name 
1009*5113495bSYour Name fail:
1010*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(reply_skb);
1011*5113495bSYour Name 	return qdf_status;
1012*5113495bSYour Name }
1013*5113495bSYour Name 
hdd_is_twt_command_allowed(struct hdd_adapter * adapter)1014*5113495bSYour Name static int hdd_is_twt_command_allowed(struct hdd_adapter *adapter)
1015*5113495bSYour Name {
1016*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1017*5113495bSYour Name 
1018*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE &&
1019*5113495bSYour Name 	    adapter->device_mode != QDF_P2P_CLIENT_MODE)
1020*5113495bSYour Name 		return -EOPNOTSUPP;
1021*5113495bSYour Name 
1022*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
1023*5113495bSYour Name 		hdd_err_rl("Invalid state, vdev %d mode %d",
1024*5113495bSYour Name 			   adapter->deflink->vdev_id, adapter->device_mode);
1025*5113495bSYour Name 		return -EAGAIN;
1026*5113495bSYour Name 	}
1027*5113495bSYour Name 
1028*5113495bSYour Name 	if (hdd_is_roaming_in_progress(hdd_ctx))
1029*5113495bSYour Name 		return -EBUSY;
1030*5113495bSYour Name 
1031*5113495bSYour Name 	if (ucfg_scan_get_pdev_status(hdd_ctx->pdev)) {
1032*5113495bSYour Name 		hdd_err_rl("Scan in progress");
1033*5113495bSYour Name 		return -EBUSY;
1034*5113495bSYour Name 	}
1035*5113495bSYour Name 
1036*5113495bSYour Name 	return 0;
1037*5113495bSYour Name }
1038*5113495bSYour Name 
1039*5113495bSYour Name /**
1040*5113495bSYour Name  * hdd_send_inactive_session_reply  -  Send session state as inactive for
1041*5113495bSYour Name  * dialog ID for which setup is not done.
1042*5113495bSYour Name  * @adapter: hdd_adapter
1043*5113495bSYour Name  * @params: TWT session parameters
1044*5113495bSYour Name  *
1045*5113495bSYour Name  * Return: QDF_STATUS
1046*5113495bSYour Name  */
1047*5113495bSYour Name static QDF_STATUS
hdd_send_inactive_session_reply(struct hdd_adapter * adapter,struct wmi_host_twt_session_stats_info * params)1048*5113495bSYour Name hdd_send_inactive_session_reply(struct hdd_adapter *adapter,
1049*5113495bSYour Name 				struct wmi_host_twt_session_stats_info *params)
1050*5113495bSYour Name {
1051*5113495bSYour Name 	QDF_STATUS qdf_status;
1052*5113495bSYour Name 	int num_twt_session = 0;
1053*5113495bSYour Name 
1054*5113495bSYour Name 	params[num_twt_session].event_type = HOST_TWT_SESSION_UPDATE;
1055*5113495bSYour Name 	num_twt_session++;
1056*5113495bSYour Name 
1057*5113495bSYour Name 	qdf_status = hdd_twt_pack_get_params_resp(adapter->hdd_ctx, params,
1058*5113495bSYour Name 						  num_twt_session);
1059*5113495bSYour Name 
1060*5113495bSYour Name 	return qdf_status;
1061*5113495bSYour Name }
1062*5113495bSYour Name 
1063*5113495bSYour Name /**
1064*5113495bSYour Name  * hdd_twt_get_peer_session_params() - Obtains twt session parameters of a peer
1065*5113495bSYour Name  * and sends response to the user space
1066*5113495bSYour Name  * @hdd_ctx: hdd context
1067*5113495bSYour Name  * @params: Pointer to store twt peer session parameters
1068*5113495bSYour Name  *
1069*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
1070*5113495bSYour Name  */
1071*5113495bSYour Name static QDF_STATUS
hdd_twt_get_peer_session_params(struct hdd_context * hdd_ctx,struct wmi_host_twt_session_stats_info * params)1072*5113495bSYour Name hdd_twt_get_peer_session_params(struct hdd_context *hdd_ctx,
1073*5113495bSYour Name 				struct wmi_host_twt_session_stats_info *params)
1074*5113495bSYour Name {
1075*5113495bSYour Name 	int num_twt_session = 0;
1076*5113495bSYour Name 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
1077*5113495bSYour Name 
1078*5113495bSYour Name 	if (!hdd_ctx || !params)
1079*5113495bSYour Name 		return qdf_status;
1080*5113495bSYour Name 	num_twt_session = ucfg_twt_get_peer_session_params(hdd_ctx->psoc,
1081*5113495bSYour Name 							   params);
1082*5113495bSYour Name 	if (num_twt_session)
1083*5113495bSYour Name 		qdf_status = hdd_twt_pack_get_params_resp(hdd_ctx, params,
1084*5113495bSYour Name 							  num_twt_session);
1085*5113495bSYour Name 
1086*5113495bSYour Name 	return qdf_status;
1087*5113495bSYour Name }
1088*5113495bSYour Name 
1089*5113495bSYour Name /**
1090*5113495bSYour Name  * hdd_sap_twt_get_session_params() - Parses twt nl attributes, obtains twt
1091*5113495bSYour Name  * session parameters based on dialog_id and returns to user via nl layer
1092*5113495bSYour Name  * @adapter: hdd_adapter
1093*5113495bSYour Name  * @twt_param_attr: twt nl attributes
1094*5113495bSYour Name  *
1095*5113495bSYour Name  * Return: 0 on success, negative value on failure
1096*5113495bSYour Name  */
hdd_sap_twt_get_session_params(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)1097*5113495bSYour Name static int hdd_sap_twt_get_session_params(struct hdd_adapter *adapter,
1098*5113495bSYour Name 					  struct nlattr *twt_param_attr)
1099*5113495bSYour Name {
1100*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1101*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1102*5113495bSYour Name 	int max_num_peer;
1103*5113495bSYour Name 	struct wmi_host_twt_session_stats_info *params;
1104*5113495bSYour Name 	int ret, id, id1;
1105*5113495bSYour Name 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
1106*5113495bSYour Name 	struct qdf_mac_addr mac_addr;
1107*5113495bSYour Name 	bool is_associated;
1108*5113495bSYour Name 
1109*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(
1110*5113495bSYour Name 					tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1111*5113495bSYour Name 					twt_param_attr,
1112*5113495bSYour Name 					qca_wlan_vendor_twt_add_dialog_policy);
1113*5113495bSYour Name 	if (ret)
1114*5113495bSYour Name 		return ret;
1115*5113495bSYour Name 
1116*5113495bSYour Name 	max_num_peer = hdd_ctx->wiphy->max_ap_assoc_sta;
1117*5113495bSYour Name 	params = qdf_mem_malloc(TWT_PEER_MAX_SESSIONS * max_num_peer *
1118*5113495bSYour Name 				sizeof(*params));
1119*5113495bSYour Name 
1120*5113495bSYour Name 	if (!params)
1121*5113495bSYour Name 		return -ENOMEM;
1122*5113495bSYour Name 
1123*5113495bSYour Name 	params[0].vdev_id = adapter->deflink->vdev_id;
1124*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1125*5113495bSYour Name 	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1126*5113495bSYour Name 
1127*5113495bSYour Name 	if (tb[id] && tb[id1]) {
1128*5113495bSYour Name 		params[0].dialog_id = nla_get_u8(tb[id]);
1129*5113495bSYour Name 		nla_memcpy(params[0].peer_mac, tb[id1], QDF_MAC_ADDR_SIZE);
1130*5113495bSYour Name 	} else {
1131*5113495bSYour Name 		hdd_err_rl("TWT: get_params dialog_id or mac_addr is missing");
1132*5113495bSYour Name 		goto done;
1133*5113495bSYour Name 	}
1134*5113495bSYour Name 
1135*5113495bSYour Name 	if (QDF_IS_ADDR_BROADCAST(params[0].peer_mac) &&
1136*5113495bSYour Name 	    params[0].dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) {
1137*5113495bSYour Name 		hdd_err_rl("TWT: get_params dialog_is is invalid");
1138*5113495bSYour Name 		goto done;
1139*5113495bSYour Name 	}
1140*5113495bSYour Name 
1141*5113495bSYour Name 	if (!params[0].dialog_id)
1142*5113495bSYour Name 		params[0].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
1143*5113495bSYour Name 
1144*5113495bSYour Name 	qdf_mem_copy(mac_addr.bytes, params[0].peer_mac, QDF_MAC_ADDR_SIZE);
1145*5113495bSYour Name 
1146*5113495bSYour Name 	if (!qdf_is_macaddr_broadcast(&mac_addr)) {
1147*5113495bSYour Name 		is_associated = hdd_is_peer_associated(adapter, &mac_addr);
1148*5113495bSYour Name 		if (!is_associated) {
1149*5113495bSYour Name 			hdd_err("TWT: Association doesn't exist for STA: "
1150*5113495bSYour Name 				   QDF_MAC_ADDR_FMT,
1151*5113495bSYour Name 				   QDF_MAC_ADDR_REF(&mac_addr));
1152*5113495bSYour Name 			goto done;
1153*5113495bSYour Name 		}
1154*5113495bSYour Name 	}
1155*5113495bSYour Name 
1156*5113495bSYour Name 	hdd_debug("TWT: get_params dialog_id %d and mac_addr " QDF_MAC_ADDR_FMT,
1157*5113495bSYour Name 		  params[0].dialog_id, QDF_MAC_ADDR_REF(params[0].peer_mac));
1158*5113495bSYour Name 
1159*5113495bSYour Name 	qdf_status = hdd_twt_get_peer_session_params(adapter->hdd_ctx,
1160*5113495bSYour Name 						     &params[0]);
1161*5113495bSYour Name done:
1162*5113495bSYour Name 	qdf_mem_free(params);
1163*5113495bSYour Name 	return qdf_status_to_os_return(qdf_status);
1164*5113495bSYour Name }
1165*5113495bSYour Name 
1166*5113495bSYour Name /**
1167*5113495bSYour Name  * hdd_sta_twt_get_session_params() - Parses twt nl attributes, obtains twt
1168*5113495bSYour Name  * session parameters based on dialog_id and returns to user via nl layer
1169*5113495bSYour Name  * @adapter: hdd_adapter
1170*5113495bSYour Name  * @twt_param_attr: twt nl attributes
1171*5113495bSYour Name  *
1172*5113495bSYour Name  * Return: 0 on success, negative value on failure
1173*5113495bSYour Name  */
hdd_sta_twt_get_session_params(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)1174*5113495bSYour Name static int hdd_sta_twt_get_session_params(struct hdd_adapter *adapter,
1175*5113495bSYour Name 					  struct nlattr *twt_param_attr)
1176*5113495bSYour Name {
1177*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
1178*5113495bSYour Name 				WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
1179*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1180*5113495bSYour Name 	struct wmi_host_twt_session_stats_info
1181*5113495bSYour Name 				params[TWT_PSOC_MAX_SESSIONS] = { {0} };
1182*5113495bSYour Name 	int ret, id;
1183*5113495bSYour Name 	QDF_STATUS qdf_status;
1184*5113495bSYour Name 	struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
1185*5113495bSYour Name 
1186*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
1187*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1188*5113495bSYour Name 					     twt_param_attr,
1189*5113495bSYour Name 					     qca_wlan_vendor_twt_add_dialog_policy);
1190*5113495bSYour Name 	if (ret)
1191*5113495bSYour Name 		return ret;
1192*5113495bSYour Name 
1193*5113495bSYour Name 	params[0].vdev_id = adapter->deflink->vdev_id;
1194*5113495bSYour Name 	/*
1195*5113495bSYour Name 	 * Currently twt_get_params nl cmd is sending only dialog_id(STA), fill
1196*5113495bSYour Name 	 * mac_addr of STA in params and call hdd_twt_get_peer_session_params.
1197*5113495bSYour Name 	 * When twt_get_params passes mac_addr and dialog_id of STA/SAP, update
1198*5113495bSYour Name 	 * both mac_addr and dialog_id in params before calling
1199*5113495bSYour Name 	 * hdd_twt_get_peer_session_params. dialog_id if not received,
1200*5113495bSYour Name 	 * dialog_id of value 0 will be used as default.
1201*5113495bSYour Name 	 */
1202*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1203*5113495bSYour Name 	if (tb[id])
1204*5113495bSYour Name 		params[0].dialog_id = (uint32_t)nla_get_u8(tb[id]);
1205*5113495bSYour Name 	else
1206*5113495bSYour Name 		params[0].dialog_id = 0;
1207*5113495bSYour Name 
1208*5113495bSYour Name 	if (params[0].dialog_id <= TWT_MAX_DIALOG_ID) {
1209*5113495bSYour Name 		qdf_mem_copy(params[0].peer_mac,
1210*5113495bSYour Name 			     hdd_sta_ctx->conn_info.bssid.bytes,
1211*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
1212*5113495bSYour Name 		hdd_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT,
1213*5113495bSYour Name 			  QDF_MAC_ADDR_REF(params[0].peer_mac));
1214*5113495bSYour Name 	} else {
1215*5113495bSYour Name 		qdf_mem_copy(params[0].peer_mac, &bcast_addr,
1216*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
1217*5113495bSYour Name 	}
1218*5113495bSYour Name 
1219*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
1220*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
1221*5113495bSYour Name 					 params[0].dialog_id)) {
1222*5113495bSYour Name 		hdd_debug("vdev%d: TWT session %d setup incomplete",
1223*5113495bSYour Name 			  adapter->deflink->vdev_id, params[0].dialog_id);
1224*5113495bSYour Name 		qdf_status = hdd_send_inactive_session_reply(adapter, params);
1225*5113495bSYour Name 
1226*5113495bSYour Name 		return qdf_status_to_os_return(qdf_status);
1227*5113495bSYour Name 	}
1228*5113495bSYour Name 
1229*5113495bSYour Name 	hdd_debug("TWT: get_params dialog_id %d and mac_addr " QDF_MAC_ADDR_FMT,
1230*5113495bSYour Name 		  params[0].dialog_id, QDF_MAC_ADDR_REF(params[0].peer_mac));
1231*5113495bSYour Name 
1232*5113495bSYour Name 	qdf_status = hdd_twt_get_peer_session_params(adapter->hdd_ctx,
1233*5113495bSYour Name 						     &params[0]);
1234*5113495bSYour Name 
1235*5113495bSYour Name 	return qdf_status_to_os_return(qdf_status);
1236*5113495bSYour Name }
1237*5113495bSYour Name 
1238*5113495bSYour Name /**
1239*5113495bSYour Name  * hdd_twt_get_session_params() - Parses twt nl attributes, obtains twt
1240*5113495bSYour Name  * session parameters based on dialog_id and returns to user via nl layer
1241*5113495bSYour Name  * @adapter: hdd_adapter
1242*5113495bSYour Name  * @twt_param_attr: twt nl attributes
1243*5113495bSYour Name  *
1244*5113495bSYour Name  * Return: 0 on success, negative value on failure
1245*5113495bSYour Name  */
hdd_twt_get_session_params(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)1246*5113495bSYour Name static int hdd_twt_get_session_params(struct hdd_adapter *adapter,
1247*5113495bSYour Name 				      struct nlattr *twt_param_attr)
1248*5113495bSYour Name {
1249*5113495bSYour Name 	enum QDF_OPMODE device_mode = adapter->device_mode;
1250*5113495bSYour Name 
1251*5113495bSYour Name 	switch (device_mode) {
1252*5113495bSYour Name 	case QDF_STA_MODE:
1253*5113495bSYour Name 		return hdd_sta_twt_get_session_params(adapter, twt_param_attr);
1254*5113495bSYour Name 	case QDF_SAP_MODE:
1255*5113495bSYour Name 		return hdd_sap_twt_get_session_params(adapter, twt_param_attr);
1256*5113495bSYour Name 	default:
1257*5113495bSYour Name 		hdd_err_rl("TWT get session params is not supported on %s",
1258*5113495bSYour Name 			   qdf_opmode_str(adapter->device_mode));
1259*5113495bSYour Name 	}
1260*5113495bSYour Name 
1261*5113495bSYour Name 	return -EOPNOTSUPP;
1262*5113495bSYour Name }
1263*5113495bSYour Name 
1264*5113495bSYour Name /**
1265*5113495bSYour Name  * hdd_get_twt_setup_event_len() - Calculates the length of twt
1266*5113495bSYour Name  * setup nl response
1267*5113495bSYour Name  * @ev_params: event parameters, contains info that what parameters need
1268*5113495bSYour Name  * to send in twt setup response.
1269*5113495bSYour Name  *
1270*5113495bSYour Name  * Return: Length of twt setup nl response
1271*5113495bSYour Name  */
1272*5113495bSYour Name static uint32_t
hdd_get_twt_setup_event_len(struct wma_twt_add_dialog_complete_event * ev_params)1273*5113495bSYour Name hdd_get_twt_setup_event_len(struct wma_twt_add_dialog_complete_event *ev_params)
1274*5113495bSYour Name {
1275*5113495bSYour Name 	uint32_t len = 0;
1276*5113495bSYour Name 
1277*5113495bSYour Name 	len += NLMSG_HDRLEN;
1278*5113495bSYour Name 
1279*5113495bSYour Name 	/* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */
1280*5113495bSYour Name 	len += NLA_HDRLEN;
1281*5113495bSYour Name 
1282*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */
1283*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1284*5113495bSYour Name 
1285*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
1286*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1287*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
1288*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1289*5113495bSYour Name 
1290*5113495bSYour Name 	if (!ev_params->params.num_additional_twt_params)
1291*5113495bSYour Name 		return len;
1292*5113495bSYour Name 
1293*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE */
1294*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1295*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE*/
1296*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1297*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION*/
1298*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1299*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA*/
1300*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1301*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/
1302*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1303*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF*/
1304*5113495bSYour Name 	len += nla_total_size(sizeof(u64));
1305*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME*/
1306*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1307*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER*/
1308*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1309*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION*/
1310*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1311*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST*/
1312*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1313*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED*/
1314*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1315*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
1316*5113495bSYour Name 	len += nla_total_size(QDF_MAC_ADDR_SIZE);
1317*5113495bSYour Name 	if (ev_params->additional_params.pm_responder_bit_valid)
1318*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */
1319*5113495bSYour Name 		len += nla_total_size(sizeof(u8));
1320*5113495bSYour Name 
1321*5113495bSYour Name 	return len;
1322*5113495bSYour Name }
1323*5113495bSYour Name 
1324*5113495bSYour Name /**
1325*5113495bSYour Name  * wmi_twt_resume_status_to_vendor_twt_status() - convert from
1326*5113495bSYour Name  * WMI_HOST_RESUME_TWT_STATUS to qca_wlan_vendor_twt_status
1327*5113495bSYour Name  * @status: WMI_HOST_RESUME_TWT_STATUS value from firmware
1328*5113495bSYour Name  *
1329*5113495bSYour Name  * Return: qca_wlan_vendor_twt_status values corresponding
1330*5113495bSYour Name  * to the firmware failure status
1331*5113495bSYour Name  */
1332*5113495bSYour Name static int
wmi_twt_resume_status_to_vendor_twt_status(enum WMI_HOST_RESUME_TWT_STATUS status)1333*5113495bSYour Name wmi_twt_resume_status_to_vendor_twt_status(enum WMI_HOST_RESUME_TWT_STATUS status)
1334*5113495bSYour Name {
1335*5113495bSYour Name 	switch (status) {
1336*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_OK:
1337*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1338*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_NOT_EXIST:
1339*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
1340*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_INVALID_PARAM:
1341*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1342*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_BUSY:
1343*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
1344*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_NOT_PAUSED:
1345*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED;
1346*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_NO_RESOURCE:
1347*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
1348*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_NO_ACK:
1349*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
1350*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_UNKNOWN_ERROR:
1351*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1352*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_CHAN_SW_IN_PROGRESS:
1353*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
1354*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_ROAM_IN_PROGRESS:
1355*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
1356*5113495bSYour Name 	case WMI_HOST_RESUME_TWT_STATUS_SCAN_IN_PROGRESS:
1357*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
1358*5113495bSYour Name 	default:
1359*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1360*5113495bSYour Name 	}
1361*5113495bSYour Name }
1362*5113495bSYour Name 
1363*5113495bSYour Name /**
1364*5113495bSYour Name  * wmi_twt_pause_status_to_vendor_twt_status() - convert from
1365*5113495bSYour Name  * WMI_HOST_PAUSE_TWT_STATUS to qca_wlan_vendor_twt_status
1366*5113495bSYour Name  * @status: WMI_HOST_PAUSE_TWT_STATUS value from firmware
1367*5113495bSYour Name  *
1368*5113495bSYour Name  * Return: qca_wlan_vendor_twt_status values corresponding
1369*5113495bSYour Name  * to the firmware failure status
1370*5113495bSYour Name  */
1371*5113495bSYour Name static int
wmi_twt_pause_status_to_vendor_twt_status(enum WMI_HOST_PAUSE_TWT_STATUS status)1372*5113495bSYour Name wmi_twt_pause_status_to_vendor_twt_status(enum WMI_HOST_PAUSE_TWT_STATUS status)
1373*5113495bSYour Name {
1374*5113495bSYour Name 	switch (status) {
1375*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_OK:
1376*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1377*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_NOT_EXIST:
1378*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
1379*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_INVALID_PARAM:
1380*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1381*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_BUSY:
1382*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
1383*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_ALREADY_PAUSED:
1384*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED;
1385*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_NO_RESOURCE:
1386*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
1387*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_NO_ACK:
1388*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
1389*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_UNKNOWN_ERROR:
1390*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1391*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_CHAN_SW_IN_PROGRESS:
1392*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
1393*5113495bSYour Name 	case WMI_HOST_PAUSE_TWT_STATUS_ROAM_IN_PROGRESS:
1394*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
1395*5113495bSYour Name 	default:
1396*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1397*5113495bSYour Name 	}
1398*5113495bSYour Name }
1399*5113495bSYour Name 
1400*5113495bSYour Name /**
1401*5113495bSYour Name  * wmi_twt_nudge_status_to_vendor_twt_status() - convert from
1402*5113495bSYour Name  * WMI_HOST_NUDGE_TWT_STATUS to qca_wlan_vendor_twt_status
1403*5113495bSYour Name  * @status: WMI_HOST_NUDGE_TWT_STATUS value from firmware
1404*5113495bSYour Name  *
1405*5113495bSYour Name  * Return: qca_wlan_vendor_twt_status values corresponding
1406*5113495bSYour Name  * to the firmware failure status
1407*5113495bSYour Name  */
1408*5113495bSYour Name static int
wmi_twt_nudge_status_to_vendor_twt_status(enum WMI_HOST_NUDGE_TWT_STATUS status)1409*5113495bSYour Name wmi_twt_nudge_status_to_vendor_twt_status(enum WMI_HOST_NUDGE_TWT_STATUS status)
1410*5113495bSYour Name {
1411*5113495bSYour Name 	switch (status) {
1412*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_OK:
1413*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1414*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_NOT_EXIST:
1415*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
1416*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_INVALID_PARAM:
1417*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1418*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_BUSY:
1419*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
1420*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_NO_RESOURCE:
1421*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
1422*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_NO_ACK:
1423*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
1424*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_UNKNOWN_ERROR:
1425*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1426*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_ALREADY_PAUSED:
1427*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED;
1428*5113495bSYour Name 	case WMI_HOST_NUDGE_TWT_STATUS_CHAN_SW_IN_PROGRESS:
1429*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
1430*5113495bSYour Name 	default:
1431*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1432*5113495bSYour Name 	}
1433*5113495bSYour Name }
1434*5113495bSYour Name 
1435*5113495bSYour Name /**
1436*5113495bSYour Name  * wmi_twt_add_cmd_to_vendor_twt_resp_type() - convert from
1437*5113495bSYour Name  * WMI_HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type
1438*5113495bSYour Name  * @type: WMI_HOST_TWT_COMMAND value from firmware
1439*5113495bSYour Name  *
1440*5113495bSYour Name  * Return: qca_wlan_vendor_twt_setup_resp_type values for valid
1441*5113495bSYour Name  * WMI_HOST_TWT_COMMAND value and -EINVAL for invalid value
1442*5113495bSYour Name  */
1443*5113495bSYour Name static
wmi_twt_add_cmd_to_vendor_twt_resp_type(enum WMI_HOST_TWT_COMMAND type)1444*5113495bSYour Name int wmi_twt_add_cmd_to_vendor_twt_resp_type(enum WMI_HOST_TWT_COMMAND type)
1445*5113495bSYour Name {
1446*5113495bSYour Name 	switch (type) {
1447*5113495bSYour Name 	case WMI_HOST_TWT_COMMAND_ACCEPT_TWT:
1448*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_RESP_ACCEPT;
1449*5113495bSYour Name 	case WMI_HOST_TWT_COMMAND_ALTERNATE_TWT:
1450*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE;
1451*5113495bSYour Name 	case WMI_HOST_TWT_COMMAND_DICTATE_TWT:
1452*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_RESP_DICTATE;
1453*5113495bSYour Name 	case WMI_HOST_TWT_COMMAND_REJECT_TWT:
1454*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_RESP_REJECT;
1455*5113495bSYour Name 	default:
1456*5113495bSYour Name 		return -EINVAL;
1457*5113495bSYour Name 	}
1458*5113495bSYour Name }
1459*5113495bSYour Name 
1460*5113495bSYour Name /**
1461*5113495bSYour Name  * wmi_twt_del_status_to_vendor_twt_status() - convert from
1462*5113495bSYour Name  * WMI_HOST_DEL_TWT_STATUS to qca_wlan_vendor_twt_status
1463*5113495bSYour Name  * @status: WMI_HOST_DEL_TWT_STATUS value from firmware
1464*5113495bSYour Name  *
1465*5113495bSYour Name  * Return: qca_wlan_vendor_twt_status values corresponding
1466*5113495bSYour Name  * to the firmware failure status
1467*5113495bSYour Name  */
1468*5113495bSYour Name static
wmi_twt_del_status_to_vendor_twt_status(enum WMI_HOST_DEL_TWT_STATUS status)1469*5113495bSYour Name int wmi_twt_del_status_to_vendor_twt_status(enum WMI_HOST_DEL_TWT_STATUS status)
1470*5113495bSYour Name {
1471*5113495bSYour Name 	switch (status) {
1472*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_OK:
1473*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1474*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_NOT_EXIST:
1475*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
1476*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_INVALID_PARAM:
1477*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1478*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_BUSY:
1479*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
1480*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_NO_RESOURCE:
1481*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
1482*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_NO_ACK:
1483*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
1484*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR:
1485*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1486*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_PEER_INIT_TEARDOWN:
1487*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE;
1488*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_ROAMING:
1489*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE;
1490*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_CONCURRENCY:
1491*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE;
1492*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_CHAN_SW_IN_PROGRESS:
1493*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
1494*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_SCAN_IN_PROGRESS:
1495*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
1496*5113495bSYour Name 	case WMI_HOST_DEL_TWT_STATUS_PS_DISABLE_TEARDOWN:
1497*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE;
1498*5113495bSYour Name 	default:
1499*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1500*5113495bSYour Name 	}
1501*5113495bSYour Name }
1502*5113495bSYour Name 
1503*5113495bSYour Name /**
1504*5113495bSYour Name  * wmi_twt_add_status_to_vendor_twt_status() - convert from
1505*5113495bSYour Name  * WMI_HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status
1506*5113495bSYour Name  * @status: WMI_HOST_ADD_TWT_STATUS value from firmware
1507*5113495bSYour Name  *
1508*5113495bSYour Name  * Return: qca_wlan_vendor_twt_status values corresponding
1509*5113495bSYour Name  * to WMI_HOST_ADD_TWT_STATUS.
1510*5113495bSYour Name  */
1511*5113495bSYour Name static enum qca_wlan_vendor_twt_status
wmi_twt_add_status_to_vendor_twt_status(enum WMI_HOST_ADD_TWT_STATUS status)1512*5113495bSYour Name wmi_twt_add_status_to_vendor_twt_status(enum WMI_HOST_ADD_TWT_STATUS status)
1513*5113495bSYour Name {
1514*5113495bSYour Name 	switch (status) {
1515*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_OK:
1516*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1517*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
1518*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED;
1519*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
1520*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID;
1521*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_INVALID_PARAM:
1522*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1523*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_NOT_READY:
1524*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY;
1525*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_NO_RESOURCE:
1526*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
1527*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_NO_ACK:
1528*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
1529*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_NO_RESPONSE:
1530*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE;
1531*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_DENIED:
1532*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_DENIED;
1533*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
1534*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1535*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_AP_PARAMS_NOT_IN_RANGE:
1536*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE;
1537*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_AP_IE_VALIDATION_FAILED:
1538*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID;
1539*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
1540*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
1541*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
1542*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
1543*5113495bSYour Name 	case WMI_HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
1544*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
1545*5113495bSYour Name 	default:
1546*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1547*5113495bSYour Name 	}
1548*5113495bSYour Name }
1549*5113495bSYour Name 
1550*5113495bSYour Name /**
1551*5113495bSYour Name  * hdd_twt_setup_pack_resp_nlmsg() - pack nlmsg response for setup
1552*5113495bSYour Name  * @reply_skb: pointer to the response skb structure
1553*5113495bSYour Name  * @event: twt event buffer with firmware response
1554*5113495bSYour Name  *
1555*5113495bSYour Name  * Pack the nl response with parameters and additional parameters
1556*5113495bSYour Name  * received from firmware.
1557*5113495bSYour Name  * Firmware sends additional parameters only for 2 conditions
1558*5113495bSYour Name  * 1) TWT Negotiation is accepted by AP - Firmware sends
1559*5113495bSYour Name  * QCA_WLAN_VENDOR_TWT_STATUS_OK with appropriate response type
1560*5113495bSYour Name  * in additional parameters
1561*5113495bSYour Name  * 2) AP has proposed Alternate values - In this case firmware sends
1562*5113495bSYour Name  * QCA_WLAN_VENDOR_TWT_STATUS_DENIED with appropriate response type
1563*5113495bSYour Name  * in additional parameters
1564*5113495bSYour Name  *
1565*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
1566*5113495bSYour Name  * on failure
1567*5113495bSYour Name  */
1568*5113495bSYour Name static QDF_STATUS
hdd_twt_setup_pack_resp_nlmsg(struct sk_buff * reply_skb,struct wma_twt_add_dialog_complete_event * event)1569*5113495bSYour Name hdd_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb,
1570*5113495bSYour Name 			      struct wma_twt_add_dialog_complete_event *event)
1571*5113495bSYour Name {
1572*5113495bSYour Name 	struct nlattr *config_attr;
1573*5113495bSYour Name 	uint64_t sp_offset_tsf;
1574*5113495bSYour Name 	enum qca_wlan_vendor_twt_status vendor_status;
1575*5113495bSYour Name 	int response_type, attr;
1576*5113495bSYour Name 	uint32_t wake_duration;
1577*5113495bSYour Name 	uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu;
1578*5113495bSYour Name 
1579*5113495bSYour Name 	hdd_enter();
1580*5113495bSYour Name 
1581*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
1582*5113495bSYour Name 		       QCA_WLAN_TWT_SET)) {
1583*5113495bSYour Name 		hdd_err("Failed to put TWT operation");
1584*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1585*5113495bSYour Name 	}
1586*5113495bSYour Name 
1587*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
1588*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
1589*5113495bSYour Name 	if (!config_attr) {
1590*5113495bSYour Name 		hdd_err("nla_nest_start error");
1591*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1592*5113495bSYour Name 	}
1593*5113495bSYour Name 
1594*5113495bSYour Name 	sp_offset_tsf = event->additional_params.sp_tsf_us_hi;
1595*5113495bSYour Name 	sp_offset_tsf = (sp_offset_tsf << 32) |
1596*5113495bSYour Name 			 event->additional_params.sp_tsf_us_lo;
1597*5113495bSYour Name 
1598*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1599*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, event->params.dialog_id)) {
1600*5113495bSYour Name 		hdd_err("Failed to put dialog_id");
1601*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1602*5113495bSYour Name 	}
1603*5113495bSYour Name 
1604*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
1605*5113495bSYour Name 	vendor_status = wmi_twt_add_status_to_vendor_twt_status(
1606*5113495bSYour Name 							event->params.status);
1607*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, vendor_status)) {
1608*5113495bSYour Name 		hdd_err("Failed to put setup status");
1609*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1610*5113495bSYour Name 	}
1611*5113495bSYour Name 
1612*5113495bSYour Name 	if (event->params.num_additional_twt_params == 0) {
1613*5113495bSYour Name 		nla_nest_end(reply_skb, config_attr);
1614*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
1615*5113495bSYour Name 	}
1616*5113495bSYour Name 
1617*5113495bSYour Name 	response_type = wmi_twt_add_cmd_to_vendor_twt_resp_type(
1618*5113495bSYour Name 					event->additional_params.twt_cmd);
1619*5113495bSYour Name 	if (response_type == -EINVAL) {
1620*5113495bSYour Name 		hdd_err("Invalid response type from firmware");
1621*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1622*5113495bSYour Name 	}
1623*5113495bSYour Name 
1624*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE;
1625*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, response_type)) {
1626*5113495bSYour Name 		hdd_err("Failed to put setup response type");
1627*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1628*5113495bSYour Name 	}
1629*5113495bSYour Name 
1630*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
1631*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, event->additional_params.announce)) {
1632*5113495bSYour Name 		hdd_err("Failed to put setup flow type");
1633*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1634*5113495bSYour Name 	}
1635*5113495bSYour Name 
1636*5113495bSYour Name 	hdd_debug("wake_dur_us %d", event->additional_params.wake_dur_us);
1637*5113495bSYour Name 	wake_duration = (event->additional_params.wake_dur_us /
1638*5113495bSYour Name 			 TWT_WAKE_DURATION_MULTIPLICATION_FACTOR);
1639*5113495bSYour Name 
1640*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
1641*5113495bSYour Name 	if (nla_put_u32(reply_skb, attr, wake_duration)) {
1642*5113495bSYour Name 		hdd_err("Failed to put wake duration");
1643*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1644*5113495bSYour Name 	}
1645*5113495bSYour Name 
1646*5113495bSYour Name 	wake_intvl_mantis_us = event->additional_params.wake_intvl_us;
1647*5113495bSYour Name 	if (nla_put_u32(reply_skb,
1648*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA,
1649*5113495bSYour Name 			wake_intvl_mantis_us)) {
1650*5113495bSYour Name 		hdd_err("Failed to put wake interval mantissa in us");
1651*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1652*5113495bSYour Name 	}
1653*5113495bSYour Name 
1654*5113495bSYour Name 	wake_intvl_mantis_tu = (event->additional_params.wake_intvl_us /
1655*5113495bSYour Name 				 TWT_WAKE_INTVL_MULTIPLICATION_FACTOR);
1656*5113495bSYour Name 
1657*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
1658*5113495bSYour Name 	if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) {
1659*5113495bSYour Name 		hdd_err("Failed to put wake interval mantissa in tu");
1660*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1661*5113495bSYour Name 	}
1662*5113495bSYour Name 	hdd_debug("Send mantissa_us:%d, mantissa_tu:%d to userspace",
1663*5113495bSYour Name 		  wake_intvl_mantis_us, wake_intvl_mantis_tu);
1664*5113495bSYour Name 
1665*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
1666*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, 0)) {
1667*5113495bSYour Name 		hdd_err("Failed to put wake interval exp");
1668*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1669*5113495bSYour Name 	}
1670*5113495bSYour Name 
1671*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
1672*5113495bSYour Name 	if (wlan_cfg80211_nla_put_u64(reply_skb, attr, sp_offset_tsf)) {
1673*5113495bSYour Name 		hdd_err("Failed to put sp_offset_tsf");
1674*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1675*5113495bSYour Name 	}
1676*5113495bSYour Name 
1677*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
1678*5113495bSYour Name 	if (nla_put_u32(reply_skb, attr,
1679*5113495bSYour Name 			event->additional_params.sp_offset_us)) {
1680*5113495bSYour Name 		hdd_err("Failed to put sp_offset_us");
1681*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1682*5113495bSYour Name 	}
1683*5113495bSYour Name 
1684*5113495bSYour Name 	if (event->additional_params.trig_en) {
1685*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
1686*5113495bSYour Name 		if (nla_put_flag(reply_skb, attr)) {
1687*5113495bSYour Name 			hdd_err("Failed to put trig type");
1688*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1689*5113495bSYour Name 		}
1690*5113495bSYour Name 	}
1691*5113495bSYour Name 
1692*5113495bSYour Name 	if (event->additional_params.protection) {
1693*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
1694*5113495bSYour Name 		if (nla_put_flag(reply_skb, attr)) {
1695*5113495bSYour Name 			hdd_err("Failed to put protection flag");
1696*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1697*5113495bSYour Name 		}
1698*5113495bSYour Name 	}
1699*5113495bSYour Name 
1700*5113495bSYour Name 	if (event->additional_params.bcast) {
1701*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
1702*5113495bSYour Name 		if (nla_put_flag(reply_skb, attr)) {
1703*5113495bSYour Name 			hdd_err("Failed to put bcast flag");
1704*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1705*5113495bSYour Name 		}
1706*5113495bSYour Name 	}
1707*5113495bSYour Name 	if (event->additional_params.pm_responder_bit_valid) {
1708*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE;
1709*5113495bSYour Name 		if (nla_put_u8(reply_skb, attr,
1710*5113495bSYour Name 			       event->additional_params.pm_responder_bit)) {
1711*5113495bSYour Name 			hdd_err("Failed to put pm responder mode");
1712*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1713*5113495bSYour Name 		}
1714*5113495bSYour Name 	}
1715*5113495bSYour Name 
1716*5113495bSYour Name 	if (!event->additional_params.info_frame_disabled) {
1717*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED;
1718*5113495bSYour Name 		if (nla_put_flag(reply_skb, attr)) {
1719*5113495bSYour Name 			hdd_err("Failed to put twt info enable flag");
1720*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
1721*5113495bSYour Name 		}
1722*5113495bSYour Name 	}
1723*5113495bSYour Name 
1724*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1725*5113495bSYour Name 	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
1726*5113495bSYour Name 		    event->params.peer_macaddr)) {
1727*5113495bSYour Name 		hdd_err("Failed to put mac_addr");
1728*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1729*5113495bSYour Name 	}
1730*5113495bSYour Name 
1731*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
1732*5113495bSYour Name 
1733*5113495bSYour Name 	hdd_exit();
1734*5113495bSYour Name 
1735*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1736*5113495bSYour Name }
1737*5113495bSYour Name 
1738*5113495bSYour Name /**
1739*5113495bSYour Name  * hdd_send_twt_setup_response  - Send TWT setup response to userspace
1740*5113495bSYour Name  * @adapter: Pointer to HDD adapter. This pointer is expected to
1741*5113495bSYour Name  * be validated by the caller.
1742*5113495bSYour Name  * @add_dialog_comp_ev_params: Add dialog completion event structure
1743*5113495bSYour Name  *
1744*5113495bSYour Name  * Return: QDF_STATUS
1745*5113495bSYour Name  */
hdd_send_twt_setup_response(struct hdd_adapter * adapter,struct wma_twt_add_dialog_complete_event * add_dialog_comp_ev_params)1746*5113495bSYour Name static QDF_STATUS hdd_send_twt_setup_response(
1747*5113495bSYour Name 		struct hdd_adapter *adapter,
1748*5113495bSYour Name 		struct wma_twt_add_dialog_complete_event *add_dialog_comp_ev_params)
1749*5113495bSYour Name {
1750*5113495bSYour Name 	struct hdd_context *hdd_ctx;
1751*5113495bSYour Name 	struct sk_buff *twt_vendor_event;
1752*5113495bSYour Name 	struct wireless_dev *wdev = adapter->dev->ieee80211_ptr;
1753*5113495bSYour Name 	size_t data_len;
1754*5113495bSYour Name 	QDF_STATUS status;
1755*5113495bSYour Name 
1756*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1757*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
1758*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
1759*5113495bSYour Name 		return status;
1760*5113495bSYour Name 
1761*5113495bSYour Name 	data_len = hdd_get_twt_setup_event_len(add_dialog_comp_ev_params);
1762*5113495bSYour Name 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
1763*5113495bSYour Name 				hdd_ctx->wiphy, wdev, data_len,
1764*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
1765*5113495bSYour Name 				GFP_KERNEL);
1766*5113495bSYour Name 	if (!twt_vendor_event) {
1767*5113495bSYour Name 		hdd_err("TWT: Alloc setup resp skb fail");
1768*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
1769*5113495bSYour Name 	}
1770*5113495bSYour Name 
1771*5113495bSYour Name 	status = hdd_twt_setup_pack_resp_nlmsg(twt_vendor_event,
1772*5113495bSYour Name 					       add_dialog_comp_ev_params);
1773*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1774*5113495bSYour Name 		hdd_err("Failed to pack nl add dialog response");
1775*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
1776*5113495bSYour Name 		return status;
1777*5113495bSYour Name 	}
1778*5113495bSYour Name 
1779*5113495bSYour Name 	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
1780*5113495bSYour Name 
1781*5113495bSYour Name 	return status;
1782*5113495bSYour Name }
1783*5113495bSYour Name 
1784*5113495bSYour Name /**
1785*5113495bSYour Name  * hdd_twt_handle_renego_failure() - Upon re-nego failure send TWT teardown
1786*5113495bSYour Name  *
1787*5113495bSYour Name  * @adapter: Adapter pointer
1788*5113495bSYour Name  * @add_dialog_event: Pointer to Add dialog complete event structure
1789*5113495bSYour Name  *
1790*5113495bSYour Name  * Upon re-negotiation failure, this function constructs TWT teardown
1791*5113495bSYour Name  * message to the target.
1792*5113495bSYour Name  *
1793*5113495bSYour Name  * Return: None
1794*5113495bSYour Name  */
1795*5113495bSYour Name static void
hdd_twt_handle_renego_failure(struct hdd_adapter * adapter,struct wma_twt_add_dialog_complete_event * add_dialog_event)1796*5113495bSYour Name hdd_twt_handle_renego_failure(struct hdd_adapter *adapter,
1797*5113495bSYour Name 			      struct wma_twt_add_dialog_complete_event *add_dialog_event)
1798*5113495bSYour Name {
1799*5113495bSYour Name 	struct wmi_twt_del_dialog_param params = {0};
1800*5113495bSYour Name 
1801*5113495bSYour Name 	if (!add_dialog_event)
1802*5113495bSYour Name 		return;
1803*5113495bSYour Name 
1804*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr,
1805*5113495bSYour Name 		     add_dialog_event->params.peer_macaddr,
1806*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
1807*5113495bSYour Name 	params.vdev_id = add_dialog_event->params.vdev_id;
1808*5113495bSYour Name 	params.dialog_id = add_dialog_event->params.dialog_id;
1809*5113495bSYour Name 
1810*5113495bSYour Name 	hdd_debug("renego: twt_terminate: vdev_id:%d dialog_id:%d peer mac_addr "
1811*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
1812*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr));
1813*5113495bSYour Name 
1814*5113495bSYour Name 	hdd_send_twt_del_dialog_cmd(adapter->hdd_ctx, &params);
1815*5113495bSYour Name }
1816*5113495bSYour Name 
1817*5113495bSYour Name /**
1818*5113495bSYour Name  * hdd_twt_ack_comp_cb() - TWT ack complete event callback
1819*5113495bSYour Name  * @params: TWT parameters
1820*5113495bSYour Name  * @context: Context
1821*5113495bSYour Name  *
1822*5113495bSYour Name  * Return: None
1823*5113495bSYour Name  */
1824*5113495bSYour Name static void
hdd_twt_ack_comp_cb(struct wmi_twt_ack_complete_event_param * params,void * context)1825*5113495bSYour Name hdd_twt_ack_comp_cb(struct wmi_twt_ack_complete_event_param *params,
1826*5113495bSYour Name 		    void *context)
1827*5113495bSYour Name {
1828*5113495bSYour Name 	struct osif_request *request = NULL;
1829*5113495bSYour Name 	struct twt_ack_info_priv *status_priv;
1830*5113495bSYour Name 
1831*5113495bSYour Name 	request = osif_request_get(context);
1832*5113495bSYour Name 	if (!request) {
1833*5113495bSYour Name 		hdd_err("obsolete request");
1834*5113495bSYour Name 		return;
1835*5113495bSYour Name 	}
1836*5113495bSYour Name 
1837*5113495bSYour Name 	status_priv = osif_request_priv(request);
1838*5113495bSYour Name 	if (!status_priv) {
1839*5113495bSYour Name 		hdd_err("obsolete status_priv");
1840*5113495bSYour Name 		return;
1841*5113495bSYour Name 	}
1842*5113495bSYour Name 
1843*5113495bSYour Name 	if (status_priv->twt_cmd_ack == params->twt_cmd_ack) {
1844*5113495bSYour Name 		status_priv->vdev_id = params->vdev_id;
1845*5113495bSYour Name 		qdf_copy_macaddr(&status_priv->peer_macaddr,
1846*5113495bSYour Name 				 &params->peer_macaddr);
1847*5113495bSYour Name 		status_priv->dialog_id = params->dialog_id;
1848*5113495bSYour Name 		status_priv->status = params->status;
1849*5113495bSYour Name 		osif_request_complete(request);
1850*5113495bSYour Name 	} else {
1851*5113495bSYour Name 		hdd_err("Invalid ack for twt command");
1852*5113495bSYour Name 	}
1853*5113495bSYour Name 
1854*5113495bSYour Name 	osif_request_put(request);
1855*5113495bSYour Name }
1856*5113495bSYour Name 
1857*5113495bSYour Name /**
1858*5113495bSYour Name  * hdd_twt_ack_wait_response: TWT wait for ack event if it's supported
1859*5113495bSYour Name  * @hdd_ctx: HDD context
1860*5113495bSYour Name  * @request: OSIF request cookie
1861*5113495bSYour Name  * @twt_cmd: TWT command for which ack event come
1862*5113495bSYour Name  *
1863*5113495bSYour Name  * Return: None
1864*5113495bSYour Name  */
1865*5113495bSYour Name static QDF_STATUS
hdd_twt_ack_wait_response(struct hdd_context * hdd_ctx,struct osif_request * request,int twt_cmd)1866*5113495bSYour Name hdd_twt_ack_wait_response(struct hdd_context *hdd_ctx,
1867*5113495bSYour Name 			  struct osif_request *request, int twt_cmd)
1868*5113495bSYour Name {
1869*5113495bSYour Name 	struct target_psoc_info *tgt_hdl;
1870*5113495bSYour Name 	struct twt_ack_info_priv *ack_priv;
1871*5113495bSYour Name 	int ret = 0;
1872*5113495bSYour Name 	bool twt_ack_cap;
1873*5113495bSYour Name 
1874*5113495bSYour Name 	tgt_hdl = wlan_psoc_get_tgt_if_handle(hdd_ctx->psoc);
1875*5113495bSYour Name 	if (!tgt_hdl) {
1876*5113495bSYour Name 		hdd_err("tgt_hdl is NULL");
1877*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1878*5113495bSYour Name 	}
1879*5113495bSYour Name 	target_psoc_get_twt_ack_cap(tgt_hdl, &twt_ack_cap);
1880*5113495bSYour Name 
1881*5113495bSYour Name 	if (!twt_ack_cap) {
1882*5113495bSYour Name 		hdd_err("TWT ack bit is not supported. No need to wait");
1883*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
1884*5113495bSYour Name 	}
1885*5113495bSYour Name 
1886*5113495bSYour Name 	ack_priv = osif_request_priv(request);
1887*5113495bSYour Name 	ack_priv->twt_cmd_ack = twt_cmd;
1888*5113495bSYour Name 
1889*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
1890*5113495bSYour Name 	if (ret) {
1891*5113495bSYour Name 		hdd_err("TWT setup response timed out");
1892*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
1893*5113495bSYour Name 	}
1894*5113495bSYour Name 
1895*5113495bSYour Name 	ack_priv = osif_request_priv(request);
1896*5113495bSYour Name 	hdd_debug("TWT ack info: vdev_id %d dialog_id %d twt_cmd %d status %d peer_macaddr "
1897*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, ack_priv->vdev_id, ack_priv->dialog_id,
1898*5113495bSYour Name 		  ack_priv->twt_cmd_ack, ack_priv->status,
1899*5113495bSYour Name 		  QDF_MAC_ADDR_REF(ack_priv->peer_macaddr.bytes));
1900*5113495bSYour Name 
1901*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1902*5113495bSYour Name }
1903*5113495bSYour Name 
1904*5113495bSYour Name /**
1905*5113495bSYour Name  * hdd_twt_add_dialog_comp_cb() - HDD callback for twt add dialog
1906*5113495bSYour Name  * complete event
1907*5113495bSYour Name  * @psoc: Pointer to global psoc
1908*5113495bSYour Name  * @add_dialog_event: Pointer to Add dialog complete event structure
1909*5113495bSYour Name  * @renego_fail: Flag to indicate if its re-negotiation failure case
1910*5113495bSYour Name  *
1911*5113495bSYour Name  * Return: None
1912*5113495bSYour Name  */
1913*5113495bSYour Name static void
hdd_twt_add_dialog_comp_cb(struct wlan_objmgr_psoc * psoc,struct wma_twt_add_dialog_complete_event * add_dialog_event,bool renego_fail)1914*5113495bSYour Name hdd_twt_add_dialog_comp_cb(struct wlan_objmgr_psoc *psoc,
1915*5113495bSYour Name 			   struct wma_twt_add_dialog_complete_event *add_dialog_event,
1916*5113495bSYour Name 			   bool renego_fail)
1917*5113495bSYour Name {
1918*5113495bSYour Name 	struct hdd_adapter *adapter;
1919*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1920*5113495bSYour Name 	uint8_t vdev_id = add_dialog_event->params.vdev_id;
1921*5113495bSYour Name 
1922*5113495bSYour Name 	link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id);
1923*5113495bSYour Name 	if (!link_info) {
1924*5113495bSYour Name 		hdd_err("Invalid vdev");
1925*5113495bSYour Name 		return;
1926*5113495bSYour Name 	}
1927*5113495bSYour Name 
1928*5113495bSYour Name 	adapter = link_info->adapter;
1929*5113495bSYour Name 	hdd_debug("TWT: add dialog_id:%d, status:%d vdev_id:%d renego_fail:%d peer mac_addr "
1930*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, add_dialog_event->params.dialog_id,
1931*5113495bSYour Name 		  add_dialog_event->params.status, vdev_id, renego_fail,
1932*5113495bSYour Name 		  QDF_MAC_ADDR_REF(add_dialog_event->params.peer_macaddr));
1933*5113495bSYour Name 
1934*5113495bSYour Name 	hdd_send_twt_setup_response(adapter, add_dialog_event);
1935*5113495bSYour Name 
1936*5113495bSYour Name 	if (renego_fail)
1937*5113495bSYour Name 		hdd_twt_handle_renego_failure(adapter, add_dialog_event);
1938*5113495bSYour Name }
1939*5113495bSYour Name 
1940*5113495bSYour Name /**
1941*5113495bSYour Name  * hdd_send_twt_add_dialog_cmd() - Send TWT add dialog command to target
1942*5113495bSYour Name  * @hdd_ctx: HDD Context
1943*5113495bSYour Name  * @twt_params: Pointer to Add dialog cmd params structure
1944*5113495bSYour Name  *
1945*5113495bSYour Name  * Return: 0 for Success and negative value for failure
1946*5113495bSYour Name  */
1947*5113495bSYour Name static
hdd_send_twt_add_dialog_cmd(struct hdd_context * hdd_ctx,struct wmi_twt_add_dialog_param * twt_params)1948*5113495bSYour Name int hdd_send_twt_add_dialog_cmd(struct hdd_context *hdd_ctx,
1949*5113495bSYour Name 				struct wmi_twt_add_dialog_param *twt_params)
1950*5113495bSYour Name {
1951*5113495bSYour Name 	QDF_STATUS status;
1952*5113495bSYour Name 	int ret = 0, twt_cmd;
1953*5113495bSYour Name 	struct osif_request *request;
1954*5113495bSYour Name 	struct twt_ack_info_priv *ack_priv;
1955*5113495bSYour Name 	void *context;
1956*5113495bSYour Name 	static const struct osif_request_params params = {
1957*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
1958*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
1959*5113495bSYour Name 	};
1960*5113495bSYour Name 
1961*5113495bSYour Name 	hdd_enter();
1962*5113495bSYour Name 
1963*5113495bSYour Name 	request = osif_request_alloc(&params);
1964*5113495bSYour Name 	if (!request) {
1965*5113495bSYour Name 		hdd_err("Request allocation failure");
1966*5113495bSYour Name 		return -EINVAL;
1967*5113495bSYour Name 	}
1968*5113495bSYour Name 
1969*5113495bSYour Name 	context = osif_request_cookie(request);
1970*5113495bSYour Name 
1971*5113495bSYour Name 	status = sme_add_dialog_cmd(hdd_ctx->mac_handle,
1972*5113495bSYour Name 				    hdd_twt_add_dialog_comp_cb,
1973*5113495bSYour Name 				    twt_params, context);
1974*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1975*5113495bSYour Name 		hdd_err("Failed to send add dialog command");
1976*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
1977*5113495bSYour Name 		goto cleanup;
1978*5113495bSYour Name 	}
1979*5113495bSYour Name 
1980*5113495bSYour Name 	twt_cmd = WMI_HOST_TWT_ADD_DIALOG_CMDID;
1981*5113495bSYour Name 
1982*5113495bSYour Name 	status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd);
1983*5113495bSYour Name 
1984*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1985*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
1986*5113495bSYour Name 		goto cleanup;
1987*5113495bSYour Name 	}
1988*5113495bSYour Name 
1989*5113495bSYour Name 	ack_priv = osif_request_priv(request);
1990*5113495bSYour Name 	if (ack_priv->status) {
1991*5113495bSYour Name 		hdd_err("Received TWT ack error. Reset twt command");
1992*5113495bSYour Name 		ucfg_mlme_reset_twt_active_cmd(
1993*5113495bSYour Name 				hdd_ctx->psoc,
1994*5113495bSYour Name 				(struct qdf_mac_addr *)twt_params->peer_macaddr,
1995*5113495bSYour Name 				twt_params->dialog_id);
1996*5113495bSYour Name 		 ucfg_mlme_init_twt_context(
1997*5113495bSYour Name 				hdd_ctx->psoc,
1998*5113495bSYour Name 				(struct qdf_mac_addr *)twt_params->peer_macaddr,
1999*5113495bSYour Name 				twt_params->dialog_id);
2000*5113495bSYour Name 
2001*5113495bSYour Name 		switch (ack_priv->status) {
2002*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_INVALID_PARAM:
2003*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
2004*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
2005*5113495bSYour Name 			ret = -EINVAL;
2006*5113495bSYour Name 			break;
2007*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
2008*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
2009*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
2010*5113495bSYour Name 			ret = -EBUSY;
2011*5113495bSYour Name 			break;
2012*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
2013*5113495bSYour Name 			ret = -EOPNOTSUPP;
2014*5113495bSYour Name 			break;
2015*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_NOT_READY:
2016*5113495bSYour Name 			ret = -EAGAIN;
2017*5113495bSYour Name 			break;
2018*5113495bSYour Name 		case WMI_HOST_ADD_TWT_STATUS_NO_RESOURCE:
2019*5113495bSYour Name 			ret = -ENOMEM;
2020*5113495bSYour Name 			break;
2021*5113495bSYour Name 		default:
2022*5113495bSYour Name 			ret = -EAGAIN;
2023*5113495bSYour Name 			break;
2024*5113495bSYour Name 		}
2025*5113495bSYour Name 	}
2026*5113495bSYour Name 
2027*5113495bSYour Name cleanup:
2028*5113495bSYour Name 	osif_request_put(request);
2029*5113495bSYour Name 	hdd_exit();
2030*5113495bSYour Name 
2031*5113495bSYour Name 	return ret;
2032*5113495bSYour Name }
2033*5113495bSYour Name 
hdd_twt_setup_conc_allowed(struct hdd_context * hdd_ctx,uint8_t vdev_id)2034*5113495bSYour Name static bool hdd_twt_setup_conc_allowed(struct hdd_context *hdd_ctx,
2035*5113495bSYour Name 				       uint8_t vdev_id)
2036*5113495bSYour Name {
2037*5113495bSYour Name 	return policy_mgr_current_concurrency_is_mcc(hdd_ctx->psoc) ||
2038*5113495bSYour Name 	       policy_mgr_is_scc_with_this_vdev_id(hdd_ctx->psoc, vdev_id);
2039*5113495bSYour Name }
2040*5113495bSYour Name 
2041*5113495bSYour Name /**
2042*5113495bSYour Name  * hdd_twt_setup_session() - Process TWT setup operation in the
2043*5113495bSYour Name  * received vendor command and send it to firmware
2044*5113495bSYour Name  * @adapter: adapter pointer
2045*5113495bSYour Name  * @twt_param_attr: nl attributes
2046*5113495bSYour Name  *
2047*5113495bSYour Name  * Handles QCA_WLAN_TWT_SET
2048*5113495bSYour Name  *
2049*5113495bSYour Name  * Return: 0 for Success and negative value for failure
2050*5113495bSYour Name  *
2051*5113495bSYour Name  *    If the setup request is received:
2052*5113495bSYour Name  *        before the host driver receiving the setup response event from
2053*5113495bSYour Name  *        firmware for the previous setup request, then return -EINPROGRESS
2054*5113495bSYour Name  *
2055*5113495bSYour Name  *        after the host driver received the setup response event from
2056*5113495bSYour Name  *        firmware for the previous setup request, then setup_done is
2057*5113495bSYour Name  *        set to true and this new setup request is sent to firmware
2058*5113495bSYour Name  *        for parameter re-negotiation.
2059*5113495bSYour Name  */
hdd_twt_setup_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)2060*5113495bSYour Name static int hdd_twt_setup_session(struct hdd_adapter *adapter,
2061*5113495bSYour Name 				 struct nlattr *twt_param_attr)
2062*5113495bSYour Name {
2063*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2064*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
2065*5113495bSYour Name 			WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
2066*5113495bSYour Name 	struct wmi_twt_add_dialog_param params = {0};
2067*5113495bSYour Name 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
2068*5113495bSYour Name 	uint32_t congestion_timeout = 0;
2069*5113495bSYour Name 	int ret = 0;
2070*5113495bSYour Name 
2071*5113495bSYour Name 	ret = hdd_is_twt_command_allowed(adapter);
2072*5113495bSYour Name 	if (ret)
2073*5113495bSYour Name 		return ret;
2074*5113495bSYour Name 
2075*5113495bSYour Name 	if (hdd_twt_setup_conc_allowed(hdd_ctx, adapter->deflink->vdev_id)) {
2076*5113495bSYour Name 		hdd_err_rl("TWT setup reject: SCC or MCC concurrency exists");
2077*5113495bSYour Name 		return -EAGAIN;
2078*5113495bSYour Name 	}
2079*5113495bSYour Name 
2080*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr,
2081*5113495bSYour Name 		     hdd_sta_ctx->conn_info.bssid.bytes,
2082*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
2083*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
2084*5113495bSYour Name 
2085*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb2,
2086*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2087*5113495bSYour Name 					     twt_param_attr,
2088*5113495bSYour Name 					     qca_wlan_vendor_twt_add_dialog_policy);
2089*5113495bSYour Name 	if (ret)
2090*5113495bSYour Name 		return ret;
2091*5113495bSYour Name 
2092*5113495bSYour Name 	ret = hdd_twt_get_add_dialog_values(tb2, &params);
2093*5113495bSYour Name 	if (ret)
2094*5113495bSYour Name 		return ret;
2095*5113495bSYour Name 
2096*5113495bSYour Name 	if (params.flag_bcast && !ucfg_mlme_get_twt_peer_bcast_capabilities(
2097*5113495bSYour Name 					adapter->hdd_ctx->psoc,
2098*5113495bSYour Name 					&hdd_sta_ctx->conn_info.bssid)) {
2099*5113495bSYour Name 		hdd_err_rl("TWT setup reject: TWT Broadcast not supported");
2100*5113495bSYour Name 		return -EOPNOTSUPP;
2101*5113495bSYour Name 	} else if (!params.flag_bcast &&
2102*5113495bSYour Name 		   !ucfg_mlme_get_twt_peer_responder_capabilities(
2103*5113495bSYour Name 					adapter->hdd_ctx->psoc,
2104*5113495bSYour Name 					&hdd_sta_ctx->conn_info.bssid)) {
2105*5113495bSYour Name 		hdd_err_rl("TWT setup reject: TWT responder not supported");
2106*5113495bSYour Name 		return -EOPNOTSUPP;
2107*5113495bSYour Name 	}
2108*5113495bSYour Name 
2109*5113495bSYour Name 	ucfg_mlme_get_twt_congestion_timeout(adapter->hdd_ctx->psoc,
2110*5113495bSYour Name 					     &congestion_timeout);
2111*5113495bSYour Name 
2112*5113495bSYour Name 	if (congestion_timeout) {
2113*5113495bSYour Name 		ret = qdf_status_to_os_return(
2114*5113495bSYour Name 			hdd_send_twt_requestor_disable_cmd(adapter->hdd_ctx,
2115*5113495bSYour Name 							   0));
2116*5113495bSYour Name 		if (ret) {
2117*5113495bSYour Name 			hdd_err("Failed to disable TWT");
2118*5113495bSYour Name 			return ret;
2119*5113495bSYour Name 		}
2120*5113495bSYour Name 
2121*5113495bSYour Name 		ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0);
2122*5113495bSYour Name 
2123*5113495bSYour Name 		ret = qdf_status_to_os_return(
2124*5113495bSYour Name 			hdd_send_twt_requestor_enable_cmd(adapter->hdd_ctx));
2125*5113495bSYour Name 		if (ret) {
2126*5113495bSYour Name 			hdd_err("Failed to Enable TWT");
2127*5113495bSYour Name 			return ret;
2128*5113495bSYour Name 		}
2129*5113495bSYour Name 	}
2130*5113495bSYour Name 
2131*5113495bSYour Name 	if (ucfg_mlme_is_max_twt_sessions_reached(adapter->hdd_ctx->psoc,
2132*5113495bSYour Name 					       &hdd_sta_ctx->conn_info.bssid,
2133*5113495bSYour Name 						params.dialog_id)) {
2134*5113495bSYour Name 		hdd_err_rl("TWT add failed(dialog_id:%d), another TWT already exists (max reached)",
2135*5113495bSYour Name 			   params.dialog_id);
2136*5113495bSYour Name 		return -EAGAIN;
2137*5113495bSYour Name 	}
2138*5113495bSYour Name 
2139*5113495bSYour Name 	if (ucfg_mlme_is_twt_setup_in_progress(adapter->hdd_ctx->psoc,
2140*5113495bSYour Name 					       &hdd_sta_ctx->conn_info.bssid,
2141*5113495bSYour Name 					params.dialog_id)) {
2142*5113495bSYour Name 		hdd_err_rl("TWT setup is in progress for dialog_id:%d",
2143*5113495bSYour Name 			   params.dialog_id);
2144*5113495bSYour Name 		return -EINPROGRESS;
2145*5113495bSYour Name 	}
2146*5113495bSYour Name 
2147*5113495bSYour Name 	ret = hdd_send_twt_add_dialog_cmd(adapter->hdd_ctx, &params);
2148*5113495bSYour Name 	if (ret < 0)
2149*5113495bSYour Name 		return ret;
2150*5113495bSYour Name 
2151*5113495bSYour Name 	return ret;
2152*5113495bSYour Name }
2153*5113495bSYour Name 
2154*5113495bSYour Name /**
2155*5113495bSYour Name  * hdd_twt_add_ac_config() - Get TWT AC parameter
2156*5113495bSYour Name  * value from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
2157*5113495bSYour Name  * @adapter: adapter pointer
2158*5113495bSYour Name  * @twt_ac_param: AC parameter
2159*5113495bSYour Name  *
2160*5113495bSYour Name  * Handles QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE
2161*5113495bSYour Name  *
2162*5113495bSYour Name  * Return: 0 on success, negative value on failure.
2163*5113495bSYour Name  */
hdd_twt_add_ac_config(struct hdd_adapter * adapter,enum qca_wlan_ac_type twt_ac_param)2164*5113495bSYour Name static int hdd_twt_add_ac_config(struct hdd_adapter *adapter,
2165*5113495bSYour Name 				 enum qca_wlan_ac_type twt_ac_param)
2166*5113495bSYour Name {
2167*5113495bSYour Name 	bool is_responder_en;
2168*5113495bSYour Name 	int ret = 0;
2169*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2170*5113495bSYour Name 
2171*5113495bSYour Name 	if (twt_ac_param < QCA_WLAN_AC_BE || twt_ac_param > QCA_WLAN_AC_VO) {
2172*5113495bSYour Name 		hdd_err_rl("Invalid AC parameter. Value: %d", twt_ac_param);
2173*5113495bSYour Name 		return -EINVAL;
2174*5113495bSYour Name 	}
2175*5113495bSYour Name 
2176*5113495bSYour Name 	ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &is_responder_en);
2177*5113495bSYour Name 
2178*5113495bSYour Name 	if (adapter->device_mode == QDF_SAP_MODE && is_responder_en) {
2179*5113495bSYour Name 		ret = sme_cli_set_command(adapter->deflink->vdev_id,
2180*5113495bSYour Name 					  wmi_pdev_param_twt_ac_config,
2181*5113495bSYour Name 					  twt_ac_param, PDEV_CMD);
2182*5113495bSYour Name 	} else {
2183*5113495bSYour Name 		hdd_err_rl("Undesired device mode. Mode: %d and responder: %d",
2184*5113495bSYour Name 			   adapter->device_mode, is_responder_en);
2185*5113495bSYour Name 		return -EINVAL;
2186*5113495bSYour Name 	}
2187*5113495bSYour Name 
2188*5113495bSYour Name 	return ret;
2189*5113495bSYour Name }
2190*5113495bSYour Name 
2191*5113495bSYour Name /**
2192*5113495bSYour Name  * hdd_twt_set_param - Process TWT set parameter operation
2193*5113495bSYour Name  * in the received vendor command and send it to firmware
2194*5113495bSYour Name  * @adapter: adapter pointer
2195*5113495bSYour Name  * @twt_param_attr: nl attributes
2196*5113495bSYour Name  *
2197*5113495bSYour Name  * Handles QCA_WLAN_TWT_SET_PARAM
2198*5113495bSYour Name  *
2199*5113495bSYour Name  * Return: 0 on success, negative value on failure
2200*5113495bSYour Name  */
hdd_twt_set_param(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)2201*5113495bSYour Name static int hdd_twt_set_param(struct hdd_adapter *adapter,
2202*5113495bSYour Name 			     struct nlattr *twt_param_attr)
2203*5113495bSYour Name {
2204*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1];
2205*5113495bSYour Name 	int ret;
2206*5113495bSYour Name 	int cmd_id;
2207*5113495bSYour Name 	uint8_t twt_ac_param;
2208*5113495bSYour Name 
2209*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested
2210*5113495bSYour Name 					(tb,
2211*5113495bSYour Name 					 QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX,
2212*5113495bSYour Name 					 twt_param_attr,
2213*5113495bSYour Name 					 qca_wlan_vendor_twt_set_param_policy);
2214*5113495bSYour Name 	if (ret)
2215*5113495bSYour Name 		return ret;
2216*5113495bSYour Name 
2217*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE;
2218*5113495bSYour Name 
2219*5113495bSYour Name 	if (tb[cmd_id]) {
2220*5113495bSYour Name 		twt_ac_param = nla_get_u8(tb[cmd_id]);
2221*5113495bSYour Name 		hdd_debug("TWT_AC_CONFIG_VALUE: %d", twt_ac_param);
2222*5113495bSYour Name 		ret = hdd_twt_add_ac_config(adapter, twt_ac_param);
2223*5113495bSYour Name 
2224*5113495bSYour Name 		if (ret) {
2225*5113495bSYour Name 			hdd_err("Fail to set TWT AC parameter, errno %d",
2226*5113495bSYour Name 				ret);
2227*5113495bSYour Name 			return ret;
2228*5113495bSYour Name 		}
2229*5113495bSYour Name 	}
2230*5113495bSYour Name 
2231*5113495bSYour Name 	return ret;
2232*5113495bSYour Name }
2233*5113495bSYour Name 
2234*5113495bSYour Name /**
2235*5113495bSYour Name  * hdd_get_twt_get_stats_event_len() - calculate length of skb
2236*5113495bSYour Name  * required for sending twt get statistics command responses.
2237*5113495bSYour Name  *
2238*5113495bSYour Name  * Return: length of skb
2239*5113495bSYour Name  */
hdd_get_twt_get_stats_event_len(void)2240*5113495bSYour Name static uint32_t hdd_get_twt_get_stats_event_len(void)
2241*5113495bSYour Name {
2242*5113495bSYour Name 	uint32_t len = 0;
2243*5113495bSYour Name 
2244*5113495bSYour Name 	len += NLMSG_HDRLEN;
2245*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
2246*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
2247*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
2248*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
2249*5113495bSYour Name 
2250*5113495bSYour Name 	return len;
2251*5113495bSYour Name }
2252*5113495bSYour Name 
2253*5113495bSYour Name /**
2254*5113495bSYour Name  * hdd_get_twt_event_len() - calculate length of skb
2255*5113495bSYour Name  * required for sending twt terminate, pause and resume
2256*5113495bSYour Name  * command responses.
2257*5113495bSYour Name  *
2258*5113495bSYour Name  * Return: length of skb
2259*5113495bSYour Name  */
hdd_get_twt_event_len(void)2260*5113495bSYour Name static uint32_t hdd_get_twt_event_len(void)
2261*5113495bSYour Name {
2262*5113495bSYour Name 	uint32_t len = 0;
2263*5113495bSYour Name 
2264*5113495bSYour Name 	len += NLMSG_HDRLEN;
2265*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
2266*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
2267*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
2268*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
2269*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
2270*5113495bSYour Name 	len += nla_total_size(QDF_MAC_ADDR_SIZE);
2271*5113495bSYour Name 
2272*5113495bSYour Name 	return len;
2273*5113495bSYour Name }
2274*5113495bSYour Name 
2275*5113495bSYour Name /**
2276*5113495bSYour Name  * hdd_twt_terminate_pack_resp_nlmsg() - pack the skb with
2277*5113495bSYour Name  * firmware response for twt terminate command
2278*5113495bSYour Name  * @reply_skb: skb to store the response
2279*5113495bSYour Name  * @params: Pointer to del dialog complete event buffer
2280*5113495bSYour Name  *
2281*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
2282*5113495bSYour Name  * on failure
2283*5113495bSYour Name  */
2284*5113495bSYour Name static QDF_STATUS
hdd_twt_terminate_pack_resp_nlmsg(struct sk_buff * reply_skb,struct wmi_twt_del_dialog_complete_event_param * params)2285*5113495bSYour Name hdd_twt_terminate_pack_resp_nlmsg(struct sk_buff *reply_skb,
2286*5113495bSYour Name 				  struct wmi_twt_del_dialog_complete_event_param *params)
2287*5113495bSYour Name {
2288*5113495bSYour Name 	struct nlattr *config_attr;
2289*5113495bSYour Name 	int vendor_status, attr;
2290*5113495bSYour Name 
2291*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
2292*5113495bSYour Name 		       QCA_WLAN_TWT_TERMINATE)) {
2293*5113495bSYour Name 		hdd_err("Failed to put TWT operation");
2294*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2295*5113495bSYour Name 	}
2296*5113495bSYour Name 
2297*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
2298*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
2299*5113495bSYour Name 	if (!config_attr) {
2300*5113495bSYour Name 		hdd_err("nla_nest_start error");
2301*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2302*5113495bSYour Name 	}
2303*5113495bSYour Name 
2304*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2305*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, params->dialog_id)) {
2306*5113495bSYour Name 		hdd_debug("Failed to put dialog_id");
2307*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2308*5113495bSYour Name 	}
2309*5113495bSYour Name 
2310*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
2311*5113495bSYour Name 	vendor_status = wmi_twt_del_status_to_vendor_twt_status(params->status);
2312*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, vendor_status)) {
2313*5113495bSYour Name 		hdd_err("Failed to put QCA_WLAN_TWT_TERMINATE");
2314*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2315*5113495bSYour Name 	}
2316*5113495bSYour Name 
2317*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
2318*5113495bSYour Name 	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
2319*5113495bSYour Name 		    params->peer_macaddr)) {
2320*5113495bSYour Name 		hdd_err("Failed to put mac_addr");
2321*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2322*5113495bSYour Name 	}
2323*5113495bSYour Name 
2324*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
2325*5113495bSYour Name 
2326*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
2327*5113495bSYour Name }
2328*5113495bSYour Name 
2329*5113495bSYour Name /**
2330*5113495bSYour Name  * hdd_twt_del_dialog_comp_cb() - callback function
2331*5113495bSYour Name  * to get twt terminate command complete event
2332*5113495bSYour Name  * @psoc: Pointer to global psoc
2333*5113495bSYour Name  * @params: Pointer to del dialog complete event buffer
2334*5113495bSYour Name  *
2335*5113495bSYour Name  * Return: None
2336*5113495bSYour Name  */
2337*5113495bSYour Name static void
hdd_twt_del_dialog_comp_cb(struct wlan_objmgr_psoc * psoc,struct wmi_twt_del_dialog_complete_event_param * params)2338*5113495bSYour Name hdd_twt_del_dialog_comp_cb(struct wlan_objmgr_psoc *psoc,
2339*5113495bSYour Name 			   struct wmi_twt_del_dialog_complete_event_param *params)
2340*5113495bSYour Name {
2341*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
2342*5113495bSYour Name 	struct wireless_dev *wdev;
2343*5113495bSYour Name 	struct hdd_context *hdd_ctx;
2344*5113495bSYour Name 	struct sk_buff *twt_vendor_event;
2345*5113495bSYour Name 	size_t data_len;
2346*5113495bSYour Name 	QDF_STATUS status;
2347*5113495bSYour Name 
2348*5113495bSYour Name 	hdd_enter();
2349*5113495bSYour Name 
2350*5113495bSYour Name 	link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id);
2351*5113495bSYour Name 	if (!link_info) {
2352*5113495bSYour Name 		hdd_err("Invalid vdev");
2353*5113495bSYour Name 		return;
2354*5113495bSYour Name 	}
2355*5113495bSYour Name 
2356*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2357*5113495bSYour Name 	if (!hdd_ctx || cds_is_load_or_unload_in_progress())
2358*5113495bSYour Name 		return;
2359*5113495bSYour Name 
2360*5113495bSYour Name 	wdev = &link_info->adapter->wdev;
2361*5113495bSYour Name 
2362*5113495bSYour Name 	data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8));
2363*5113495bSYour Name 	data_len += NLA_HDRLEN;
2364*5113495bSYour Name 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
2365*5113495bSYour Name 				hdd_ctx->wiphy, wdev, data_len,
2366*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
2367*5113495bSYour Name 				GFP_KERNEL);
2368*5113495bSYour Name 	if (!twt_vendor_event) {
2369*5113495bSYour Name 		hdd_err("Del dialog skb alloc failed");
2370*5113495bSYour Name 		return;
2371*5113495bSYour Name 	}
2372*5113495bSYour Name 
2373*5113495bSYour Name 	hdd_debug("del dialog_id:%d, status:%d vdev_id %d peer mac_addr "
2374*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params->dialog_id,
2375*5113495bSYour Name 		  params->status, params->vdev_id,
2376*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params->peer_macaddr));
2377*5113495bSYour Name 
2378*5113495bSYour Name 	status = hdd_twt_terminate_pack_resp_nlmsg(twt_vendor_event, params);
2379*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2380*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
2381*5113495bSYour Name 		return;
2382*5113495bSYour Name 	}
2383*5113495bSYour Name 
2384*5113495bSYour Name 	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
2385*5113495bSYour Name 
2386*5113495bSYour Name 	hdd_exit();
2387*5113495bSYour Name 
2388*5113495bSYour Name 	return;
2389*5113495bSYour Name }
2390*5113495bSYour Name 
2391*5113495bSYour Name void
hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info * link_info)2392*5113495bSYour Name hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info *link_info)
2393*5113495bSYour Name {
2394*5113495bSYour Name 	struct hdd_adapter *adapter = link_info->adapter;
2395*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
2396*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx = NULL;
2397*5113495bSYour Name 	struct wmi_twt_del_dialog_complete_event_param params;
2398*5113495bSYour Name 
2399*5113495bSYour Name 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2400*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(link_info)) {
2401*5113495bSYour Name 		hdd_debug("Not associated, vdev %d mode %d",
2402*5113495bSYour Name 			   link_info->vdev_id, adapter->device_mode);
2403*5113495bSYour Name 		return;
2404*5113495bSYour Name 	}
2405*5113495bSYour Name 
2406*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(psoc,
2407*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
2408*5113495bSYour Name 					 TWT_ALL_SESSIONS_DIALOG_ID)) {
2409*5113495bSYour Name 		hdd_debug("No active TWT sessions, vdev_id: %d dialog_id: %d",
2410*5113495bSYour Name 			  link_info->vdev_id,
2411*5113495bSYour Name 			  TWT_ALL_SESSIONS_DIALOG_ID);
2412*5113495bSYour Name 		return;
2413*5113495bSYour Name 	}
2414*5113495bSYour Name 
2415*5113495bSYour Name 	qdf_mem_zero(&params, sizeof(params));
2416*5113495bSYour Name 	params.vdev_id = link_info->vdev_id;
2417*5113495bSYour Name 	params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
2418*5113495bSYour Name 	params.status = WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR;
2419*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes,
2420*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
2421*5113495bSYour Name 
2422*5113495bSYour Name 	hdd_twt_del_dialog_comp_cb(psoc, &params);
2423*5113495bSYour Name }
2424*5113495bSYour Name 
2425*5113495bSYour Name /**
2426*5113495bSYour Name  * hdd_send_twt_del_dialog_cmd() - Send TWT del dialog command to target
2427*5113495bSYour Name  * @hdd_ctx: HDD Context
2428*5113495bSYour Name  * @twt_params: Pointer to del dialog cmd params structure
2429*5113495bSYour Name  *
2430*5113495bSYour Name  * Return: 0 on success, negative value on failure
2431*5113495bSYour Name  */
2432*5113495bSYour Name static
hdd_send_twt_del_dialog_cmd(struct hdd_context * hdd_ctx,struct wmi_twt_del_dialog_param * twt_params)2433*5113495bSYour Name int hdd_send_twt_del_dialog_cmd(struct hdd_context *hdd_ctx,
2434*5113495bSYour Name 				struct wmi_twt_del_dialog_param *twt_params)
2435*5113495bSYour Name {
2436*5113495bSYour Name 	QDF_STATUS status;
2437*5113495bSYour Name 	int ret = 0, twt_cmd;
2438*5113495bSYour Name 	struct osif_request *request;
2439*5113495bSYour Name 	struct twt_ack_info_priv *ack_priv;
2440*5113495bSYour Name 	void *context;
2441*5113495bSYour Name 	static const struct osif_request_params params = {
2442*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
2443*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
2444*5113495bSYour Name 	};
2445*5113495bSYour Name 
2446*5113495bSYour Name 	hdd_enter();
2447*5113495bSYour Name 
2448*5113495bSYour Name 	request = osif_request_alloc(&params);
2449*5113495bSYour Name 	if (!request) {
2450*5113495bSYour Name 		hdd_err("Request allocation failure");
2451*5113495bSYour Name 		return -EINVAL;
2452*5113495bSYour Name 	}
2453*5113495bSYour Name 
2454*5113495bSYour Name 	context = osif_request_cookie(request);
2455*5113495bSYour Name 
2456*5113495bSYour Name 	status = sme_del_dialog_cmd(hdd_ctx->mac_handle,
2457*5113495bSYour Name 				    hdd_twt_del_dialog_comp_cb,
2458*5113495bSYour Name 				    twt_params, context);
2459*5113495bSYour Name 
2460*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2461*5113495bSYour Name 		hdd_err("Failed to send del dialog command");
2462*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
2463*5113495bSYour Name 		goto cleanup;
2464*5113495bSYour Name 	}
2465*5113495bSYour Name 
2466*5113495bSYour Name 	twt_cmd = WMI_HOST_TWT_DEL_DIALOG_CMDID;
2467*5113495bSYour Name 
2468*5113495bSYour Name 	status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd);
2469*5113495bSYour Name 
2470*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2471*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
2472*5113495bSYour Name 		goto cleanup;
2473*5113495bSYour Name 	}
2474*5113495bSYour Name 
2475*5113495bSYour Name 	ack_priv = osif_request_priv(request);
2476*5113495bSYour Name 	if (ack_priv->status) {
2477*5113495bSYour Name 		hdd_err("Received TWT ack error. Reset twt command");
2478*5113495bSYour Name 		ucfg_mlme_reset_twt_active_cmd(
2479*5113495bSYour Name 				hdd_ctx->psoc,
2480*5113495bSYour Name 				(struct qdf_mac_addr *)twt_params->peer_macaddr,
2481*5113495bSYour Name 				twt_params->dialog_id);
2482*5113495bSYour Name 
2483*5113495bSYour Name 		switch (ack_priv->status) {
2484*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_INVALID_PARAM:
2485*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR:
2486*5113495bSYour Name 			ret = -EINVAL;
2487*5113495bSYour Name 			break;
2488*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_NOT_EXIST:
2489*5113495bSYour Name 			ret = -EAGAIN;
2490*5113495bSYour Name 			break;
2491*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_BUSY:
2492*5113495bSYour Name 			ret = -EINPROGRESS;
2493*5113495bSYour Name 			break;
2494*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_NO_RESOURCE:
2495*5113495bSYour Name 			ret = -ENOMEM;
2496*5113495bSYour Name 			break;
2497*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_ROAMING:
2498*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_CHAN_SW_IN_PROGRESS:
2499*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_SCAN_IN_PROGRESS:
2500*5113495bSYour Name 			ret = -EBUSY;
2501*5113495bSYour Name 			break;
2502*5113495bSYour Name 		case WMI_HOST_DEL_TWT_STATUS_CONCURRENCY:
2503*5113495bSYour Name 			ret = -EAGAIN;
2504*5113495bSYour Name 			break;
2505*5113495bSYour Name 		default:
2506*5113495bSYour Name 			ret = -EAGAIN;
2507*5113495bSYour Name 			break;
2508*5113495bSYour Name 		}
2509*5113495bSYour Name 	}
2510*5113495bSYour Name cleanup:
2511*5113495bSYour Name 	osif_request_put(request);
2512*5113495bSYour Name 	hdd_exit();
2513*5113495bSYour Name 
2514*5113495bSYour Name 	return ret;
2515*5113495bSYour Name }
2516*5113495bSYour Name 
2517*5113495bSYour Name /**
2518*5113495bSYour Name  * hdd_send_sap_twt_del_dialog_cmd() - Send SAP TWT del dialog command
2519*5113495bSYour Name  * @hdd_ctx: HDD Context
2520*5113495bSYour Name  * @twt_params: Pointer to del dialog cmd params structure
2521*5113495bSYour Name  *
2522*5113495bSYour Name  * Return: 0 on success, negative value on failure
2523*5113495bSYour Name  */
2524*5113495bSYour Name static
hdd_send_sap_twt_del_dialog_cmd(struct hdd_context * hdd_ctx,struct wmi_twt_del_dialog_param * twt_params)2525*5113495bSYour Name int hdd_send_sap_twt_del_dialog_cmd(struct hdd_context *hdd_ctx,
2526*5113495bSYour Name 				    struct wmi_twt_del_dialog_param *twt_params)
2527*5113495bSYour Name {
2528*5113495bSYour Name 	QDF_STATUS status;
2529*5113495bSYour Name 	int ret = 0;
2530*5113495bSYour Name 
2531*5113495bSYour Name 	status = sme_sap_del_dialog_cmd(hdd_ctx->mac_handle,
2532*5113495bSYour Name 				    hdd_twt_del_dialog_comp_cb,
2533*5113495bSYour Name 				    twt_params);
2534*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2535*5113495bSYour Name 		hdd_err("Failed to send del dialog command");
2536*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
2537*5113495bSYour Name 	}
2538*5113495bSYour Name 
2539*5113495bSYour Name 	return ret;
2540*5113495bSYour Name }
2541*5113495bSYour Name 
2542*5113495bSYour Name 
hdd_sap_twt_terminate_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)2543*5113495bSYour Name static int hdd_sap_twt_terminate_session(struct hdd_adapter *adapter,
2544*5113495bSYour Name 					 struct nlattr *twt_param_attr)
2545*5113495bSYour Name {
2546*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
2547*5113495bSYour Name 	struct wmi_twt_del_dialog_param params = {0};
2548*5113495bSYour Name 	QDF_STATUS status;
2549*5113495bSYour Name 	int id, id1, ret;
2550*5113495bSYour Name 	bool is_associated;
2551*5113495bSYour Name 	struct qdf_mac_addr mac_addr;
2552*5113495bSYour Name 
2553*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
2554*5113495bSYour Name 
2555*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
2556*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2557*5113495bSYour Name 					     twt_param_attr,
2558*5113495bSYour Name 					     qca_wlan_vendor_twt_add_dialog_policy);
2559*5113495bSYour Name 	if (ret)
2560*5113495bSYour Name 		return ret;
2561*5113495bSYour Name 
2562*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2563*5113495bSYour Name 	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
2564*5113495bSYour Name 	if (tb[id] && tb[id1]) {
2565*5113495bSYour Name 		params.dialog_id = nla_get_u8(tb[id]);
2566*5113495bSYour Name 		nla_memcpy(params.peer_macaddr, tb[id1], QDF_MAC_ADDR_SIZE);
2567*5113495bSYour Name 	} else if (!tb[id] && !tb[id1]) {
2568*5113495bSYour Name 		struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
2569*5113495bSYour Name 
2570*5113495bSYour Name 		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
2571*5113495bSYour Name 		qdf_mem_copy(params.peer_macaddr, bcast_addr.bytes,
2572*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
2573*5113495bSYour Name 	} else {
2574*5113495bSYour Name 		hdd_err_rl("get_params dialog_id or mac_addr is missing");
2575*5113495bSYour Name 		return -EINVAL;
2576*5113495bSYour Name 	}
2577*5113495bSYour Name 
2578*5113495bSYour Name 	if (!params.dialog_id)
2579*5113495bSYour Name 		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
2580*5113495bSYour Name 
2581*5113495bSYour Name 	if (params.dialog_id != TWT_ALL_SESSIONS_DIALOG_ID &&
2582*5113495bSYour Name 	    QDF_IS_ADDR_BROADCAST(params.peer_macaddr)) {
2583*5113495bSYour Name 		hdd_err("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d",
2584*5113495bSYour Name 			TWT_ALL_SESSIONS_DIALOG_ID, params.dialog_id);
2585*5113495bSYour Name 		return -EINVAL;
2586*5113495bSYour Name 	}
2587*5113495bSYour Name 
2588*5113495bSYour Name 	status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc,
2589*5113495bSYour Name 					       params.dialog_id);
2590*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2591*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
2592*5113495bSYour Name 		return -EOPNOTSUPP;
2593*5113495bSYour Name 	}
2594*5113495bSYour Name 
2595*5113495bSYour Name 	qdf_mem_copy(mac_addr.bytes, params.peer_macaddr, QDF_MAC_ADDR_SIZE);
2596*5113495bSYour Name 
2597*5113495bSYour Name 	if (!qdf_is_macaddr_broadcast(&mac_addr)) {
2598*5113495bSYour Name 		is_associated = hdd_is_peer_associated(adapter, &mac_addr);
2599*5113495bSYour Name 		if (!is_associated) {
2600*5113495bSYour Name 			hdd_err_rl("Association doesn't exist for STA: "
2601*5113495bSYour Name 				   QDF_MAC_ADDR_FMT,
2602*5113495bSYour Name 				   QDF_MAC_ADDR_REF(mac_addr.bytes));
2603*5113495bSYour Name 			/*
2604*5113495bSYour Name 			 * Return success, since STA is not associated and
2605*5113495bSYour Name 			 * there is no TWT session.
2606*5113495bSYour Name 			 */
2607*5113495bSYour Name 			return 0;
2608*5113495bSYour Name 		}
2609*5113495bSYour Name 	}
2610*5113495bSYour Name 
2611*5113495bSYour Name 	hdd_debug("vdev_id %d dialog_id %d peer mac_addr "
2612*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
2613*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr));
2614*5113495bSYour Name 
2615*5113495bSYour Name 	ret = hdd_send_sap_twt_del_dialog_cmd(adapter->hdd_ctx, &params);
2616*5113495bSYour Name 
2617*5113495bSYour Name 	return ret;
2618*5113495bSYour Name }
2619*5113495bSYour Name 
hdd_sta_twt_terminate_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)2620*5113495bSYour Name static int hdd_sta_twt_terminate_session(struct hdd_adapter *adapter,
2621*5113495bSYour Name 					 struct nlattr *twt_param_attr)
2622*5113495bSYour Name {
2623*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx = NULL;
2624*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2625*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
2626*5113495bSYour Name 	struct wmi_twt_del_dialog_param params = {0};
2627*5113495bSYour Name 	QDF_STATUS status;
2628*5113495bSYour Name 	int id, ret;
2629*5113495bSYour Name 
2630*5113495bSYour Name 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
2631*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
2632*5113495bSYour Name 		hdd_err_rl("Invalid state, vdev %d mode %d",
2633*5113495bSYour Name 			   adapter->deflink->vdev_id, adapter->device_mode);
2634*5113495bSYour Name 
2635*5113495bSYour Name 		/*
2636*5113495bSYour Name 		 * Return success, since STA is not associated and there is
2637*5113495bSYour Name 		 * no TWT session.
2638*5113495bSYour Name 		 */
2639*5113495bSYour Name 		return 0;
2640*5113495bSYour Name 	}
2641*5113495bSYour Name 
2642*5113495bSYour Name 	if (hdd_is_roaming_in_progress(hdd_ctx))
2643*5113495bSYour Name 		return -EBUSY;
2644*5113495bSYour Name 
2645*5113495bSYour Name 	if (ucfg_scan_get_pdev_status(hdd_ctx->pdev)) {
2646*5113495bSYour Name 		hdd_err_rl("Scan in progress");
2647*5113495bSYour Name 		return -EBUSY;
2648*5113495bSYour Name 	}
2649*5113495bSYour Name 
2650*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr,
2651*5113495bSYour Name 		     hdd_sta_ctx->conn_info.bssid.bytes,
2652*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
2653*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
2654*5113495bSYour Name 
2655*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
2656*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2657*5113495bSYour Name 					     twt_param_attr,
2658*5113495bSYour Name 					     qca_wlan_vendor_twt_add_dialog_policy);
2659*5113495bSYour Name 	if (ret)
2660*5113495bSYour Name 		return ret;
2661*5113495bSYour Name 
2662*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2663*5113495bSYour Name 	if (tb[id]) {
2664*5113495bSYour Name 		params.dialog_id = nla_get_u8(tb[id]);
2665*5113495bSYour Name 	} else {
2666*5113495bSYour Name 		params.dialog_id = 0;
2667*5113495bSYour Name 		hdd_debug("TWT_TERMINATE_FLOW_ID not specified. set to zero");
2668*5113495bSYour Name 	}
2669*5113495bSYour Name 
2670*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
2671*5113495bSYour Name 	if (tb[id]) {
2672*5113495bSYour Name 		params.dialog_id = nla_get_u8(tb[id]);
2673*5113495bSYour Name 		hdd_debug("TWT_SETUP_BCAST_ID %d", params.dialog_id);
2674*5113495bSYour Name 	}
2675*5113495bSYour Name 
2676*5113495bSYour Name 	status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc,
2677*5113495bSYour Name 					       params.dialog_id);
2678*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2679*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
2680*5113495bSYour Name 		return -EOPNOTSUPP;
2681*5113495bSYour Name 	}
2682*5113495bSYour Name 
2683*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
2684*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
2685*5113495bSYour Name 					 params.dialog_id)) {
2686*5113495bSYour Name 		hdd_debug("vdev%d: TWT session %d setup incomplete",
2687*5113495bSYour Name 			  params.vdev_id, params.dialog_id);
2688*5113495bSYour Name 		return -EAGAIN;
2689*5113495bSYour Name 	}
2690*5113495bSYour Name 
2691*5113495bSYour Name 	hdd_debug("vdev_id %d dialog_id %d peer mac_addr "
2692*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
2693*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr));
2694*5113495bSYour Name 
2695*5113495bSYour Name 	ret = hdd_send_twt_del_dialog_cmd(adapter->hdd_ctx, &params);
2696*5113495bSYour Name 
2697*5113495bSYour Name 	return ret;
2698*5113495bSYour Name }
2699*5113495bSYour Name 
2700*5113495bSYour Name /**
2701*5113495bSYour Name  * hdd_twt_terminate_session - Process TWT terminate
2702*5113495bSYour Name  * operation in the received vendor command and
2703*5113495bSYour Name  * send it to firmware
2704*5113495bSYour Name  * @adapter: adapter pointer
2705*5113495bSYour Name  * @twt_param_attr: nl attributes
2706*5113495bSYour Name  *
2707*5113495bSYour Name  * Handles QCA_WLAN_TWT_TERMINATE
2708*5113495bSYour Name  *
2709*5113495bSYour Name  * Return: 0 on success, negative value on failure
2710*5113495bSYour Name  */
hdd_twt_terminate_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)2711*5113495bSYour Name static int hdd_twt_terminate_session(struct hdd_adapter *adapter,
2712*5113495bSYour Name 				     struct nlattr *twt_param_attr)
2713*5113495bSYour Name {
2714*5113495bSYour Name 	enum QDF_OPMODE device_mode = adapter->device_mode;
2715*5113495bSYour Name 
2716*5113495bSYour Name 	switch (device_mode) {
2717*5113495bSYour Name 	case QDF_STA_MODE:
2718*5113495bSYour Name 		return hdd_sta_twt_terminate_session(adapter, twt_param_attr);
2719*5113495bSYour Name 	case QDF_SAP_MODE:
2720*5113495bSYour Name 		return hdd_sap_twt_terminate_session(adapter, twt_param_attr);
2721*5113495bSYour Name 	default:
2722*5113495bSYour Name 		hdd_err_rl("TWT terminate is not supported on %s",
2723*5113495bSYour Name 			   qdf_opmode_str(adapter->device_mode));
2724*5113495bSYour Name 		return -EOPNOTSUPP;
2725*5113495bSYour Name 	}
2726*5113495bSYour Name }
2727*5113495bSYour Name 
2728*5113495bSYour Name /**
2729*5113495bSYour Name  * hdd_twt_nudge_pack_resp_nlmsg() - pack the skb with
2730*5113495bSYour Name  * firmware response for twt nudge command
2731*5113495bSYour Name  * @reply_skb: skb to store the response
2732*5113495bSYour Name  * @params: Pointer to nudge dialog complete event buffer
2733*5113495bSYour Name  *
2734*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
2735*5113495bSYour Name  * on failure
2736*5113495bSYour Name  */
2737*5113495bSYour Name static QDF_STATUS
hdd_twt_nudge_pack_resp_nlmsg(struct sk_buff * reply_skb,struct wmi_twt_nudge_dialog_complete_event_param * params)2738*5113495bSYour Name hdd_twt_nudge_pack_resp_nlmsg(struct sk_buff *reply_skb,
2739*5113495bSYour Name 		      struct wmi_twt_nudge_dialog_complete_event_param *params)
2740*5113495bSYour Name {
2741*5113495bSYour Name 	struct nlattr *config_attr;
2742*5113495bSYour Name 	int vendor_status, attr;
2743*5113495bSYour Name 	uint64_t tsf_val;
2744*5113495bSYour Name 
2745*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
2746*5113495bSYour Name 		       QCA_WLAN_TWT_NUDGE)) {
2747*5113495bSYour Name 		hdd_err("Failed to put TWT operation");
2748*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2749*5113495bSYour Name 	}
2750*5113495bSYour Name 
2751*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
2752*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
2753*5113495bSYour Name 	if (!config_attr) {
2754*5113495bSYour Name 		hdd_err("nla_nest_start error");
2755*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2756*5113495bSYour Name 	}
2757*5113495bSYour Name 
2758*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID,
2759*5113495bSYour Name 		       params->dialog_id)) {
2760*5113495bSYour Name 		hdd_debug("Failed to put dialog_id");
2761*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2762*5113495bSYour Name 	}
2763*5113495bSYour Name 
2764*5113495bSYour Name 	tsf_val = params->next_twt_tsf_us_hi;
2765*5113495bSYour Name 	tsf_val = (tsf_val << 32) | params->next_twt_tsf_us_lo;
2766*5113495bSYour Name 	if (hdd_wlan_nla_put_u64(reply_skb,
2767*5113495bSYour Name 				 QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF,
2768*5113495bSYour Name 				 tsf_val)) {
2769*5113495bSYour Name 		hdd_err("get_params failed to put TSF Value");
2770*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2771*5113495bSYour Name 	}
2772*5113495bSYour Name 
2773*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
2774*5113495bSYour Name 	vendor_status =
2775*5113495bSYour Name 		     wmi_twt_nudge_status_to_vendor_twt_status(params->status);
2776*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, vendor_status)) {
2777*5113495bSYour Name 		hdd_err("Failed to put QCA_WLAN_TWT_NUDGE status");
2778*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2779*5113495bSYour Name 	}
2780*5113495bSYour Name 
2781*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR;
2782*5113495bSYour Name 	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
2783*5113495bSYour Name 		    params->peer_macaddr)) {
2784*5113495bSYour Name 		hdd_err("Failed to put mac_addr");
2785*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2786*5113495bSYour Name 	}
2787*5113495bSYour Name 
2788*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
2789*5113495bSYour Name 
2790*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
2791*5113495bSYour Name }
2792*5113495bSYour Name 
2793*5113495bSYour Name /*
2794*5113495bSYour Name  * hdd_twt_nudge_dialog_comp_cb() - callback function
2795*5113495bSYour Name  * to get twt nudge command complete event
2796*5113495bSYour Name  * @psoc: Pointer to global psoc
2797*5113495bSYour Name  * @params: Pointer to nudge dialog complete event buffer
2798*5113495bSYour Name  *
2799*5113495bSYour Name  * Return: None
2800*5113495bSYour Name  */
hdd_twt_nudge_dialog_comp_cb(struct wlan_objmgr_psoc * psoc,struct wmi_twt_nudge_dialog_complete_event_param * params)2801*5113495bSYour Name static void hdd_twt_nudge_dialog_comp_cb(
2802*5113495bSYour Name 		struct wlan_objmgr_psoc *psoc,
2803*5113495bSYour Name 		struct wmi_twt_nudge_dialog_complete_event_param *params)
2804*5113495bSYour Name {
2805*5113495bSYour Name 
2806*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
2807*5113495bSYour Name 	struct wireless_dev *wdev;
2808*5113495bSYour Name 	struct hdd_context *hdd_ctx;
2809*5113495bSYour Name 	struct sk_buff *twt_vendor_event;
2810*5113495bSYour Name 	size_t data_len;
2811*5113495bSYour Name 	QDF_STATUS status;
2812*5113495bSYour Name 
2813*5113495bSYour Name 	hdd_enter();
2814*5113495bSYour Name 
2815*5113495bSYour Name 	link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id);
2816*5113495bSYour Name 	if (!link_info || hdd_validate_adapter(link_info->adapter))
2817*5113495bSYour Name 		return;
2818*5113495bSYour Name 
2819*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2820*5113495bSYour Name 
2821*5113495bSYour Name 	wdev = &link_info->adapter->wdev;
2822*5113495bSYour Name 
2823*5113495bSYour Name 	hdd_debug("Nudge dialog_id:%d, status:%d vdev_id %d peer mac_addr "
2824*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params->dialog_id,
2825*5113495bSYour Name 		  params->status, params->vdev_id,
2826*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params->peer_macaddr));
2827*5113495bSYour Name 
2828*5113495bSYour Name 	data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8)) +
2829*5113495bSYour Name 		   nla_total_size(sizeof(u64));
2830*5113495bSYour Name 	data_len += NLA_HDRLEN;
2831*5113495bSYour Name 
2832*5113495bSYour Name 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
2833*5113495bSYour Name 				hdd_ctx->wiphy, wdev,
2834*5113495bSYour Name 				data_len,
2835*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
2836*5113495bSYour Name 				GFP_KERNEL);
2837*5113495bSYour Name 	if (!twt_vendor_event) {
2838*5113495bSYour Name 		hdd_err("Nudge dialog alloc skb failed");
2839*5113495bSYour Name 		return;
2840*5113495bSYour Name 	}
2841*5113495bSYour Name 
2842*5113495bSYour Name 	status = hdd_twt_nudge_pack_resp_nlmsg(twt_vendor_event, params);
2843*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2844*5113495bSYour Name 		hdd_err("Failed to pack nl nudge dialog response %d", status);
2845*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
2846*5113495bSYour Name 	}
2847*5113495bSYour Name 
2848*5113495bSYour Name 	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
2849*5113495bSYour Name 
2850*5113495bSYour Name 	hdd_exit();
2851*5113495bSYour Name }
2852*5113495bSYour Name 
2853*5113495bSYour Name /**
2854*5113495bSYour Name  * hdd_twt_pause_pack_resp_nlmsg() - pack the skb with
2855*5113495bSYour Name  * firmware response for twt pause command
2856*5113495bSYour Name  * @reply_skb: skb to store the response
2857*5113495bSYour Name  * @params: Pointer to pause dialog complete event buffer
2858*5113495bSYour Name  *
2859*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
2860*5113495bSYour Name  * on failure
2861*5113495bSYour Name  */
2862*5113495bSYour Name static QDF_STATUS
hdd_twt_pause_pack_resp_nlmsg(struct sk_buff * reply_skb,struct wmi_twt_pause_dialog_complete_event_param * params)2863*5113495bSYour Name hdd_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb,
2864*5113495bSYour Name 			      struct wmi_twt_pause_dialog_complete_event_param *params)
2865*5113495bSYour Name {
2866*5113495bSYour Name 	struct nlattr *config_attr;
2867*5113495bSYour Name 	int vendor_status, attr;
2868*5113495bSYour Name 
2869*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
2870*5113495bSYour Name 		       QCA_WLAN_TWT_SUSPEND)) {
2871*5113495bSYour Name 		hdd_err("Failed to put TWT operation");
2872*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2873*5113495bSYour Name 	}
2874*5113495bSYour Name 
2875*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
2876*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
2877*5113495bSYour Name 	if (!config_attr) {
2878*5113495bSYour Name 		hdd_err("nla_nest_start error");
2879*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2880*5113495bSYour Name 	}
2881*5113495bSYour Name 
2882*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2883*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, params->dialog_id)) {
2884*5113495bSYour Name 		hdd_debug("Failed to put dialog_id");
2885*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2886*5113495bSYour Name 	}
2887*5113495bSYour Name 
2888*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
2889*5113495bSYour Name 	vendor_status = wmi_twt_pause_status_to_vendor_twt_status(params->status);
2890*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, vendor_status)) {
2891*5113495bSYour Name 		hdd_err("Failed to put QCA_WLAN_TWT_PAUSE status");
2892*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
2893*5113495bSYour Name 	}
2894*5113495bSYour Name 
2895*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
2896*5113495bSYour Name 	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
2897*5113495bSYour Name 		    params->peer_macaddr)) {
2898*5113495bSYour Name 		hdd_err("Failed to put mac_addr");
2899*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
2900*5113495bSYour Name 	}
2901*5113495bSYour Name 
2902*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
2903*5113495bSYour Name 
2904*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
2905*5113495bSYour Name }
2906*5113495bSYour Name 
2907*5113495bSYour Name /*
2908*5113495bSYour Name  * hdd_twt_pause_dialog_comp_cb() - callback function
2909*5113495bSYour Name  * to get twt pause command complete event
2910*5113495bSYour Name  * @psoc: pointer to global psoc
2911*5113495bSYour Name  * @params: Pointer to pause dialog complete event buffer
2912*5113495bSYour Name  *
2913*5113495bSYour Name  * Return: None
2914*5113495bSYour Name  */
2915*5113495bSYour Name static void
hdd_twt_pause_dialog_comp_cb(struct wlan_objmgr_psoc * psoc,struct wmi_twt_pause_dialog_complete_event_param * params)2916*5113495bSYour Name hdd_twt_pause_dialog_comp_cb(
2917*5113495bSYour Name 		struct wlan_objmgr_psoc *psoc,
2918*5113495bSYour Name 		struct wmi_twt_pause_dialog_complete_event_param *params)
2919*5113495bSYour Name {
2920*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
2921*5113495bSYour Name 	struct wireless_dev *wdev;
2922*5113495bSYour Name 	struct hdd_context *hdd_ctx;
2923*5113495bSYour Name 	struct sk_buff *twt_vendor_event;
2924*5113495bSYour Name 	size_t data_len;
2925*5113495bSYour Name 	QDF_STATUS status;
2926*5113495bSYour Name 
2927*5113495bSYour Name 	hdd_enter();
2928*5113495bSYour Name 
2929*5113495bSYour Name 	link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id);
2930*5113495bSYour Name 	if (!link_info) {
2931*5113495bSYour Name 		hdd_err("Invalid vdev");
2932*5113495bSYour Name 		return;
2933*5113495bSYour Name 	}
2934*5113495bSYour Name 
2935*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2936*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
2937*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
2938*5113495bSYour Name 		return;
2939*5113495bSYour Name 
2940*5113495bSYour Name 	wdev = &link_info->adapter->wdev;
2941*5113495bSYour Name 
2942*5113495bSYour Name 	hdd_debug("pause dialog_id:%d, status:%d vdev_id %d peer mac_addr "
2943*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params->dialog_id,
2944*5113495bSYour Name 		  params->status, params->vdev_id,
2945*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params->peer_macaddr));
2946*5113495bSYour Name 
2947*5113495bSYour Name 	data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8));
2948*5113495bSYour Name 	data_len += NLA_HDRLEN;
2949*5113495bSYour Name 
2950*5113495bSYour Name 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
2951*5113495bSYour Name 				hdd_ctx->wiphy, wdev, data_len,
2952*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
2953*5113495bSYour Name 				GFP_KERNEL);
2954*5113495bSYour Name 	if (!twt_vendor_event) {
2955*5113495bSYour Name 		hdd_err("pause dialog alloc skb failed");
2956*5113495bSYour Name 		return;
2957*5113495bSYour Name 	}
2958*5113495bSYour Name 
2959*5113495bSYour Name 	status = hdd_twt_pause_pack_resp_nlmsg(twt_vendor_event, params);
2960*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2961*5113495bSYour Name 		hdd_err("Failed to pack nl pause dialog response");
2962*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
2963*5113495bSYour Name 	}
2964*5113495bSYour Name 
2965*5113495bSYour Name 	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
2966*5113495bSYour Name 
2967*5113495bSYour Name 	hdd_exit();
2968*5113495bSYour Name }
2969*5113495bSYour Name 
2970*5113495bSYour Name /**
2971*5113495bSYour Name  * hdd_send_twt_pause_dialog_cmd() - Send TWT pause dialog command to target
2972*5113495bSYour Name  * @hdd_ctx: HDD Context
2973*5113495bSYour Name  * @twt_params: Pointer to pause dialog cmd params structure
2974*5113495bSYour Name  *
2975*5113495bSYour Name  * Return: 0 on success, negative value on failure
2976*5113495bSYour Name  */
2977*5113495bSYour Name static
hdd_send_twt_pause_dialog_cmd(struct hdd_context * hdd_ctx,struct wmi_twt_pause_dialog_cmd_param * twt_params)2978*5113495bSYour Name int hdd_send_twt_pause_dialog_cmd(struct hdd_context *hdd_ctx,
2979*5113495bSYour Name 				  struct wmi_twt_pause_dialog_cmd_param *twt_params)
2980*5113495bSYour Name {
2981*5113495bSYour Name 	QDF_STATUS status;
2982*5113495bSYour Name 	int ret = 0, twt_cmd;
2983*5113495bSYour Name 	struct osif_request *request;
2984*5113495bSYour Name 	struct twt_ack_info_priv *ack_priv;
2985*5113495bSYour Name 	void *context;
2986*5113495bSYour Name 	static const struct osif_request_params params = {
2987*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
2988*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
2989*5113495bSYour Name 	};
2990*5113495bSYour Name 
2991*5113495bSYour Name 	hdd_enter();
2992*5113495bSYour Name 
2993*5113495bSYour Name 	request = osif_request_alloc(&params);
2994*5113495bSYour Name 	if (!request) {
2995*5113495bSYour Name 		hdd_err("Request allocation failure");
2996*5113495bSYour Name 		return -EINVAL;
2997*5113495bSYour Name 	}
2998*5113495bSYour Name 
2999*5113495bSYour Name 	context = osif_request_cookie(request);
3000*5113495bSYour Name 
3001*5113495bSYour Name 	status = sme_pause_dialog_cmd(hdd_ctx->mac_handle,
3002*5113495bSYour Name 				      twt_params, context);
3003*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3004*5113495bSYour Name 		hdd_err("Failed to send pause dialog command");
3005*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3006*5113495bSYour Name 		goto cleanup;
3007*5113495bSYour Name 	}
3008*5113495bSYour Name 
3009*5113495bSYour Name 	twt_cmd = WMI_HOST_TWT_PAUSE_DIALOG_CMDID;
3010*5113495bSYour Name 
3011*5113495bSYour Name 	status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd);
3012*5113495bSYour Name 
3013*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3014*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3015*5113495bSYour Name 		goto cleanup;
3016*5113495bSYour Name 	}
3017*5113495bSYour Name 
3018*5113495bSYour Name 	ack_priv = osif_request_priv(request);
3019*5113495bSYour Name 	if (ack_priv->status) {
3020*5113495bSYour Name 		hdd_err("Received TWT ack error. Reset twt command");
3021*5113495bSYour Name 		ucfg_mlme_reset_twt_active_cmd(
3022*5113495bSYour Name 				hdd_ctx->psoc,
3023*5113495bSYour Name 				(struct qdf_mac_addr *)twt_params->peer_macaddr,
3024*5113495bSYour Name 				twt_params->dialog_id);
3025*5113495bSYour Name 
3026*5113495bSYour Name 		switch (ack_priv->status) {
3027*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_INVALID_PARAM:
3028*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_ALREADY_PAUSED:
3029*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_UNKNOWN_ERROR:
3030*5113495bSYour Name 			ret = -EINVAL;
3031*5113495bSYour Name 			break;
3032*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_NOT_EXIST:
3033*5113495bSYour Name 			ret = -EAGAIN;
3034*5113495bSYour Name 			break;
3035*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_BUSY:
3036*5113495bSYour Name 			ret = -EINPROGRESS;
3037*5113495bSYour Name 			break;
3038*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_NO_RESOURCE:
3039*5113495bSYour Name 			ret = -ENOMEM;
3040*5113495bSYour Name 			break;
3041*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_CHAN_SW_IN_PROGRESS:
3042*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_ROAM_IN_PROGRESS:
3043*5113495bSYour Name 		case WMI_HOST_PAUSE_TWT_STATUS_SCAN_IN_PROGRESS:
3044*5113495bSYour Name 			ret = -EBUSY;
3045*5113495bSYour Name 			break;
3046*5113495bSYour Name 		default:
3047*5113495bSYour Name 			ret = -EAGAIN;
3048*5113495bSYour Name 			break;
3049*5113495bSYour Name 		}
3050*5113495bSYour Name 	}
3051*5113495bSYour Name cleanup:
3052*5113495bSYour Name 	osif_request_put(request);
3053*5113495bSYour Name 	hdd_exit();
3054*5113495bSYour Name 
3055*5113495bSYour Name 	return ret;
3056*5113495bSYour Name }
3057*5113495bSYour Name 
3058*5113495bSYour Name /**
3059*5113495bSYour Name  * hdd_twt_pause_session - Process TWT pause operation
3060*5113495bSYour Name  * in the received vendor command and send it to firmware
3061*5113495bSYour Name  * @adapter: adapter pointer
3062*5113495bSYour Name  * @twt_param_attr: nl attributes
3063*5113495bSYour Name  *
3064*5113495bSYour Name  * Handles QCA_WLAN_TWT_SUSPEND
3065*5113495bSYour Name  *
3066*5113495bSYour Name  * Return: 0 on success, negative value on failure
3067*5113495bSYour Name  */
hdd_twt_pause_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)3068*5113495bSYour Name static int hdd_twt_pause_session(struct hdd_adapter *adapter,
3069*5113495bSYour Name 				 struct nlattr *twt_param_attr)
3070*5113495bSYour Name {
3071*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
3072*5113495bSYour Name 		WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
3073*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
3074*5113495bSYour Name 	struct wmi_twt_pause_dialog_cmd_param params = {0};
3075*5113495bSYour Name 	QDF_STATUS status;
3076*5113495bSYour Name 	int id;
3077*5113495bSYour Name 	int ret;
3078*5113495bSYour Name 
3079*5113495bSYour Name 	ret = hdd_is_twt_command_allowed(adapter);
3080*5113495bSYour Name 	if (ret)
3081*5113495bSYour Name 		return ret;
3082*5113495bSYour Name 
3083*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes,
3084*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
3085*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
3086*5113495bSYour Name 	params.dialog_id = 0;
3087*5113495bSYour Name 
3088*5113495bSYour Name 	if (twt_param_attr) {
3089*5113495bSYour Name 		ret = wlan_cfg80211_nla_parse_nested(tb,
3090*5113495bSYour Name 					QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
3091*5113495bSYour Name 					twt_param_attr,
3092*5113495bSYour Name 					qca_wlan_vendor_twt_add_dialog_policy);
3093*5113495bSYour Name 		if (ret) {
3094*5113495bSYour Name 			hdd_debug("command parsing failed");
3095*5113495bSYour Name 			return ret;
3096*5113495bSYour Name 		}
3097*5113495bSYour Name 
3098*5113495bSYour Name 		id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
3099*5113495bSYour Name 		if (tb[id])
3100*5113495bSYour Name 			params.dialog_id = nla_get_u8(tb[id]);
3101*5113495bSYour Name 		else
3102*5113495bSYour Name 			hdd_debug("TWT: FLOW_ID not specified. set to zero");
3103*5113495bSYour Name 	} else {
3104*5113495bSYour Name 		hdd_debug("TWT param not present. flow id set to zero");
3105*5113495bSYour Name 	}
3106*5113495bSYour Name 
3107*5113495bSYour Name 	status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc,
3108*5113495bSYour Name 					       params.dialog_id);
3109*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3110*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
3111*5113495bSYour Name 		return -EOPNOTSUPP;
3112*5113495bSYour Name 	}
3113*5113495bSYour Name 
3114*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
3115*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
3116*5113495bSYour Name 					 params.dialog_id)) {
3117*5113495bSYour Name 		hdd_debug("vdev%d: TWT session %d setup incomplete",
3118*5113495bSYour Name 			  params.vdev_id, params.dialog_id);
3119*5113495bSYour Name 		return -EAGAIN;
3120*5113495bSYour Name 	}
3121*5113495bSYour Name 
3122*5113495bSYour Name 	hdd_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr "
3123*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
3124*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr));
3125*5113495bSYour Name 
3126*5113495bSYour Name 	ret = hdd_send_twt_pause_dialog_cmd(adapter->hdd_ctx, &params);
3127*5113495bSYour Name 
3128*5113495bSYour Name 	return ret;
3129*5113495bSYour Name }
3130*5113495bSYour Name 
3131*5113495bSYour Name /**
3132*5113495bSYour Name  * hdd_send_twt_nudge_dialog_cmd() - Send TWT nudge dialog command to target
3133*5113495bSYour Name  * @hdd_ctx: HDD Context
3134*5113495bSYour Name  * @twt_params: Pointer to nudge dialog cmd params structure
3135*5113495bSYour Name  *
3136*5113495bSYour Name  * Return: 0 on success, negative value on failure
3137*5113495bSYour Name  */
3138*5113495bSYour Name static
hdd_send_twt_nudge_dialog_cmd(struct hdd_context * hdd_ctx,struct wmi_twt_nudge_dialog_cmd_param * twt_params)3139*5113495bSYour Name int hdd_send_twt_nudge_dialog_cmd(struct hdd_context *hdd_ctx,
3140*5113495bSYour Name 			struct wmi_twt_nudge_dialog_cmd_param *twt_params)
3141*5113495bSYour Name {
3142*5113495bSYour Name 	QDF_STATUS status;
3143*5113495bSYour Name 	int twt_cmd, ret = 0;
3144*5113495bSYour Name 	struct osif_request *request;
3145*5113495bSYour Name 	struct twt_ack_info_priv *ack_priv;
3146*5113495bSYour Name 	void *context;
3147*5113495bSYour Name 	static const struct osif_request_params params = {
3148*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
3149*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
3150*5113495bSYour Name 	};
3151*5113495bSYour Name 
3152*5113495bSYour Name 	hdd_enter();
3153*5113495bSYour Name 
3154*5113495bSYour Name 	request = osif_request_alloc(&params);
3155*5113495bSYour Name 	if (!request) {
3156*5113495bSYour Name 		hdd_err("Request allocation failure");
3157*5113495bSYour Name 		return -EINVAL;
3158*5113495bSYour Name 	}
3159*5113495bSYour Name 
3160*5113495bSYour Name 	context = osif_request_cookie(request);
3161*5113495bSYour Name 
3162*5113495bSYour Name 	status = sme_nudge_dialog_cmd(hdd_ctx->mac_handle, twt_params, context);
3163*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3164*5113495bSYour Name 		hdd_err("Failed to send nudge dialog command");
3165*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3166*5113495bSYour Name 		goto cleanup;
3167*5113495bSYour Name 	}
3168*5113495bSYour Name 
3169*5113495bSYour Name 	twt_cmd = WMI_HOST_TWT_NUDGE_DIALOG_CMDID;
3170*5113495bSYour Name 
3171*5113495bSYour Name 	status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd);
3172*5113495bSYour Name 
3173*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3174*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3175*5113495bSYour Name 		goto cleanup;
3176*5113495bSYour Name 	}
3177*5113495bSYour Name 
3178*5113495bSYour Name 	ack_priv = osif_request_priv(request);
3179*5113495bSYour Name 	if (ack_priv->status) {
3180*5113495bSYour Name 		hdd_err("Received TWT ack error. Reset twt command");
3181*5113495bSYour Name 		ucfg_mlme_reset_twt_active_cmd(
3182*5113495bSYour Name 				hdd_ctx->psoc,
3183*5113495bSYour Name 				(struct qdf_mac_addr *)twt_params->peer_macaddr,
3184*5113495bSYour Name 				twt_params->dialog_id);
3185*5113495bSYour Name 
3186*5113495bSYour Name 		switch (ack_priv->status) {
3187*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_INVALID_PARAM:
3188*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_ALREADY_PAUSED:
3189*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_UNKNOWN_ERROR:
3190*5113495bSYour Name 			ret = -EINVAL;
3191*5113495bSYour Name 			break;
3192*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_NOT_EXIST:
3193*5113495bSYour Name 			ret = -EAGAIN;
3194*5113495bSYour Name 			break;
3195*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_BUSY:
3196*5113495bSYour Name 			ret = -EINPROGRESS;
3197*5113495bSYour Name 			break;
3198*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_NO_RESOURCE:
3199*5113495bSYour Name 			ret = -ENOMEM;
3200*5113495bSYour Name 			break;
3201*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_CHAN_SW_IN_PROGRESS:
3202*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_ROAM_IN_PROGRESS:
3203*5113495bSYour Name 		case WMI_HOST_NUDGE_TWT_STATUS_SCAN_IN_PROGRESS:
3204*5113495bSYour Name 			ret = -EBUSY;
3205*5113495bSYour Name 			break;
3206*5113495bSYour Name 		default:
3207*5113495bSYour Name 			ret = -EAGAIN;
3208*5113495bSYour Name 			break;
3209*5113495bSYour Name 		}
3210*5113495bSYour Name 	}
3211*5113495bSYour Name cleanup:
3212*5113495bSYour Name 	osif_request_put(request);
3213*5113495bSYour Name 	hdd_exit();
3214*5113495bSYour Name 
3215*5113495bSYour Name 	return ret;
3216*5113495bSYour Name }
3217*5113495bSYour Name 
3218*5113495bSYour Name /**
3219*5113495bSYour Name  * hdd_twt_nudge_session - Process TWT nudge operation
3220*5113495bSYour Name  * in the received vendor command and send it to firmware
3221*5113495bSYour Name  * @adapter: adapter pointer
3222*5113495bSYour Name  * @twt_param_attr: nl attributes
3223*5113495bSYour Name  *
3224*5113495bSYour Name  * Handles QCA_WLAN_TWT_NUDGE
3225*5113495bSYour Name  *
3226*5113495bSYour Name  * Return: 0 on success, negative value on failure
3227*5113495bSYour Name  */
hdd_twt_nudge_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)3228*5113495bSYour Name static int hdd_twt_nudge_session(struct hdd_adapter *adapter,
3229*5113495bSYour Name 				 struct nlattr *twt_param_attr)
3230*5113495bSYour Name {
3231*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
3232*5113495bSYour Name 			WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
3233*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1];
3234*5113495bSYour Name 	struct wmi_twt_nudge_dialog_cmd_param params = {0};
3235*5113495bSYour Name 	QDF_STATUS status;
3236*5113495bSYour Name 	int id, ret;
3237*5113495bSYour Name 	bool is_nudge_tgt_cap_enabled;
3238*5113495bSYour Name 
3239*5113495bSYour Name 	ret = hdd_is_twt_command_allowed(adapter);
3240*5113495bSYour Name 	if (ret)
3241*5113495bSYour Name 		return ret;
3242*5113495bSYour Name 
3243*5113495bSYour Name 	ucfg_mlme_get_twt_nudge_tgt_cap(adapter->hdd_ctx->psoc,
3244*5113495bSYour Name 					&is_nudge_tgt_cap_enabled);
3245*5113495bSYour Name 	if (!is_nudge_tgt_cap_enabled) {
3246*5113495bSYour Name 		hdd_debug("Nudge not supported by target");
3247*5113495bSYour Name 		return -EOPNOTSUPP;
3248*5113495bSYour Name 	}
3249*5113495bSYour Name 
3250*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
3251*5113495bSYour Name 
3252*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
3253*5113495bSYour Name 				      QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX,
3254*5113495bSYour Name 				      twt_param_attr,
3255*5113495bSYour Name 				      qca_wlan_vendor_twt_nudge_dialog_policy);
3256*5113495bSYour Name 	if (ret)
3257*5113495bSYour Name 		return ret;
3258*5113495bSYour Name 
3259*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR;
3260*5113495bSYour Name 	if (tb[id]) {
3261*5113495bSYour Name 		nla_memcpy(params.peer_macaddr, tb[id], QDF_MAC_ADDR_SIZE);
3262*5113495bSYour Name 		hdd_debug("peer mac_addr "QDF_MAC_ADDR_FMT,
3263*5113495bSYour Name 			  QDF_MAC_ADDR_REF(params.peer_macaddr));
3264*5113495bSYour Name 	} else {
3265*5113495bSYour Name 		qdf_mem_copy(params.peer_macaddr,
3266*5113495bSYour Name 			     hdd_sta_ctx->conn_info.bssid.bytes,
3267*5113495bSYour Name 			     QDF_MAC_ADDR_SIZE);
3268*5113495bSYour Name 	}
3269*5113495bSYour Name 
3270*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID;
3271*5113495bSYour Name 	if (!tb[id]) {
3272*5113495bSYour Name 		hdd_debug("TWT: FLOW_ID not specified");
3273*5113495bSYour Name 		return -EINVAL;
3274*5113495bSYour Name 	}
3275*5113495bSYour Name 	params.dialog_id = nla_get_u8(tb[id]);
3276*5113495bSYour Name 
3277*5113495bSYour Name 	status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc,
3278*5113495bSYour Name 					       params.dialog_id);
3279*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3280*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
3281*5113495bSYour Name 		return -EOPNOTSUPP;
3282*5113495bSYour Name 	}
3283*5113495bSYour Name 
3284*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME;
3285*5113495bSYour Name 	if (!tb[id]) {
3286*5113495bSYour Name 		hdd_debug("TWT: WAKE_TIME not specified");
3287*5113495bSYour Name 		return -EINVAL;
3288*5113495bSYour Name 	}
3289*5113495bSYour Name 	params.suspend_duration = nla_get_u32(tb[id]);
3290*5113495bSYour Name 
3291*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE;
3292*5113495bSYour Name 	if (!tb[id]) {
3293*5113495bSYour Name 		hdd_debug("TWT: NEXT_TWT_SIZE not specified.");
3294*5113495bSYour Name 		return -EINVAL;
3295*5113495bSYour Name 	}
3296*5113495bSYour Name 	params.next_twt_size = nla_get_u32(tb[id]);
3297*5113495bSYour Name 
3298*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
3299*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
3300*5113495bSYour Name 					 params.dialog_id)) {
3301*5113495bSYour Name 		hdd_debug("vdev%d: TWT session %d setup incomplete",
3302*5113495bSYour Name 			  params.vdev_id, params.dialog_id);
3303*5113495bSYour Name 		return -EAGAIN;
3304*5113495bSYour Name 	}
3305*5113495bSYour Name 
3306*5113495bSYour Name 	hdd_debug("twt_nudge: vdev_id %d dialog_id %d ", params.vdev_id,
3307*5113495bSYour Name 		  params.dialog_id);
3308*5113495bSYour Name 	hdd_debug("twt_nudge: suspend_duration %d next_twt_size %d",
3309*5113495bSYour Name 		  params.suspend_duration, params.next_twt_size);
3310*5113495bSYour Name 
3311*5113495bSYour Name 	ret = hdd_send_twt_nudge_dialog_cmd(adapter->hdd_ctx, &params);
3312*5113495bSYour Name 
3313*5113495bSYour Name 	return ret;
3314*5113495bSYour Name }
3315*5113495bSYour Name 
3316*5113495bSYour Name /**
3317*5113495bSYour Name  * hdd_twt_resume_pack_resp_nlmsg() - pack the skb with
3318*5113495bSYour Name  * firmware response for twt resume command
3319*5113495bSYour Name  * @reply_skb: skb to store the response
3320*5113495bSYour Name  * @params: Pointer to resume dialog complete event buffer
3321*5113495bSYour Name  *
3322*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
3323*5113495bSYour Name  * on failure
3324*5113495bSYour Name  */
3325*5113495bSYour Name static QDF_STATUS
hdd_twt_resume_pack_resp_nlmsg(struct sk_buff * reply_skb,struct wmi_twt_resume_dialog_complete_event_param * params)3326*5113495bSYour Name hdd_twt_resume_pack_resp_nlmsg(struct sk_buff *reply_skb,
3327*5113495bSYour Name 			       struct wmi_twt_resume_dialog_complete_event_param *params)
3328*5113495bSYour Name {
3329*5113495bSYour Name 	struct nlattr *config_attr;
3330*5113495bSYour Name 	int vendor_status, attr;
3331*5113495bSYour Name 
3332*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
3333*5113495bSYour Name 		       QCA_WLAN_TWT_RESUME)) {
3334*5113495bSYour Name 		hdd_err("Failed to put TWT operation");
3335*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
3336*5113495bSYour Name 	}
3337*5113495bSYour Name 
3338*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
3339*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
3340*5113495bSYour Name 	if (!config_attr) {
3341*5113495bSYour Name 		hdd_err("nla_nest_start error");
3342*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3343*5113495bSYour Name 	}
3344*5113495bSYour Name 
3345*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID,
3346*5113495bSYour Name 		       params->dialog_id)) {
3347*5113495bSYour Name 		hdd_debug("Failed to put dialog_id");
3348*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
3349*5113495bSYour Name 	}
3350*5113495bSYour Name 
3351*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
3352*5113495bSYour Name 	vendor_status = wmi_twt_resume_status_to_vendor_twt_status(params->status);
3353*5113495bSYour Name 	if (nla_put_u8(reply_skb, attr, vendor_status)) {
3354*5113495bSYour Name 		hdd_err("Failed to put QCA_WLAN_TWT_RESUME status");
3355*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
3356*5113495bSYour Name 	}
3357*5113495bSYour Name 
3358*5113495bSYour Name 	attr = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR;
3359*5113495bSYour Name 	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
3360*5113495bSYour Name 		    params->peer_macaddr)) {
3361*5113495bSYour Name 		hdd_err("Failed to put mac_addr");
3362*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3363*5113495bSYour Name 	}
3364*5113495bSYour Name 
3365*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
3366*5113495bSYour Name 
3367*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3368*5113495bSYour Name }
3369*5113495bSYour Name 
3370*5113495bSYour Name /**
3371*5113495bSYour Name  * hdd_twt_resume_dialog_comp_cb() - callback function
3372*5113495bSYour Name  * to get twt resume command complete event
3373*5113495bSYour Name  * @psoc: Pointer to global psoc
3374*5113495bSYour Name  * @params: Pointer to resume dialog complete event buffer
3375*5113495bSYour Name  *
3376*5113495bSYour Name  * Return: None
3377*5113495bSYour Name  */
hdd_twt_resume_dialog_comp_cb(struct wlan_objmgr_psoc * psoc,struct wmi_twt_resume_dialog_complete_event_param * params)3378*5113495bSYour Name static void hdd_twt_resume_dialog_comp_cb(
3379*5113495bSYour Name 		struct wlan_objmgr_psoc *psoc,
3380*5113495bSYour Name 		struct wmi_twt_resume_dialog_complete_event_param *params)
3381*5113495bSYour Name {
3382*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
3383*5113495bSYour Name 	struct hdd_context *hdd_ctx;
3384*5113495bSYour Name 	struct wireless_dev *wdev;
3385*5113495bSYour Name 	struct sk_buff *twt_vendor_event;
3386*5113495bSYour Name 	size_t data_len;
3387*5113495bSYour Name 	QDF_STATUS status;
3388*5113495bSYour Name 
3389*5113495bSYour Name 	hdd_enter();
3390*5113495bSYour Name 
3391*5113495bSYour Name 	link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id);
3392*5113495bSYour Name 	if (!link_info) {
3393*5113495bSYour Name 		hdd_err("Invalid vdev");
3394*5113495bSYour Name 		return;
3395*5113495bSYour Name 	}
3396*5113495bSYour Name 
3397*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
3398*5113495bSYour Name 	status = wlan_hdd_validate_context(hdd_ctx);
3399*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3400*5113495bSYour Name 		return;
3401*5113495bSYour Name 
3402*5113495bSYour Name 	wdev = &link_info->adapter->wdev;
3403*5113495bSYour Name 
3404*5113495bSYour Name 	hdd_debug("TWT: resume dialog_id:%d status:%d vdev_id %d peer mac_addr "
3405*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params->dialog_id,
3406*5113495bSYour Name 		  params->status, params->vdev_id,
3407*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params->peer_macaddr));
3408*5113495bSYour Name 
3409*5113495bSYour Name 	data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8));
3410*5113495bSYour Name 	data_len += NLA_HDRLEN;
3411*5113495bSYour Name 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
3412*5113495bSYour Name 			hdd_ctx->wiphy, wdev, data_len,
3413*5113495bSYour Name 			QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
3414*5113495bSYour Name 			GFP_KERNEL);
3415*5113495bSYour Name 	if (!twt_vendor_event) {
3416*5113495bSYour Name 		hdd_err("TWT: skb alloc failed");
3417*5113495bSYour Name 		return;
3418*5113495bSYour Name 	}
3419*5113495bSYour Name 
3420*5113495bSYour Name 	status = hdd_twt_resume_pack_resp_nlmsg(twt_vendor_event, params);
3421*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3422*5113495bSYour Name 		hdd_err("Failed to pack nl resume dialog response");
3423*5113495bSYour Name 
3424*5113495bSYour Name 	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
3425*5113495bSYour Name 
3426*5113495bSYour Name 	hdd_exit();
3427*5113495bSYour Name }
3428*5113495bSYour Name 
3429*5113495bSYour Name /**
3430*5113495bSYour Name  * hdd_send_twt_resume_dialog_cmd() - Send TWT resume dialog command to target
3431*5113495bSYour Name  * @hdd_ctx: HDD Context
3432*5113495bSYour Name  * @twt_params: Pointer to resume dialog cmd params structure
3433*5113495bSYour Name  *
3434*5113495bSYour Name  * Return: 0 on success, negative value on failure
3435*5113495bSYour Name  */
3436*5113495bSYour Name static int
hdd_send_twt_resume_dialog_cmd(struct hdd_context * hdd_ctx,struct wmi_twt_resume_dialog_cmd_param * twt_params)3437*5113495bSYour Name hdd_send_twt_resume_dialog_cmd(struct hdd_context *hdd_ctx,
3438*5113495bSYour Name 			       struct wmi_twt_resume_dialog_cmd_param *twt_params)
3439*5113495bSYour Name {
3440*5113495bSYour Name 	QDF_STATUS status;
3441*5113495bSYour Name 	int ret = 0, twt_cmd;
3442*5113495bSYour Name 	struct osif_request *request;
3443*5113495bSYour Name 	struct twt_ack_info_priv *ack_priv;
3444*5113495bSYour Name 	void *context;
3445*5113495bSYour Name 	static const struct osif_request_params params = {
3446*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
3447*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
3448*5113495bSYour Name 	};
3449*5113495bSYour Name 
3450*5113495bSYour Name 	hdd_enter();
3451*5113495bSYour Name 
3452*5113495bSYour Name 	request = osif_request_alloc(&params);
3453*5113495bSYour Name 	if (!request) {
3454*5113495bSYour Name 		hdd_err("Request allocation failure");
3455*5113495bSYour Name 		return -EINVAL;
3456*5113495bSYour Name 	}
3457*5113495bSYour Name 
3458*5113495bSYour Name 	context = osif_request_cookie(request);
3459*5113495bSYour Name 
3460*5113495bSYour Name 	status = sme_resume_dialog_cmd(hdd_ctx->mac_handle,
3461*5113495bSYour Name 				       twt_params, context);
3462*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3463*5113495bSYour Name 		hdd_err("Failed to send resume dialog command");
3464*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3465*5113495bSYour Name 		goto cleanup;
3466*5113495bSYour Name 	}
3467*5113495bSYour Name 
3468*5113495bSYour Name 	twt_cmd = WMI_HOST_TWT_RESUME_DIALOG_CMDID;
3469*5113495bSYour Name 
3470*5113495bSYour Name 	status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd);
3471*5113495bSYour Name 
3472*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3473*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
3474*5113495bSYour Name 		goto cleanup;
3475*5113495bSYour Name 	}
3476*5113495bSYour Name 
3477*5113495bSYour Name 	ack_priv = osif_request_priv(request);
3478*5113495bSYour Name 	if (ack_priv->status) {
3479*5113495bSYour Name 		hdd_err("Received TWT ack error. Reset twt command");
3480*5113495bSYour Name 		ucfg_mlme_reset_twt_active_cmd(
3481*5113495bSYour Name 				hdd_ctx->psoc,
3482*5113495bSYour Name 				(struct qdf_mac_addr *)twt_params->peer_macaddr,
3483*5113495bSYour Name 				twt_params->dialog_id);
3484*5113495bSYour Name 
3485*5113495bSYour Name 		switch (ack_priv->status) {
3486*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_INVALID_PARAM:
3487*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_UNKNOWN_ERROR:
3488*5113495bSYour Name 			ret = -EINVAL;
3489*5113495bSYour Name 			break;
3490*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_NOT_EXIST:
3491*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_NOT_PAUSED:
3492*5113495bSYour Name 			ret = -EAGAIN;
3493*5113495bSYour Name 			break;
3494*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_BUSY:
3495*5113495bSYour Name 			ret = -EINPROGRESS;
3496*5113495bSYour Name 			break;
3497*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_NO_RESOURCE:
3498*5113495bSYour Name 			ret = -ENOMEM;
3499*5113495bSYour Name 			break;
3500*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_CHAN_SW_IN_PROGRESS:
3501*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_ROAM_IN_PROGRESS:
3502*5113495bSYour Name 		case WMI_HOST_RESUME_TWT_STATUS_SCAN_IN_PROGRESS:
3503*5113495bSYour Name 			ret = -EBUSY;
3504*5113495bSYour Name 			break;
3505*5113495bSYour Name 		default:
3506*5113495bSYour Name 			ret = -EAGAIN;
3507*5113495bSYour Name 			break;
3508*5113495bSYour Name 		}
3509*5113495bSYour Name 	}
3510*5113495bSYour Name cleanup:
3511*5113495bSYour Name 	osif_request_put(request);
3512*5113495bSYour Name 	hdd_exit();
3513*5113495bSYour Name 
3514*5113495bSYour Name 	return ret;
3515*5113495bSYour Name }
3516*5113495bSYour Name 
3517*5113495bSYour Name /**
3518*5113495bSYour Name  * hdd_twt_pack_get_capabilities_resp  - TWT pack and send response to
3519*5113495bSYour Name  * userspace for get capabilities command
3520*5113495bSYour Name  * @adapter: Pointer to hdd adapter
3521*5113495bSYour Name  *
3522*5113495bSYour Name  * Return: QDF_STATUS
3523*5113495bSYour Name  */
3524*5113495bSYour Name static QDF_STATUS
hdd_twt_pack_get_capabilities_resp(struct hdd_adapter * adapter)3525*5113495bSYour Name hdd_twt_pack_get_capabilities_resp(struct hdd_adapter *adapter)
3526*5113495bSYour Name {
3527*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3528*5113495bSYour Name 	struct hdd_station_ctx *sta_ctx =
3529*5113495bSYour Name 		WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
3530*5113495bSYour Name 	struct nlattr *config_attr;
3531*5113495bSYour Name 	struct sk_buff *reply_skb;
3532*5113495bSYour Name 	size_t skb_len = NLMSG_HDRLEN;
3533*5113495bSYour Name 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
3534*5113495bSYour Name 	uint8_t connected_band;
3535*5113495bSYour Name 	uint8_t peer_cap = 0, self_cap = 0;
3536*5113495bSYour Name 	bool twt_req = false, twt_bcast_req = false;
3537*5113495bSYour Name 	bool is_twt_24ghz_allowed = true;
3538*5113495bSYour Name 	int ret;
3539*5113495bSYour Name 
3540*5113495bSYour Name 	/*
3541*5113495bSYour Name 	 * Length of attribute QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF &
3542*5113495bSYour Name 	 * QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER
3543*5113495bSYour Name 	 */
3544*5113495bSYour Name 	skb_len += 2 * nla_total_size(sizeof(u16)) + NLA_HDRLEN;
3545*5113495bSYour Name 
3546*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
3547*5113495bSYour Name 							     skb_len);
3548*5113495bSYour Name 	if (!reply_skb) {
3549*5113495bSYour Name 		hdd_err("TWT: get_caps alloc reply skb failed");
3550*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
3551*5113495bSYour Name 	}
3552*5113495bSYour Name 
3553*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
3554*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
3555*5113495bSYour Name 	if (!config_attr) {
3556*5113495bSYour Name 		hdd_err("TWT: nla_nest_start error");
3557*5113495bSYour Name 		qdf_status = QDF_STATUS_E_FAILURE;
3558*5113495bSYour Name 		goto free_skb;
3559*5113495bSYour Name 	}
3560*5113495bSYour Name 
3561*5113495bSYour Name 	/*
3562*5113495bSYour Name 	 * Userspace will query the TWT get capabilities before
3563*5113495bSYour Name 	 * issuing a get capabilities request. For legacy connection,
3564*5113495bSYour Name 	 * if the STA is connected, then check the "enable_twt_24ghz"
3565*5113495bSYour Name 	 * ini value to advertise the TWT requestor capability.
3566*5113495bSYour Name 	 * For MLO connection, TWT requestor capabilities are advertised
3567*5113495bSYour Name 	 * irrespective of connected band.
3568*5113495bSYour Name 	 */
3569*5113495bSYour Name 	if (!mlo_is_mld_sta(adapter->deflink->vdev)) {
3570*5113495bSYour Name 		connected_band = hdd_conn_get_connected_band(adapter->deflink);
3571*5113495bSYour Name 		if (connected_band == BAND_2G &&
3572*5113495bSYour Name 		    !ucfg_mlme_is_24ghz_twt_enabled(hdd_ctx->psoc))
3573*5113495bSYour Name 			is_twt_24ghz_allowed = false;
3574*5113495bSYour Name 	} else {
3575*5113495bSYour Name 		is_twt_24ghz_allowed = true;
3576*5113495bSYour Name 	}
3577*5113495bSYour Name 
3578*5113495bSYour Name 	/* fill the self_capability bitmap  */
3579*5113495bSYour Name 	ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &twt_req);
3580*5113495bSYour Name 	if (twt_req && is_twt_24ghz_allowed)
3581*5113495bSYour Name 		self_cap |= QCA_WLAN_TWT_CAPA_REQUESTOR;
3582*5113495bSYour Name 
3583*5113495bSYour Name 	ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc,
3584*5113495bSYour Name 					  &twt_bcast_req);
3585*5113495bSYour Name 	self_cap |= (twt_bcast_req ? QCA_WLAN_TWT_CAPA_BROADCAST : 0);
3586*5113495bSYour Name 
3587*5113495bSYour Name 	if (ucfg_mlme_is_flexible_twt_enabled(hdd_ctx->psoc))
3588*5113495bSYour Name 		self_cap |= QCA_WLAN_TWT_CAPA_FLEXIBLE;
3589*5113495bSYour Name 
3590*5113495bSYour Name 	/* Fill the Peer capability bitmap */
3591*5113495bSYour Name 	peer_cap = ucfg_mlme_get_twt_peer_capabilities(
3592*5113495bSYour Name 		hdd_ctx->psoc,
3593*5113495bSYour Name 		(struct qdf_mac_addr *)sta_ctx->conn_info.bssid.bytes);
3594*5113495bSYour Name 
3595*5113495bSYour Name 	if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF,
3596*5113495bSYour Name 			self_cap)) {
3597*5113495bSYour Name 		hdd_err("TWT: Failed to fill capabilities");
3598*5113495bSYour Name 		qdf_status = QDF_STATUS_E_FAILURE;
3599*5113495bSYour Name 		goto free_skb;
3600*5113495bSYour Name 	}
3601*5113495bSYour Name 
3602*5113495bSYour Name 	if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER,
3603*5113495bSYour Name 			peer_cap)) {
3604*5113495bSYour Name 		hdd_err("TWT: Failed to fill capabilities");
3605*5113495bSYour Name 		qdf_status = QDF_STATUS_E_FAILURE;
3606*5113495bSYour Name 		goto free_skb;
3607*5113495bSYour Name 	}
3608*5113495bSYour Name 
3609*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
3610*5113495bSYour Name 
3611*5113495bSYour Name 	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
3612*5113495bSYour Name 	return qdf_status_from_os_return(ret);
3613*5113495bSYour Name 
3614*5113495bSYour Name free_skb:
3615*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(reply_skb);
3616*5113495bSYour Name 	return qdf_status;
3617*5113495bSYour Name }
3618*5113495bSYour Name 
3619*5113495bSYour Name /**
3620*5113495bSYour Name  * hdd_twt_get_capabilities() - Process TWT get capabilities
3621*5113495bSYour Name  * in the received vendor command.
3622*5113495bSYour Name  * @adapter: adapter pointer
3623*5113495bSYour Name  * @twt_param_attr: nl attributes
3624*5113495bSYour Name  *
3625*5113495bSYour Name  * Handles QCA_WLAN_TWT_GET_CAPABILITIES
3626*5113495bSYour Name  *
3627*5113495bSYour Name  * Return: 0 on success, negative value on failure
3628*5113495bSYour Name  */
hdd_twt_get_capabilities(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)3629*5113495bSYour Name static int hdd_twt_get_capabilities(struct hdd_adapter *adapter,
3630*5113495bSYour Name 				    struct nlattr *twt_param_attr)
3631*5113495bSYour Name {
3632*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
3633*5113495bSYour Name 	QDF_STATUS status;
3634*5113495bSYour Name 	int ret = 0;
3635*5113495bSYour Name 
3636*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
3637*5113495bSYour Name 	if (ret < 0)
3638*5113495bSYour Name 		return -EINVAL;
3639*5113495bSYour Name 
3640*5113495bSYour Name 	if (adapter->device_mode != QDF_STA_MODE &&
3641*5113495bSYour Name 	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
3642*5113495bSYour Name 		return -EOPNOTSUPP;
3643*5113495bSYour Name 	}
3644*5113495bSYour Name 
3645*5113495bSYour Name 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
3646*5113495bSYour Name 		hdd_err_rl("vdev %d not in connected state, mode %d",
3647*5113495bSYour Name 			   adapter->deflink->vdev_id, adapter->device_mode);
3648*5113495bSYour Name 		return -EAGAIN;
3649*5113495bSYour Name 	}
3650*5113495bSYour Name 
3651*5113495bSYour Name 	if (hdd_is_roaming_in_progress(hdd_ctx))
3652*5113495bSYour Name 		return -EBUSY;
3653*5113495bSYour Name 
3654*5113495bSYour Name 	status = hdd_twt_pack_get_capabilities_resp(adapter);
3655*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
3656*5113495bSYour Name 		hdd_err_rl("TWT: Get capabilities failed");
3657*5113495bSYour Name 
3658*5113495bSYour Name 	return qdf_status_to_os_return(status);
3659*5113495bSYour Name }
3660*5113495bSYour Name 
3661*5113495bSYour Name /**
3662*5113495bSYour Name  * hdd_twt_resume_session - Process TWT resume operation
3663*5113495bSYour Name  * in the received vendor command and send it to firmware
3664*5113495bSYour Name  * @adapter: adapter pointer
3665*5113495bSYour Name  * @twt_param_attr: nl attributes
3666*5113495bSYour Name  *
3667*5113495bSYour Name  * Handles QCA_WLAN_TWT_RESUME
3668*5113495bSYour Name  *
3669*5113495bSYour Name  * Return: 0 on success, negative value on failure
3670*5113495bSYour Name  */
hdd_twt_resume_session(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)3671*5113495bSYour Name static int hdd_twt_resume_session(struct hdd_adapter *adapter,
3672*5113495bSYour Name 				  struct nlattr *twt_param_attr)
3673*5113495bSYour Name {
3674*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
3675*5113495bSYour Name 			WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
3676*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1];
3677*5113495bSYour Name 	struct wmi_twt_resume_dialog_cmd_param params = {0};
3678*5113495bSYour Name 	QDF_STATUS status;
3679*5113495bSYour Name 	int id, id2;
3680*5113495bSYour Name 	int ret;
3681*5113495bSYour Name 
3682*5113495bSYour Name 	ret = hdd_is_twt_command_allowed(adapter);
3683*5113495bSYour Name 	if (ret)
3684*5113495bSYour Name 		return ret;
3685*5113495bSYour Name 
3686*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes,
3687*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
3688*5113495bSYour Name 	params.vdev_id = adapter->deflink->vdev_id;
3689*5113495bSYour Name 
3690*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
3691*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX,
3692*5113495bSYour Name 					     twt_param_attr,
3693*5113495bSYour Name 					     qca_wlan_vendor_twt_resume_dialog_policy);
3694*5113495bSYour Name 	if (ret)
3695*5113495bSYour Name 		return ret;
3696*5113495bSYour Name 
3697*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID;
3698*5113495bSYour Name 	if (tb[id]) {
3699*5113495bSYour Name 		params.dialog_id = nla_get_u8(tb[id]);
3700*5113495bSYour Name 	} else {
3701*5113495bSYour Name 		params.dialog_id = 0;
3702*5113495bSYour Name 		hdd_debug("TWT_RESUME_FLOW_ID not specified. set to zero");
3703*5113495bSYour Name 	}
3704*5113495bSYour Name 
3705*5113495bSYour Name 	status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc,
3706*5113495bSYour Name 					       params.dialog_id);
3707*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3708*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
3709*5113495bSYour Name 		return -EOPNOTSUPP;
3710*5113495bSYour Name 	}
3711*5113495bSYour Name 
3712*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
3713*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
3714*5113495bSYour Name 					 params.dialog_id)) {
3715*5113495bSYour Name 		hdd_debug("vdev%d: TWT session %d setup incomplete",
3716*5113495bSYour Name 			  params.vdev_id, params.dialog_id);
3717*5113495bSYour Name 		return -EAGAIN;
3718*5113495bSYour Name 	}
3719*5113495bSYour Name 
3720*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT;
3721*5113495bSYour Name 	id2 = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT;
3722*5113495bSYour Name 	if (tb[id2])
3723*5113495bSYour Name 		params.sp_offset_us = nla_get_u32(tb[id2]);
3724*5113495bSYour Name 	else if (tb[id])
3725*5113495bSYour Name 		params.sp_offset_us = nla_get_u8(tb[id]);
3726*5113495bSYour Name 	else
3727*5113495bSYour Name 		params.sp_offset_us = 0;
3728*5113495bSYour Name 
3729*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE;
3730*5113495bSYour Name 	if (tb[id]) {
3731*5113495bSYour Name 		params.next_twt_size = nla_get_u32(tb[id]);
3732*5113495bSYour Name 	} else {
3733*5113495bSYour Name 		hdd_err_rl("TWT_RESUME NEXT_TWT_SIZE is must");
3734*5113495bSYour Name 		return -EINVAL;
3735*5113495bSYour Name 	}
3736*5113495bSYour Name 	if (params.next_twt_size > TWT_MAX_NEXT_TWT_SIZE)
3737*5113495bSYour Name 		return -EINVAL;
3738*5113495bSYour Name 
3739*5113495bSYour Name 	hdd_debug("twt_resume: vdev_id %d dialog_id %d peer mac_addr "
3740*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
3741*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr));
3742*5113495bSYour Name 
3743*5113495bSYour Name 	ret = hdd_send_twt_resume_dialog_cmd(adapter->hdd_ctx, &params);
3744*5113495bSYour Name 
3745*5113495bSYour Name 	return ret;
3746*5113495bSYour Name }
3747*5113495bSYour Name 
get_session_wake_duration(struct hdd_context * hdd_ctx,uint32_t dialog_id,struct qdf_mac_addr * peer_macaddr)3748*5113495bSYour Name static uint32_t get_session_wake_duration(struct hdd_context *hdd_ctx,
3749*5113495bSYour Name 					  uint32_t dialog_id,
3750*5113495bSYour Name 					  struct qdf_mac_addr *peer_macaddr)
3751*5113495bSYour Name {
3752*5113495bSYour Name 	struct wmi_host_twt_session_stats_info params = {0};
3753*5113495bSYour Name 	int num_twt_session = 0;
3754*5113495bSYour Name 
3755*5113495bSYour Name 	params.dialog_id = dialog_id;
3756*5113495bSYour Name 	qdf_mem_copy(params.peer_mac,
3757*5113495bSYour Name 		     peer_macaddr->bytes,
3758*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
3759*5113495bSYour Name 	hdd_debug("Get_params peer mac_addr " QDF_MAC_ADDR_FMT,
3760*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_mac));
3761*5113495bSYour Name 
3762*5113495bSYour Name 	num_twt_session = ucfg_twt_get_peer_session_params(hdd_ctx->psoc,
3763*5113495bSYour Name 							   &params);
3764*5113495bSYour Name 	if (num_twt_session)
3765*5113495bSYour Name 		return params.wake_dura_us;
3766*5113495bSYour Name 
3767*5113495bSYour Name 	return 0;
3768*5113495bSYour Name }
3769*5113495bSYour Name 
3770*5113495bSYour Name static int
wmi_twt_get_stats_status_to_vendor_twt_status(enum WMI_HOST_GET_STATS_TWT_STATUS status)3771*5113495bSYour Name wmi_twt_get_stats_status_to_vendor_twt_status(enum WMI_HOST_GET_STATS_TWT_STATUS status)
3772*5113495bSYour Name {
3773*5113495bSYour Name 	switch (status) {
3774*5113495bSYour Name 	case WMI_HOST_GET_STATS_TWT_STATUS_OK:
3775*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
3776*5113495bSYour Name 	case WMI_HOST_GET_STATS_TWT_STATUS_DIALOG_ID_NOT_EXIST:
3777*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
3778*5113495bSYour Name 	case WMI_HOST_GET_STATS_TWT_STATUS_INVALID_PARAM:
3779*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
3780*5113495bSYour Name 	default:
3781*5113495bSYour Name 		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
3782*5113495bSYour Name 	}
3783*5113495bSYour Name }
3784*5113495bSYour Name 
3785*5113495bSYour Name /**
3786*5113495bSYour Name  * hdd_twt_pack_get_stats_resp_nlmsg()- Packs and sends twt get stats response
3787*5113495bSYour Name  * @hdd_ctx: pointer to the hdd context
3788*5113495bSYour Name  * @reply_skb: pointer to response skb buffer
3789*5113495bSYour Name  * @params: Pointer to twt session parameter buffer
3790*5113495bSYour Name  * @num_session_stats: number of twt statistics
3791*5113495bSYour Name  *
3792*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
3793*5113495bSYour Name  */
3794*5113495bSYour Name static QDF_STATUS
hdd_twt_pack_get_stats_resp_nlmsg(struct hdd_context * hdd_ctx,struct sk_buff * reply_skb,struct twt_infra_cp_stats_event * params,uint32_t num_session_stats)3795*5113495bSYour Name hdd_twt_pack_get_stats_resp_nlmsg(struct hdd_context *hdd_ctx,
3796*5113495bSYour Name 				  struct sk_buff *reply_skb,
3797*5113495bSYour Name 				  struct twt_infra_cp_stats_event *params,
3798*5113495bSYour Name 				  uint32_t num_session_stats)
3799*5113495bSYour Name {
3800*5113495bSYour Name 	struct nlattr *config_attr, *nla_params;
3801*5113495bSYour Name 	int i, attr;
3802*5113495bSYour Name 	int vendor_status;
3803*5113495bSYour Name 	uint32_t duration;
3804*5113495bSYour Name 
3805*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
3806*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
3807*5113495bSYour Name 	if (!config_attr) {
3808*5113495bSYour Name 		hdd_err("get_params nla_nest_start error");
3809*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
3810*5113495bSYour Name 	}
3811*5113495bSYour Name 
3812*5113495bSYour Name 	for (i = 0; i < num_session_stats; i++) {
3813*5113495bSYour Name 
3814*5113495bSYour Name 		nla_params = nla_nest_start(reply_skb, i);
3815*5113495bSYour Name 		if (!nla_params) {
3816*5113495bSYour Name 			hdd_err("get_stats nla_nest_start error");
3817*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3818*5113495bSYour Name 		}
3819*5113495bSYour Name 
3820*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR;
3821*5113495bSYour Name 		if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
3822*5113495bSYour Name 			    params[i].peer_macaddr.bytes)) {
3823*5113495bSYour Name 			hdd_err("get_stats failed to put mac_addr");
3824*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3825*5113495bSYour Name 		}
3826*5113495bSYour Name 		hdd_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT,
3827*5113495bSYour Name 			  QDF_MAC_ADDR_REF(params[i].peer_macaddr.bytes));
3828*5113495bSYour Name 
3829*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
3830*5113495bSYour Name 		if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) {
3831*5113495bSYour Name 			hdd_err("get_stats failed to put dialog_id");
3832*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3833*5113495bSYour Name 		}
3834*5113495bSYour Name 
3835*5113495bSYour Name 		duration = get_session_wake_duration(hdd_ctx,
3836*5113495bSYour Name 						     params[i].dialog_id,
3837*5113495bSYour Name 						     &params[i].peer_macaddr);
3838*5113495bSYour Name 
3839*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION;
3840*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, duration)) {
3841*5113495bSYour Name 			hdd_err("get_params failed to put Wake duration");
3842*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3843*5113495bSYour Name 		}
3844*5113495bSYour Name 		hdd_debug("dialog_id %d wake duration %d num sp cycles %d",
3845*5113495bSYour Name 			  params[i].dialog_id, duration,
3846*5113495bSYour Name 			  params[i].num_sp_cycles);
3847*5113495bSYour Name 
3848*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS;
3849*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].num_sp_cycles)) {
3850*5113495bSYour Name 			hdd_err("get_params failed to put num_sp_cycles");
3851*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3852*5113495bSYour Name 		}
3853*5113495bSYour Name 
3854*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION;
3855*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].avg_sp_dur_us)) {
3856*5113495bSYour Name 			hdd_err("get_params failed to put avg_sp_dur_us");
3857*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3858*5113495bSYour Name 		}
3859*5113495bSYour Name 
3860*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION;
3861*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].min_sp_dur_us)) {
3862*5113495bSYour Name 			hdd_err("get_params failed to put min_sp_dur_us");
3863*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3864*5113495bSYour Name 		}
3865*5113495bSYour Name 
3866*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION;
3867*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].max_sp_dur_us)) {
3868*5113495bSYour Name 			hdd_err("get_params failed to put max_sp_dur_us");
3869*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3870*5113495bSYour Name 		}
3871*5113495bSYour Name 
3872*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU;
3873*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].tx_mpdu_per_sp)) {
3874*5113495bSYour Name 			hdd_err("get_params failed to put tx_mpdu_per_sp");
3875*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3876*5113495bSYour Name 		}
3877*5113495bSYour Name 
3878*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU;
3879*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].rx_mpdu_per_sp)) {
3880*5113495bSYour Name 			hdd_err("get_params failed to put rx_mpdu_per_sp");
3881*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3882*5113495bSYour Name 		}
3883*5113495bSYour Name 
3884*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE;
3885*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].tx_bytes_per_sp)) {
3886*5113495bSYour Name 			hdd_err("get_params failed to put tx_bytes_per_sp");
3887*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3888*5113495bSYour Name 		}
3889*5113495bSYour Name 
3890*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE;
3891*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, params[i].rx_bytes_per_sp)) {
3892*5113495bSYour Name 			hdd_err("get_params failed to put rx_bytes_per_sp");
3893*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3894*5113495bSYour Name 		}
3895*5113495bSYour Name 
3896*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS;
3897*5113495bSYour Name 		vendor_status = wmi_twt_get_stats_status_to_vendor_twt_status(params[i].status);
3898*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, vendor_status)) {
3899*5113495bSYour Name 			hdd_err("get_params failed to put status");
3900*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
3901*5113495bSYour Name 		}
3902*5113495bSYour Name 		nla_nest_end(reply_skb, nla_params);
3903*5113495bSYour Name 	}
3904*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
3905*5113495bSYour Name 
3906*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
3907*5113495bSYour Name }
3908*5113495bSYour Name 
3909*5113495bSYour Name /**
3910*5113495bSYour Name  * hdd_twt_clear_session_traffic_stats() - Parses twt nl attributes and
3911*5113495bSYour Name  * sends clear twt stats request for a single or all sessions
3912*5113495bSYour Name  * @adapter: hdd_adapter
3913*5113495bSYour Name  * @twt_param_attr: twt nl attributes
3914*5113495bSYour Name  *
3915*5113495bSYour Name  * Return: 0 on success, negative value on failure
3916*5113495bSYour Name  */
hdd_twt_clear_session_traffic_stats(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)3917*5113495bSYour Name static int hdd_twt_clear_session_traffic_stats(struct hdd_adapter *adapter,
3918*5113495bSYour Name 					       struct nlattr *twt_param_attr)
3919*5113495bSYour Name {
3920*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
3921*5113495bSYour Name 				WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
3922*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1];
3923*5113495bSYour Name 	int ret, id;
3924*5113495bSYour Name 	uint32_t dialog_id;
3925*5113495bSYour Name 	uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
3926*5113495bSYour Name 	bool is_stats_tgt_cap_enabled;
3927*5113495bSYour Name 	QDF_STATUS status;
3928*5113495bSYour Name 
3929*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(
3930*5113495bSYour Name 				tb,
3931*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX,
3932*5113495bSYour Name 				twt_param_attr,
3933*5113495bSYour Name 				qca_wlan_vendor_twt_stats_dialog_policy);
3934*5113495bSYour Name 	if (ret)
3935*5113495bSYour Name 		return ret;
3936*5113495bSYour Name 
3937*5113495bSYour Name 	ucfg_mlme_get_twt_statistics_tgt_cap(adapter->hdd_ctx->psoc,
3938*5113495bSYour Name 					     &is_stats_tgt_cap_enabled);
3939*5113495bSYour Name 	if (!is_stats_tgt_cap_enabled) {
3940*5113495bSYour Name 		hdd_debug("TWT Stats not supported by target");
3941*5113495bSYour Name 		return -EOPNOTSUPP;
3942*5113495bSYour Name 	}
3943*5113495bSYour Name 
3944*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
3945*5113495bSYour Name 	if (!tb[id]) {
3946*5113495bSYour Name 		hdd_err_rl("TWT Clear stats - dialog id param is must");
3947*5113495bSYour Name 		return -EINVAL;
3948*5113495bSYour Name 	}
3949*5113495bSYour Name 
3950*5113495bSYour Name 	dialog_id = (uint32_t)nla_get_u8(tb[id]);
3951*5113495bSYour Name 
3952*5113495bSYour Name 	qdf_mem_copy(peer_mac,
3953*5113495bSYour Name 		     hdd_sta_ctx->conn_info.bssid.bytes,
3954*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
3955*5113495bSYour Name 	hdd_debug("dialog_id %d peer mac_addr " QDF_MAC_ADDR_FMT,
3956*5113495bSYour Name 		  dialog_id, QDF_MAC_ADDR_REF(peer_mac));
3957*5113495bSYour Name 
3958*5113495bSYour Name 	status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc,
3959*5113495bSYour Name 					       dialog_id);
3960*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
3961*5113495bSYour Name 		hdd_debug("All TWT sessions not supported by target");
3962*5113495bSYour Name 		return -EOPNOTSUPP;
3963*5113495bSYour Name 	}
3964*5113495bSYour Name 
3965*5113495bSYour Name 	if (ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc,
3966*5113495bSYour Name 						 &hdd_sta_ctx->conn_info.bssid,
3967*5113495bSYour Name 						 TWT_ALL_SESSIONS_DIALOG_ID,
3968*5113495bSYour Name 						 WLAN_TWT_STATISTICS, NULL) ||
3969*5113495bSYour Name 	   ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc,
3970*5113495bSYour Name 						&hdd_sta_ctx->conn_info.bssid,
3971*5113495bSYour Name 						TWT_ALL_SESSIONS_DIALOG_ID,
3972*5113495bSYour Name 						WLAN_TWT_CLEAR_STATISTICS,
3973*5113495bSYour Name 						NULL)) {
3974*5113495bSYour Name 		hdd_warn("Already TWT statistics or clear statistics exists");
3975*5113495bSYour Name 		return -EALREADY;
3976*5113495bSYour Name 	}
3977*5113495bSYour Name 
3978*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
3979*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
3980*5113495bSYour Name 					 dialog_id)) {
3981*5113495bSYour Name 		hdd_debug("TWT session %d setup incomplete", dialog_id);
3982*5113495bSYour Name 		return -EAGAIN;
3983*5113495bSYour Name 	}
3984*5113495bSYour Name 
3985*5113495bSYour Name 	ret = wlan_cfg80211_mc_twt_clear_infra_cp_stats(adapter->deflink->vdev,
3986*5113495bSYour Name 							dialog_id, peer_mac);
3987*5113495bSYour Name 
3988*5113495bSYour Name 	return ret;
3989*5113495bSYour Name }
3990*5113495bSYour Name 
3991*5113495bSYour Name /**
3992*5113495bSYour Name  * hdd_twt_request_session_traffic_stats() - Obtains twt session
3993*5113495bSYour Name  * traffic statistics and sends response to the user space
3994*5113495bSYour Name  * @adapter: hdd_adapter
3995*5113495bSYour Name  * @dialog_id: dialog id of the twt session
3996*5113495bSYour Name  * @peer_mac: Mac address of the peer
3997*5113495bSYour Name  *
3998*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
3999*5113495bSYour Name  */
4000*5113495bSYour Name static QDF_STATUS
hdd_twt_request_session_traffic_stats(struct hdd_adapter * adapter,uint32_t dialog_id,uint8_t * peer_mac)4001*5113495bSYour Name hdd_twt_request_session_traffic_stats(struct hdd_adapter *adapter,
4002*5113495bSYour Name 				      uint32_t dialog_id, uint8_t *peer_mac)
4003*5113495bSYour Name {
4004*5113495bSYour Name 	int errno;
4005*5113495bSYour Name 	int skb_len;
4006*5113495bSYour Name 	struct sk_buff *reply_skb;
4007*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
4008*5113495bSYour Name 	struct infra_cp_stats_event *event;
4009*5113495bSYour Name 
4010*5113495bSYour Name 	if (!adapter || !peer_mac)
4011*5113495bSYour Name 		return status;
4012*5113495bSYour Name 
4013*5113495bSYour Name 	event = wlan_cfg80211_mc_twt_get_infra_cp_stats(adapter->deflink->vdev,
4014*5113495bSYour Name 							dialog_id,
4015*5113495bSYour Name 							peer_mac,
4016*5113495bSYour Name 							&errno);
4017*5113495bSYour Name 	if (!event)
4018*5113495bSYour Name 		return qdf_status_from_os_return(errno);
4019*5113495bSYour Name 
4020*5113495bSYour Name 	skb_len = hdd_get_twt_get_stats_event_len();
4021*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
4022*5113495bSYour Name 						adapter->hdd_ctx->wiphy,
4023*5113495bSYour Name 						skb_len);
4024*5113495bSYour Name 	if (!reply_skb) {
4025*5113495bSYour Name 		hdd_err("Get stats - alloc reply_skb failed");
4026*5113495bSYour Name 		status = QDF_STATUS_E_NOMEM;
4027*5113495bSYour Name 		goto free_event;
4028*5113495bSYour Name 	}
4029*5113495bSYour Name 
4030*5113495bSYour Name 	status = hdd_twt_pack_get_stats_resp_nlmsg(
4031*5113495bSYour Name 						adapter->hdd_ctx,
4032*5113495bSYour Name 						reply_skb,
4033*5113495bSYour Name 						event->twt_infra_cp_stats,
4034*5113495bSYour Name 						event->num_twt_infra_cp_stats);
4035*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
4036*5113495bSYour Name 		hdd_err("Get stats - Failed to pack nl response");
4037*5113495bSYour Name 		goto free_skb;
4038*5113495bSYour Name 	}
4039*5113495bSYour Name 
4040*5113495bSYour Name 	qdf_mem_free(event->twt_infra_cp_stats);
4041*5113495bSYour Name 	qdf_mem_free(event);
4042*5113495bSYour Name 
4043*5113495bSYour Name 	errno = wlan_cfg80211_vendor_cmd_reply(reply_skb);
4044*5113495bSYour Name 	return qdf_status_from_os_return(errno);
4045*5113495bSYour Name 
4046*5113495bSYour Name free_skb:
4047*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(reply_skb);
4048*5113495bSYour Name 
4049*5113495bSYour Name free_event:
4050*5113495bSYour Name 	qdf_mem_free(event->twt_infra_cp_stats);
4051*5113495bSYour Name 	qdf_mem_free(event);
4052*5113495bSYour Name 
4053*5113495bSYour Name 	return status;
4054*5113495bSYour Name }
4055*5113495bSYour Name 
4056*5113495bSYour Name /**
4057*5113495bSYour Name  * hdd_twt_get_session_traffic_stats() - Parses twt nl attributes, obtains twt
4058*5113495bSYour Name  * session parameters based on dialog_id and returns to user via nl layer
4059*5113495bSYour Name  * @adapter: hdd_adapter
4060*5113495bSYour Name  * @twt_param_attr: twt nl attributes
4061*5113495bSYour Name  *
4062*5113495bSYour Name  * Return: 0 on success, negative value on failure
4063*5113495bSYour Name  */
hdd_twt_get_session_traffic_stats(struct hdd_adapter * adapter,struct nlattr * twt_param_attr)4064*5113495bSYour Name static int hdd_twt_get_session_traffic_stats(struct hdd_adapter *adapter,
4065*5113495bSYour Name 					     struct nlattr *twt_param_attr)
4066*5113495bSYour Name {
4067*5113495bSYour Name 	struct hdd_station_ctx *hdd_sta_ctx =
4068*5113495bSYour Name 				WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
4069*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1];
4070*5113495bSYour Name 	int ret, id;
4071*5113495bSYour Name 	QDF_STATUS qdf_status;
4072*5113495bSYour Name 	uint32_t dialog_id;
4073*5113495bSYour Name 	uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
4074*5113495bSYour Name 	bool is_stats_tgt_cap_enabled;
4075*5113495bSYour Name 
4076*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(
4077*5113495bSYour Name 				tb,
4078*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX,
4079*5113495bSYour Name 				twt_param_attr,
4080*5113495bSYour Name 				qca_wlan_vendor_twt_stats_dialog_policy);
4081*5113495bSYour Name 	if (ret)
4082*5113495bSYour Name 		return ret;
4083*5113495bSYour Name 
4084*5113495bSYour Name 	ucfg_mlme_get_twt_statistics_tgt_cap(adapter->hdd_ctx->psoc,
4085*5113495bSYour Name 					     &is_stats_tgt_cap_enabled);
4086*5113495bSYour Name 	if (!is_stats_tgt_cap_enabled) {
4087*5113495bSYour Name 		hdd_debug("TWT Stats not supported by target");
4088*5113495bSYour Name 		return -EOPNOTSUPP;
4089*5113495bSYour Name 	}
4090*5113495bSYour Name 
4091*5113495bSYour Name 	if (ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc,
4092*5113495bSYour Name 						 &hdd_sta_ctx->conn_info.bssid,
4093*5113495bSYour Name 						 TWT_ALL_SESSIONS_DIALOG_ID,
4094*5113495bSYour Name 						 WLAN_TWT_STATISTICS, NULL) ||
4095*5113495bSYour Name 	    ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc,
4096*5113495bSYour Name 						 &hdd_sta_ctx->conn_info.bssid,
4097*5113495bSYour Name 						 TWT_ALL_SESSIONS_DIALOG_ID,
4098*5113495bSYour Name 						 WLAN_TWT_CLEAR_STATISTICS,
4099*5113495bSYour Name 						 NULL)) {
4100*5113495bSYour Name 		hdd_warn("Already TWT statistics or clear statistics exists");
4101*5113495bSYour Name 		return -EALREADY;
4102*5113495bSYour Name 	}
4103*5113495bSYour Name 
4104*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
4105*5113495bSYour Name 	if (tb[id])
4106*5113495bSYour Name 		dialog_id = (uint32_t)nla_get_u8(tb[id]);
4107*5113495bSYour Name 	else
4108*5113495bSYour Name 		dialog_id = 0;
4109*5113495bSYour Name 
4110*5113495bSYour Name 	hdd_debug("get_stats dialog_id %d", dialog_id);
4111*5113495bSYour Name 
4112*5113495bSYour Name 	qdf_mem_copy(peer_mac,
4113*5113495bSYour Name 		     hdd_sta_ctx->conn_info.bssid.bytes,
4114*5113495bSYour Name 		     QDF_MAC_ADDR_SIZE);
4115*5113495bSYour Name 	hdd_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT,
4116*5113495bSYour Name 		  QDF_MAC_ADDR_REF(peer_mac));
4117*5113495bSYour Name 
4118*5113495bSYour Name 	if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc,
4119*5113495bSYour Name 					 &hdd_sta_ctx->conn_info.bssid,
4120*5113495bSYour Name 					 dialog_id)) {
4121*5113495bSYour Name 		hdd_debug("TWT session %d setup incomplete", dialog_id);
4122*5113495bSYour Name 		return -EAGAIN;
4123*5113495bSYour Name 	}
4124*5113495bSYour Name 
4125*5113495bSYour Name 	ucfg_mlme_set_twt_command_in_progress(adapter->hdd_ctx->psoc,
4126*5113495bSYour Name 					      &hdd_sta_ctx->conn_info.bssid,
4127*5113495bSYour Name 					      dialog_id,
4128*5113495bSYour Name 					      WLAN_TWT_STATISTICS);
4129*5113495bSYour Name 	qdf_status = hdd_twt_request_session_traffic_stats(adapter,
4130*5113495bSYour Name 							   dialog_id, peer_mac);
4131*5113495bSYour Name 	ucfg_mlme_set_twt_command_in_progress(adapter->hdd_ctx->psoc,
4132*5113495bSYour Name 					      &hdd_sta_ctx->conn_info.bssid,
4133*5113495bSYour Name 					      dialog_id,
4134*5113495bSYour Name 					      WLAN_TWT_NONE);
4135*5113495bSYour Name 
4136*5113495bSYour Name 	return qdf_status_to_os_return(qdf_status);
4137*5113495bSYour Name }
4138*5113495bSYour Name 
4139*5113495bSYour Name /**
4140*5113495bSYour Name  * hdd_twt_notify_pack_nlmsg() - pack the skb with
4141*5113495bSYour Name  * twt notify event from firmware
4142*5113495bSYour Name  * @reply_skb: skb to store the response
4143*5113495bSYour Name  *
4144*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
4145*5113495bSYour Name  * on failure
4146*5113495bSYour Name  */
4147*5113495bSYour Name static QDF_STATUS
hdd_twt_notify_pack_nlmsg(struct sk_buff * reply_skb)4148*5113495bSYour Name hdd_twt_notify_pack_nlmsg(struct sk_buff *reply_skb)
4149*5113495bSYour Name {
4150*5113495bSYour Name 	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
4151*5113495bSYour Name 		       QCA_WLAN_TWT_SETUP_READY_NOTIFY)) {
4152*5113495bSYour Name 		hdd_err("Failed to put TWT notify operation");
4153*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
4154*5113495bSYour Name 	}
4155*5113495bSYour Name 
4156*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
4157*5113495bSYour Name }
4158*5113495bSYour Name 
4159*5113495bSYour Name /**
4160*5113495bSYour Name  * hdd_twt_notify_cb() - callback function
4161*5113495bSYour Name  * to get twt notify event
4162*5113495bSYour Name  * @psoc: Pointer to global psoc
4163*5113495bSYour Name  * @params: Pointer to notify param event buffer
4164*5113495bSYour Name  *
4165*5113495bSYour Name  * Return: None
4166*5113495bSYour Name  */
4167*5113495bSYour Name static void
hdd_twt_notify_cb(struct wlan_objmgr_psoc * psoc,struct wmi_twt_notify_event_param * params)4168*5113495bSYour Name hdd_twt_notify_cb(struct wlan_objmgr_psoc *psoc,
4169*5113495bSYour Name 		  struct wmi_twt_notify_event_param *params)
4170*5113495bSYour Name {
4171*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
4172*5113495bSYour Name 	struct wireless_dev *wdev;
4173*5113495bSYour Name 	struct sk_buff *twt_vendor_event;
4174*5113495bSYour Name 	size_t data_len;
4175*5113495bSYour Name 	QDF_STATUS status;
4176*5113495bSYour Name 
4177*5113495bSYour Name 	hdd_enter();
4178*5113495bSYour Name 
4179*5113495bSYour Name 	link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id);
4180*5113495bSYour Name 	if (!link_info || hdd_validate_adapter(link_info->adapter))
4181*5113495bSYour Name 		return;
4182*5113495bSYour Name 
4183*5113495bSYour Name 	wdev = &link_info->adapter->wdev;
4184*5113495bSYour Name 
4185*5113495bSYour Name 	data_len = NLA_HDRLEN;
4186*5113495bSYour Name 	data_len += nla_total_size(sizeof(u8));
4187*5113495bSYour Name 
4188*5113495bSYour Name 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
4189*5113495bSYour Name 				wdev->wiphy, wdev,
4190*5113495bSYour Name 				data_len,
4191*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
4192*5113495bSYour Name 				GFP_KERNEL);
4193*5113495bSYour Name 	if (!twt_vendor_event) {
4194*5113495bSYour Name 		hdd_err("Notify skb alloc failed");
4195*5113495bSYour Name 		return;
4196*5113495bSYour Name 	}
4197*5113495bSYour Name 
4198*5113495bSYour Name 	hdd_debug("Notify vdev_id %d", params->vdev_id);
4199*5113495bSYour Name 
4200*5113495bSYour Name 	status = hdd_twt_notify_pack_nlmsg(twt_vendor_event);
4201*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
4202*5113495bSYour Name 		hdd_err("Failed to pack nl notify event");
4203*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
4204*5113495bSYour Name 		return;
4205*5113495bSYour Name 	}
4206*5113495bSYour Name 
4207*5113495bSYour Name 	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
4208*5113495bSYour Name 
4209*5113495bSYour Name 	hdd_exit();
4210*5113495bSYour Name }
4211*5113495bSYour Name 
4212*5113495bSYour Name /**
4213*5113495bSYour Name  * hdd_twt_configure - Process the TWT
4214*5113495bSYour Name  * operation in the received vendor command
4215*5113495bSYour Name  * @adapter: adapter pointer
4216*5113495bSYour Name  * @tb: nl attributes
4217*5113495bSYour Name  *
4218*5113495bSYour Name  * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION
4219*5113495bSYour Name  *
4220*5113495bSYour Name  * Return: 0 for Success and negative value for failure
4221*5113495bSYour Name  */
hdd_twt_configure(struct hdd_adapter * adapter,struct nlattr ** tb)4222*5113495bSYour Name static int hdd_twt_configure(struct hdd_adapter *adapter,
4223*5113495bSYour Name 			     struct nlattr **tb)
4224*5113495bSYour Name {
4225*5113495bSYour Name 	enum qca_wlan_twt_operation twt_oper;
4226*5113495bSYour Name 	struct nlattr *twt_oper_attr;
4227*5113495bSYour Name 	struct nlattr *twt_param_attr;
4228*5113495bSYour Name 	uint32_t id;
4229*5113495bSYour Name 	int ret = 0;
4230*5113495bSYour Name 
4231*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION;
4232*5113495bSYour Name 	twt_oper_attr = tb[id];
4233*5113495bSYour Name 
4234*5113495bSYour Name 	if (!twt_oper_attr) {
4235*5113495bSYour Name 		hdd_err("TWT operation NOT specified");
4236*5113495bSYour Name 		return -EINVAL;
4237*5113495bSYour Name 	}
4238*5113495bSYour Name 
4239*5113495bSYour Name 	twt_oper = nla_get_u8(twt_oper_attr);
4240*5113495bSYour Name 
4241*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS;
4242*5113495bSYour Name 	twt_param_attr = tb[id];
4243*5113495bSYour Name 
4244*5113495bSYour Name 	if (!twt_param_attr &&
4245*5113495bSYour Name 	    twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES &&
4246*5113495bSYour Name 	    twt_oper != QCA_WLAN_TWT_SUSPEND) {
4247*5113495bSYour Name 		hdd_err("TWT parameters NOT specified");
4248*5113495bSYour Name 		return -EINVAL;
4249*5113495bSYour Name 	}
4250*5113495bSYour Name 
4251*5113495bSYour Name 	hdd_debug("TWT Operation 0x%x", twt_oper);
4252*5113495bSYour Name 
4253*5113495bSYour Name 	switch (twt_oper) {
4254*5113495bSYour Name 	case QCA_WLAN_TWT_SET:
4255*5113495bSYour Name 		ret = hdd_twt_setup_session(adapter, twt_param_attr);
4256*5113495bSYour Name 		break;
4257*5113495bSYour Name 	case QCA_WLAN_TWT_GET:
4258*5113495bSYour Name 		ret = hdd_twt_get_session_params(adapter, twt_param_attr);
4259*5113495bSYour Name 		break;
4260*5113495bSYour Name 	case QCA_WLAN_TWT_TERMINATE:
4261*5113495bSYour Name 		ret = hdd_twt_terminate_session(adapter, twt_param_attr);
4262*5113495bSYour Name 		break;
4263*5113495bSYour Name 	case QCA_WLAN_TWT_SUSPEND:
4264*5113495bSYour Name 		ret = hdd_twt_pause_session(adapter, twt_param_attr);
4265*5113495bSYour Name 		break;
4266*5113495bSYour Name 	case QCA_WLAN_TWT_RESUME:
4267*5113495bSYour Name 		ret = hdd_twt_resume_session(adapter, twt_param_attr);
4268*5113495bSYour Name 		break;
4269*5113495bSYour Name 	case QCA_WLAN_TWT_NUDGE:
4270*5113495bSYour Name 		ret = hdd_twt_nudge_session(adapter, twt_param_attr);
4271*5113495bSYour Name 		break;
4272*5113495bSYour Name 	case QCA_WLAN_TWT_GET_CAPABILITIES:
4273*5113495bSYour Name 		ret = hdd_twt_get_capabilities(adapter, twt_param_attr);
4274*5113495bSYour Name 		break;
4275*5113495bSYour Name 	case QCA_WLAN_TWT_GET_STATS:
4276*5113495bSYour Name 		ret = hdd_twt_get_session_traffic_stats(adapter,
4277*5113495bSYour Name 							twt_param_attr);
4278*5113495bSYour Name 		break;
4279*5113495bSYour Name 	case QCA_WLAN_TWT_CLEAR_STATS:
4280*5113495bSYour Name 		ret = hdd_twt_clear_session_traffic_stats(adapter,
4281*5113495bSYour Name 							  twt_param_attr);
4282*5113495bSYour Name 		break;
4283*5113495bSYour Name 	case QCA_WLAN_TWT_SET_PARAM:
4284*5113495bSYour Name 		ret = hdd_twt_set_param(adapter, twt_param_attr);
4285*5113495bSYour Name 		break;
4286*5113495bSYour Name 	default:
4287*5113495bSYour Name 		hdd_err("Invalid TWT Operation");
4288*5113495bSYour Name 		ret = -EINVAL;
4289*5113495bSYour Name 		break;
4290*5113495bSYour Name 	}
4291*5113495bSYour Name 
4292*5113495bSYour Name 	return ret;
4293*5113495bSYour Name }
4294*5113495bSYour Name 
hdd_update_tgt_twt_cap(struct hdd_context * hdd_ctx,struct wma_tgt_cfg * cfg)4295*5113495bSYour Name void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
4296*5113495bSYour Name 			    struct wma_tgt_cfg *cfg)
4297*5113495bSYour Name {
4298*5113495bSYour Name 	struct wma_tgt_services *services = &cfg->services;
4299*5113495bSYour Name 	bool twt_bcast_req;
4300*5113495bSYour Name 	bool twt_bcast_res;
4301*5113495bSYour Name 	bool twt_req, twt_res, enable_twt;
4302*5113495bSYour Name 
4303*5113495bSYour Name 	enable_twt = ucfg_mlme_is_twt_enabled(hdd_ctx->psoc);
4304*5113495bSYour Name 
4305*5113495bSYour Name 	ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &twt_req);
4306*5113495bSYour Name 
4307*5113495bSYour Name 	ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &twt_res);
4308*5113495bSYour Name 
4309*5113495bSYour Name 	ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc,
4310*5113495bSYour Name 					  &twt_bcast_req);
4311*5113495bSYour Name 
4312*5113495bSYour Name 	ucfg_mlme_get_twt_bcast_responder(hdd_ctx->psoc,
4313*5113495bSYour Name 					  &twt_bcast_res);
4314*5113495bSYour Name 
4315*5113495bSYour Name 	hdd_debug("ini: enable_twt=%d, bcast_req=%d, bcast_res=%d",
4316*5113495bSYour Name 		  enable_twt, twt_bcast_req, twt_bcast_res);
4317*5113495bSYour Name 	hdd_debug("ini: twt_req=%d, twt_res=%d", twt_req, twt_res);
4318*5113495bSYour Name 	hdd_debug("svc:  req=%d, res=%d, bcast_req=%d, bcast_res=%d legacy_bcast_twt:%d",
4319*5113495bSYour Name 		  services->twt_requestor, services->twt_responder,
4320*5113495bSYour Name 		  cfg->twt_bcast_req_support, cfg->twt_bcast_res_support,
4321*5113495bSYour Name 		  cfg->legacy_bcast_twt_support);
4322*5113495bSYour Name 
4323*5113495bSYour Name 	/*
4324*5113495bSYour Name 	 * Set the twt fw responder service capability
4325*5113495bSYour Name 	 */
4326*5113495bSYour Name 	ucfg_mlme_set_twt_res_service_cap(hdd_ctx->psoc,
4327*5113495bSYour Name 					  services->twt_responder);
4328*5113495bSYour Name 	/*
4329*5113495bSYour Name 	 * The HE cap IE in frame will have intersection of
4330*5113495bSYour Name 	 * "enable_twt" ini, twt requestor fw service cap and
4331*5113495bSYour Name 	 * "twt_requestor" ini requestor bit after this
4332*5113495bSYour Name 	 * set operation.
4333*5113495bSYour Name 	 */
4334*5113495bSYour Name 	ucfg_mlme_set_twt_requestor(hdd_ctx->psoc,
4335*5113495bSYour Name 				    QDF_MIN(services->twt_requestor,
4336*5113495bSYour Name 					    (enable_twt && twt_req)));
4337*5113495bSYour Name 
4338*5113495bSYour Name 	/*
4339*5113495bSYour Name 	 * The HE cap IE in frame will have intersection of
4340*5113495bSYour Name 	 * "enable_twt" ini, twt responder fw service cap and
4341*5113495bSYour Name 	 * "twt_responder" ini responder bit after this
4342*5113495bSYour Name 	 * set operation.
4343*5113495bSYour Name 	 */
4344*5113495bSYour Name 	ucfg_mlme_set_twt_responder(hdd_ctx->psoc,
4345*5113495bSYour Name 				    QDF_MIN(services->twt_responder,
4346*5113495bSYour Name 					    (enable_twt && twt_res)));
4347*5113495bSYour Name 	/*
4348*5113495bSYour Name 	 * The HE cap IE in frame will have intersection of
4349*5113495bSYour Name 	 * "enable_twt" ini, twt requestor fw service cap and
4350*5113495bSYour Name 	 * "twt_bcast_req_resp_config" ini requestor bit after this
4351*5113495bSYour Name 	 * set operation.
4352*5113495bSYour Name 	 */
4353*5113495bSYour Name 	ucfg_mlme_set_twt_bcast_requestor(
4354*5113495bSYour Name 			hdd_ctx->psoc,
4355*5113495bSYour Name 			QDF_MIN((cfg->twt_bcast_req_support ||
4356*5113495bSYour Name 				 cfg->legacy_bcast_twt_support),
4357*5113495bSYour Name 				(enable_twt && twt_bcast_req)));
4358*5113495bSYour Name 
4359*5113495bSYour Name 	/*
4360*5113495bSYour Name 	 * The HE cap IE in frame will have intersection of
4361*5113495bSYour Name 	 * "enable_twt" ini, twt responder fw service cap and
4362*5113495bSYour Name 	 * "twt_bcast_req_resp_config" ini responder bit after this
4363*5113495bSYour Name 	 * set operation.
4364*5113495bSYour Name 	 */
4365*5113495bSYour Name 	ucfg_mlme_set_twt_bcast_responder(
4366*5113495bSYour Name 			hdd_ctx->psoc,
4367*5113495bSYour Name 			QDF_MIN((cfg->twt_bcast_res_support ||
4368*5113495bSYour Name 				 cfg->legacy_bcast_twt_support),
4369*5113495bSYour Name 				(enable_twt && twt_bcast_res)));
4370*5113495bSYour Name 
4371*5113495bSYour Name 	ucfg_mlme_set_twt_nudge_tgt_cap(hdd_ctx->psoc, cfg->twt_nudge_enabled);
4372*5113495bSYour Name 	ucfg_mlme_set_twt_all_twt_tgt_cap(hdd_ctx->psoc,
4373*5113495bSYour Name 					  cfg->all_twt_enabled);
4374*5113495bSYour Name 	ucfg_mlme_set_twt_statistics_tgt_cap(hdd_ctx->psoc,
4375*5113495bSYour Name 					     cfg->twt_stats_enabled);
4376*5113495bSYour Name }
4377*5113495bSYour Name 
hdd_send_twt_requestor_enable_cmd(struct hdd_context * hdd_ctx)4378*5113495bSYour Name QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx)
4379*5113495bSYour Name {
4380*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
4381*5113495bSYour Name 	struct twt_enable_disable_conf twt_en_dis = {0};
4382*5113495bSYour Name 	bool is_requestor_en, twt_bcast_requestor = false;
4383*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4384*5113495bSYour Name 
4385*5113495bSYour Name 	ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &is_requestor_en);
4386*5113495bSYour Name 	ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc, &twt_bcast_requestor);
4387*5113495bSYour Name 	twt_en_dis.bcast_en = twt_bcast_requestor;
4388*5113495bSYour Name 
4389*5113495bSYour Name 	ucfg_mlme_get_twt_congestion_timeout(hdd_ctx->psoc,
4390*5113495bSYour Name 					     &twt_en_dis.congestion_timeout);
4391*5113495bSYour Name 	hdd_debug("TWT mlme cfg:req: %d, bcast:%d, cong:%d, pdev:%d",
4392*5113495bSYour Name 		  is_requestor_en, twt_en_dis.bcast_en,
4393*5113495bSYour Name 		  twt_en_dis.congestion_timeout, pdev_id);
4394*5113495bSYour Name 
4395*5113495bSYour Name 	/* The below code takes care of the following :
4396*5113495bSYour Name 	 * If user wants to separately enable requestor role, and also the
4397*5113495bSYour Name 	 * broadcast TWT capabilities separately for each role. This is done
4398*5113495bSYour Name 	 * by reusing the INI configuration to indicate the user preference
4399*5113495bSYour Name 	 * and sending the command accordingly.
4400*5113495bSYour Name 	 * Legacy targets did not provide this. Newer targets provide this.
4401*5113495bSYour Name 	 *
4402*5113495bSYour Name 	 * 1. The MLME config holds the intersection of fw cap and user config
4403*5113495bSYour Name 	 * 2. This may result in two enable commands sent for legacy, but
4404*5113495bSYour Name 	 *    that's fine, since the firmware returns harmlessly for the
4405*5113495bSYour Name 	 *    second command.
4406*5113495bSYour Name 	 * 3. The new two parameters in the enable command are ignored
4407*5113495bSYour Name 	 *    by legacy targets, and honored by new targets.
4408*5113495bSYour Name 	 */
4409*5113495bSYour Name 
4410*5113495bSYour Name 	/* If requestor configured, send requestor bcast/ucast config */
4411*5113495bSYour Name 	if (is_requestor_en) {
4412*5113495bSYour Name 		twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR;
4413*5113495bSYour Name 		twt_en_dis.ext_conf_present = true;
4414*5113495bSYour Name 		if (twt_bcast_requestor)
4415*5113495bSYour Name 			twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST;
4416*5113495bSYour Name 		else
4417*5113495bSYour Name 			twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL;
4418*5113495bSYour Name 
4419*5113495bSYour Name 		ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, true);
4420*5113495bSYour Name 		qdf_event_reset(&hdd_ctx->twt_enable_comp_evt);
4421*5113495bSYour Name 
4422*5113495bSYour Name 		wma_send_twt_enable_cmd(pdev_id, &twt_en_dis);
4423*5113495bSYour Name 		status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt,
4424*5113495bSYour Name 					       TWT_ENABLE_COMPLETE_TIMEOUT);
4425*5113495bSYour Name 
4426*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4427*5113495bSYour Name 			hdd_warn("TWT Requestor Enable timedout");
4428*5113495bSYour Name 			ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, false);
4429*5113495bSYour Name 		}
4430*5113495bSYour Name 	}
4431*5113495bSYour Name 
4432*5113495bSYour Name 	return status;
4433*5113495bSYour Name }
4434*5113495bSYour Name 
hdd_send_twt_responder_enable_cmd(struct hdd_context * hdd_ctx)4435*5113495bSYour Name QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx)
4436*5113495bSYour Name {
4437*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
4438*5113495bSYour Name 	struct twt_enable_disable_conf twt_en_dis = {0};
4439*5113495bSYour Name 	bool is_responder_en, twt_bcast_responder = false;
4440*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4441*5113495bSYour Name 
4442*5113495bSYour Name 	ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &is_responder_en);
4443*5113495bSYour Name 	ucfg_mlme_get_twt_bcast_responder(hdd_ctx->psoc, &twt_bcast_responder);
4444*5113495bSYour Name 	twt_en_dis.bcast_en = twt_bcast_responder;
4445*5113495bSYour Name 
4446*5113495bSYour Name 	hdd_debug("TWT responder mlme cfg:res:%d, bcast:%d, pdev:%d",
4447*5113495bSYour Name 		  is_responder_en, twt_en_dis.bcast_en, pdev_id);
4448*5113495bSYour Name 
4449*5113495bSYour Name 	/* The below code takes care of the following :
4450*5113495bSYour Name 	 * If user wants to separately enable responder roles, and also the
4451*5113495bSYour Name 	 * broadcast TWT capabilities separately for each role. This is done
4452*5113495bSYour Name 	 * by reusing the INI configuration to indicate the user preference
4453*5113495bSYour Name 	 * and sending the command accordingly.
4454*5113495bSYour Name 	 * Legacy targets did not provide this. Newer targets provide this.
4455*5113495bSYour Name 	 *
4456*5113495bSYour Name 	 * 1. The MLME config holds the intersection of fw cap and user config
4457*5113495bSYour Name 	 * 2. This may result in two enable commands sent for legacy, but
4458*5113495bSYour Name 	 *    that's fine, since the firmware returns harmlessly for the
4459*5113495bSYour Name 	 *    second command.
4460*5113495bSYour Name 	 * 3. The new two parameters in the enable command are ignored
4461*5113495bSYour Name 	 *    by legacy targets, and honored by new targets.
4462*5113495bSYour Name 	 */
4463*5113495bSYour Name 
4464*5113495bSYour Name 	/* If responder configured, send responder bcast/ucast config */
4465*5113495bSYour Name 	if (is_responder_en) {
4466*5113495bSYour Name 		twt_en_dis.role = WMI_TWT_ROLE_RESPONDER;
4467*5113495bSYour Name 		twt_en_dis.ext_conf_present = true;
4468*5113495bSYour Name 		if (twt_bcast_responder)
4469*5113495bSYour Name 			twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST;
4470*5113495bSYour Name 		else
4471*5113495bSYour Name 			twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL;
4472*5113495bSYour Name 
4473*5113495bSYour Name 		ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, true);
4474*5113495bSYour Name 		qdf_event_reset(&hdd_ctx->twt_enable_comp_evt);
4475*5113495bSYour Name 		wma_send_twt_enable_cmd(pdev_id, &twt_en_dis);
4476*5113495bSYour Name 		status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt,
4477*5113495bSYour Name 					       TWT_ENABLE_COMPLETE_TIMEOUT);
4478*5113495bSYour Name 
4479*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4480*5113495bSYour Name 			hdd_warn("TWT Responder Enable timedout");
4481*5113495bSYour Name 			ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, false);
4482*5113495bSYour Name 		}
4483*5113495bSYour Name 	}
4484*5113495bSYour Name 
4485*5113495bSYour Name 	return status;
4486*5113495bSYour Name }
4487*5113495bSYour Name 
hdd_send_twt_requestor_disable_cmd(struct hdd_context * hdd_ctx,uint32_t reason)4488*5113495bSYour Name QDF_STATUS hdd_send_twt_requestor_disable_cmd(struct hdd_context *hdd_ctx,
4489*5113495bSYour Name 					      uint32_t reason)
4490*5113495bSYour Name {
4491*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
4492*5113495bSYour Name 	struct twt_enable_disable_conf twt_en_dis = {0};
4493*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4494*5113495bSYour Name 
4495*5113495bSYour Name 	hdd_debug("TWT requestor disable cmd: pdev:%d", pdev_id);
4496*5113495bSYour Name 
4497*5113495bSYour Name 	/* Set MLME TWT flag */
4498*5113495bSYour Name 	ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, false);
4499*5113495bSYour Name 
4500*5113495bSYour Name        /* One disable should be fine, with extended configuration
4501*5113495bSYour Name 	* set to false, and extended arguments will be ignored by target
4502*5113495bSYour Name 	*/
4503*5113495bSYour Name 	twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR;
4504*5113495bSYour Name 	hdd_ctx->twt_state = TWT_DISABLE_REQUESTED;
4505*5113495bSYour Name 	twt_en_dis.ext_conf_present = true;
4506*5113495bSYour Name 	qdf_event_reset(&hdd_ctx->twt_disable_comp_evt);
4507*5113495bSYour Name 
4508*5113495bSYour Name 	wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
4509*5113495bSYour Name 
4510*5113495bSYour Name 	status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt,
4511*5113495bSYour Name 				       TWT_DISABLE_COMPLETE_TIMEOUT);
4512*5113495bSYour Name 
4513*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status))
4514*5113495bSYour Name 		goto timeout;
4515*5113495bSYour Name 
4516*5113495bSYour Name 	return status;
4517*5113495bSYour Name 
4518*5113495bSYour Name timeout:
4519*5113495bSYour Name 	hdd_warn("TWT Requestor disable timedout");
4520*5113495bSYour Name 	return status;
4521*5113495bSYour Name }
4522*5113495bSYour Name 
hdd_send_twt_responder_disable_cmd(struct hdd_context * hdd_ctx,uint32_t reason)4523*5113495bSYour Name QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx,
4524*5113495bSYour Name 					      uint32_t reason)
4525*5113495bSYour Name {
4526*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
4527*5113495bSYour Name 	struct twt_enable_disable_conf twt_en_dis = {0};
4528*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
4529*5113495bSYour Name 
4530*5113495bSYour Name 	hdd_debug("TWT responder disable cmd: pdev:%d", pdev_id);
4531*5113495bSYour Name 
4532*5113495bSYour Name 	/* Set MLME TWT flag */
4533*5113495bSYour Name 	ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, false);
4534*5113495bSYour Name 
4535*5113495bSYour Name        /* One disable should be fine, with extended configuration
4536*5113495bSYour Name 	* set to false, and extended arguments will be ignored by target
4537*5113495bSYour Name 	*/
4538*5113495bSYour Name 	twt_en_dis.role = WMI_TWT_ROLE_RESPONDER;
4539*5113495bSYour Name 	hdd_ctx->twt_state = TWT_DISABLE_REQUESTED;
4540*5113495bSYour Name 	twt_en_dis.ext_conf_present = true;
4541*5113495bSYour Name 	qdf_event_reset(&hdd_ctx->twt_disable_comp_evt);
4542*5113495bSYour Name 	wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
4543*5113495bSYour Name 
4544*5113495bSYour Name 	status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt,
4545*5113495bSYour Name 				       TWT_DISABLE_COMPLETE_TIMEOUT);
4546*5113495bSYour Name 
4547*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status))
4548*5113495bSYour Name 		goto timeout;
4549*5113495bSYour Name 
4550*5113495bSYour Name 	return status;
4551*5113495bSYour Name 
4552*5113495bSYour Name timeout:
4553*5113495bSYour Name 	hdd_warn("TWT Responder disable timedout");
4554*5113495bSYour Name 	return status;
4555*5113495bSYour Name }
4556*5113495bSYour Name 
4557*5113495bSYour Name /**
4558*5113495bSYour Name  * hdd_twt_enable_comp_cb() - TWT enable complete event callback
4559*5113495bSYour Name  * @hdd_handle: Pointer to opaque HDD handle
4560*5113495bSYour Name  * @params: Pointer to TWT enable completion parameters
4561*5113495bSYour Name  *
4562*5113495bSYour Name  * Return: None
4563*5113495bSYour Name  */
4564*5113495bSYour Name static void
hdd_twt_enable_comp_cb(hdd_handle_t hdd_handle,struct wmi_twt_enable_complete_event_param * params)4565*5113495bSYour Name hdd_twt_enable_comp_cb(hdd_handle_t hdd_handle,
4566*5113495bSYour Name 		       struct wmi_twt_enable_complete_event_param *params)
4567*5113495bSYour Name {
4568*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
4569*5113495bSYour Name 	enum twt_status prev_state;
4570*5113495bSYour Name 	QDF_STATUS status;
4571*5113495bSYour Name 
4572*5113495bSYour Name 	prev_state = hdd_ctx->twt_state;
4573*5113495bSYour Name 	if (params->status == WMI_HOST_ENABLE_TWT_STATUS_OK ||
4574*5113495bSYour Name 	    params->status == WMI_HOST_ENABLE_TWT_STATUS_ALREADY_ENABLED) {
4575*5113495bSYour Name 		switch (prev_state) {
4576*5113495bSYour Name 		case TWT_FW_TRIGGER_ENABLE_REQUESTED:
4577*5113495bSYour Name 			hdd_ctx->twt_state = TWT_FW_TRIGGER_ENABLED;
4578*5113495bSYour Name 			break;
4579*5113495bSYour Name 		case TWT_HOST_TRIGGER_ENABLE_REQUESTED:
4580*5113495bSYour Name 			hdd_ctx->twt_state = TWT_HOST_TRIGGER_ENABLED;
4581*5113495bSYour Name 			break;
4582*5113495bSYour Name 		default:
4583*5113495bSYour Name 			break;
4584*5113495bSYour Name 		}
4585*5113495bSYour Name 	}
4586*5113495bSYour Name 
4587*5113495bSYour Name 	if (params->status == WMI_HOST_ENABLE_TWT_INVALID_PARAM ||
4588*5113495bSYour Name 	    params->status == WMI_HOST_ENABLE_TWT_STATUS_UNKNOWN_ERROR)
4589*5113495bSYour Name 		hdd_ctx->twt_state = TWT_INIT;
4590*5113495bSYour Name 
4591*5113495bSYour Name 	hdd_debug("TWT: pdev ID:%d, status:%d State transitioned from %d to %d",
4592*5113495bSYour Name 		  params->pdev_id, params->status,
4593*5113495bSYour Name 		  prev_state, hdd_ctx->twt_state);
4594*5113495bSYour Name 
4595*5113495bSYour Name 	status = qdf_event_set(&hdd_ctx->twt_enable_comp_evt);
4596*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
4597*5113495bSYour Name 		hdd_err("Failed to set twt_enable_comp_evt");
4598*5113495bSYour Name }
4599*5113495bSYour Name 
4600*5113495bSYour Name /**
4601*5113495bSYour Name  * hdd_twt_disable_comp_cb() - TWT disable complete event callback
4602*5113495bSYour Name  * @hdd_handle: opaque handle for the global HDD Context
4603*5113495bSYour Name  *
4604*5113495bSYour Name  * Return: None
4605*5113495bSYour Name  */
4606*5113495bSYour Name static void
hdd_twt_disable_comp_cb(hdd_handle_t hdd_handle)4607*5113495bSYour Name hdd_twt_disable_comp_cb(hdd_handle_t hdd_handle)
4608*5113495bSYour Name {
4609*5113495bSYour Name 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
4610*5113495bSYour Name 	enum twt_status prev_state;
4611*5113495bSYour Name 	QDF_STATUS status;
4612*5113495bSYour Name 
4613*5113495bSYour Name 	prev_state = hdd_ctx->twt_state;
4614*5113495bSYour Name 	/* Do not change the state for role specific disables */
4615*5113495bSYour Name 	if (hdd_ctx->twt_state == TWT_DISABLE_REQUESTED)
4616*5113495bSYour Name 		hdd_ctx->twt_state = TWT_DISABLED;
4617*5113495bSYour Name 
4618*5113495bSYour Name 	hdd_debug("TWT: State transitioned from %d to %d",
4619*5113495bSYour Name 		  prev_state, hdd_ctx->twt_state);
4620*5113495bSYour Name 
4621*5113495bSYour Name 	status = qdf_event_set(&hdd_ctx->twt_disable_comp_evt);
4622*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status))
4623*5113495bSYour Name 		hdd_err("Failed to set twt_disable_comp_evt");
4624*5113495bSYour Name }
4625*5113495bSYour Name 
hdd_send_twt_role_disable_cmd(struct hdd_context * hdd_ctx,enum twt_role role)4626*5113495bSYour Name void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx,
4627*5113495bSYour Name 				   enum twt_role role)
4628*5113495bSYour Name {
4629*5113495bSYour Name 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
4630*5113495bSYour Name 	struct twt_enable_disable_conf twt_en_dis = {0};
4631*5113495bSYour Name 	QDF_STATUS status;
4632*5113495bSYour Name 
4633*5113495bSYour Name 	hdd_debug("TWT disable cmd :pdev:%d : %d", pdev_id, role);
4634*5113495bSYour Name 
4635*5113495bSYour Name 	if ((role == TWT_REQUESTOR) || (role == TWT_REQUESTOR_INDV)) {
4636*5113495bSYour Name 		twt_en_dis.ext_conf_present = true;
4637*5113495bSYour Name 		twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR;
4638*5113495bSYour Name 		twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL;
4639*5113495bSYour Name 		wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
4640*5113495bSYour Name 	}
4641*5113495bSYour Name 
4642*5113495bSYour Name 	if (role == TWT_REQUESTOR_BCAST) {
4643*5113495bSYour Name 		twt_en_dis.ext_conf_present = true;
4644*5113495bSYour Name 		twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR;
4645*5113495bSYour Name 		twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST;
4646*5113495bSYour Name 		wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
4647*5113495bSYour Name 	}
4648*5113495bSYour Name 
4649*5113495bSYour Name 	if ((role == TWT_RESPONDER) || (role == TWT_RESPONDER_INDV)) {
4650*5113495bSYour Name 		twt_en_dis.ext_conf_present = true;
4651*5113495bSYour Name 		twt_en_dis.role = WMI_TWT_ROLE_RESPONDER;
4652*5113495bSYour Name 		twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL;
4653*5113495bSYour Name 		wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
4654*5113495bSYour Name 	}
4655*5113495bSYour Name 
4656*5113495bSYour Name 	if (role == TWT_RESPONDER_BCAST) {
4657*5113495bSYour Name 		twt_en_dis.ext_conf_present = true;
4658*5113495bSYour Name 		twt_en_dis.role = WMI_TWT_ROLE_RESPONDER;
4659*5113495bSYour Name 		twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST;
4660*5113495bSYour Name 		wma_send_twt_disable_cmd(pdev_id, &twt_en_dis);
4661*5113495bSYour Name 	}
4662*5113495bSYour Name 
4663*5113495bSYour Name 	status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt,
4664*5113495bSYour Name 				       TWT_DISABLE_COMPLETE_TIMEOUT);
4665*5113495bSYour Name 
4666*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status)) {
4667*5113495bSYour Name 		hdd_warn("TWT request disable timedout");
4668*5113495bSYour Name 		return;
4669*5113495bSYour Name 	}
4670*5113495bSYour Name }
4671*5113495bSYour Name 
hdd_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev * pdev,void * object,void * arg)4672*5113495bSYour Name void hdd_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev,
4673*5113495bSYour Name 				       void *object, void *arg)
4674*5113495bSYour Name {
4675*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
4676*5113495bSYour Name 	struct twt_conc_arg *twt_arg = arg;
4677*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
4678*5113495bSYour Name 
4679*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
4680*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
4681*5113495bSYour Name 		hdd_debug("Concurrency exist on SAP vdev");
4682*5113495bSYour Name 		status = hdd_send_twt_responder_disable_cmd(twt_arg->hdd_ctx,
4683*5113495bSYour Name 							    0);
4684*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4685*5113495bSYour Name 			hdd_err("TWT responder disable cmd to firmware failed");
4686*5113495bSYour Name 			return;
4687*5113495bSYour Name 		}
4688*5113495bSYour Name 		sme_twt_update_beacon_template(twt_arg->hdd_ctx->mac_handle);
4689*5113495bSYour Name 	}
4690*5113495bSYour Name 
4691*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
4692*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
4693*5113495bSYour Name 		hdd_debug("Concurrency exist on STA vdev");
4694*5113495bSYour Name 		status = hdd_send_twt_requestor_disable_cmd(twt_arg->hdd_ctx,
4695*5113495bSYour Name 							    0);
4696*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4697*5113495bSYour Name 			hdd_err("TWT requestor disable cmd to firmware failed");
4698*5113495bSYour Name 			return;
4699*5113495bSYour Name 		}
4700*5113495bSYour Name 	}
4701*5113495bSYour Name }
4702*5113495bSYour Name 
hdd_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev * pdev,void * object,void * arg)4703*5113495bSYour Name void hdd_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev,
4704*5113495bSYour Name 				       void *object, void *arg)
4705*5113495bSYour Name {
4706*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
4707*5113495bSYour Name 	struct twt_conc_arg *twt_arg = arg;
4708*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
4709*5113495bSYour Name 
4710*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
4711*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
4712*5113495bSYour Name 		hdd_debug("Concurrency exist on SAP vdev");
4713*5113495bSYour Name 		status = hdd_send_twt_responder_disable_cmd(twt_arg->hdd_ctx,
4714*5113495bSYour Name 							    0);
4715*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4716*5113495bSYour Name 			hdd_err("TWT responder disable cmd to firmware failed");
4717*5113495bSYour Name 			return;
4718*5113495bSYour Name 		}
4719*5113495bSYour Name 		sme_twt_update_beacon_template(twt_arg->hdd_ctx->mac_handle);
4720*5113495bSYour Name 	}
4721*5113495bSYour Name 
4722*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
4723*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
4724*5113495bSYour Name 		hdd_debug("Concurrency exist on STA vdev");
4725*5113495bSYour Name 		status = hdd_send_twt_requestor_disable_cmd(twt_arg->hdd_ctx,
4726*5113495bSYour Name 							    0);
4727*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4728*5113495bSYour Name 			hdd_err("TWT requestor disable cmd to firmware failed");
4729*5113495bSYour Name 			return;
4730*5113495bSYour Name 		}
4731*5113495bSYour Name 	}
4732*5113495bSYour Name }
4733*5113495bSYour Name 
hdd_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev * pdev,void * object,void * arg)4734*5113495bSYour Name void hdd_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev,
4735*5113495bSYour Name 				       void *object, void *arg)
4736*5113495bSYour Name {
4737*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
4738*5113495bSYour Name 	struct twt_conc_arg *twt_arg = arg;
4739*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
4740*5113495bSYour Name 
4741*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
4742*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
4743*5113495bSYour Name 		hdd_debug("SAP vdev exist");
4744*5113495bSYour Name 		status = hdd_send_twt_responder_enable_cmd(twt_arg->hdd_ctx);
4745*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4746*5113495bSYour Name 			hdd_err("TWT responder enable cmd to firmware failed");
4747*5113495bSYour Name 			return;
4748*5113495bSYour Name 		}
4749*5113495bSYour Name 		sme_twt_update_beacon_template(twt_arg->hdd_ctx->mac_handle);
4750*5113495bSYour Name 	}
4751*5113495bSYour Name 
4752*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
4753*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
4754*5113495bSYour Name 		hdd_debug("STA vdev exist");
4755*5113495bSYour Name 		status = hdd_send_twt_requestor_enable_cmd(twt_arg->hdd_ctx);
4756*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
4757*5113495bSYour Name 			hdd_err("TWT requestor enable cmd to firmware failed");
4758*5113495bSYour Name 			return;
4759*5113495bSYour Name 		}
4760*5113495bSYour Name 	}
4761*5113495bSYour Name }
4762*5113495bSYour Name 
__hdd_twt_update_work_handler(struct hdd_context * hdd_ctx)4763*5113495bSYour Name void __hdd_twt_update_work_handler(struct hdd_context *hdd_ctx)
4764*5113495bSYour Name {
4765*5113495bSYour Name 	struct twt_conc_arg twt_arg;
4766*5113495bSYour Name 	uint32_t num_connections = 0, sap_count = 0, sta_count = 0;
4767*5113495bSYour Name 	int ret;
4768*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
4769*5113495bSYour Name 
4770*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
4771*5113495bSYour Name 	if (ret) {
4772*5113495bSYour Name 		hdd_err("Invalid HDD context");
4773*5113495bSYour Name 		return;
4774*5113495bSYour Name 	}
4775*5113495bSYour Name 	num_connections = policy_mgr_get_connection_count(hdd_ctx->psoc);
4776*5113495bSYour Name 	sta_count = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc,
4777*5113495bSYour Name 							      PM_STA_MODE,
4778*5113495bSYour Name 							      NULL);
4779*5113495bSYour Name 	sap_count = policy_mgr_get_sap_mode_count(hdd_ctx->psoc, NULL);
4780*5113495bSYour Name 	twt_arg.hdd_ctx = hdd_ctx;
4781*5113495bSYour Name 
4782*5113495bSYour Name 	hdd_debug("Total connection %d, sta_count %d, sap_count %d",
4783*5113495bSYour Name 		  num_connections, sta_count, sap_count);
4784*5113495bSYour Name 	switch (num_connections) {
4785*5113495bSYour Name 	case 0:
4786*5113495bSYour Name 		break;
4787*5113495bSYour Name 	case 1:
4788*5113495bSYour Name 		if (sta_count == 1) {
4789*5113495bSYour Name 			hdd_send_twt_requestor_enable_cmd(hdd_ctx);
4790*5113495bSYour Name 		} else if (sap_count == 1) {
4791*5113495bSYour Name 			hdd_send_twt_responder_enable_cmd(hdd_ctx);
4792*5113495bSYour Name 			sme_twt_update_beacon_template(hdd_ctx->mac_handle);
4793*5113495bSYour Name 		}
4794*5113495bSYour Name 		break;
4795*5113495bSYour Name 	case 2:
4796*5113495bSYour Name 		if (policy_mgr_current_concurrency_is_scc(hdd_ctx->psoc)) {
4797*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
4798*5113495bSYour Name 					hdd_ctx->pdev,
4799*5113495bSYour Name 					WLAN_VDEV_OP,
4800*5113495bSYour Name 					hdd_twt_concurrency_update_on_scc,
4801*5113495bSYour Name 					&twt_arg, 0,
4802*5113495bSYour Name 					WLAN_HDD_ID_OBJ_MGR);
4803*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
4804*5113495bSYour Name 				hdd_err("2port concurrency,SAP/STA not in SCC");
4805*5113495bSYour Name 				return;
4806*5113495bSYour Name 			}
4807*5113495bSYour Name 		} else if (policy_mgr_current_concurrency_is_mcc(
4808*5113495bSYour Name 							hdd_ctx->psoc)) {
4809*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
4810*5113495bSYour Name 					hdd_ctx->pdev,
4811*5113495bSYour Name 					WLAN_VDEV_OP,
4812*5113495bSYour Name 					hdd_twt_concurrency_update_on_mcc,
4813*5113495bSYour Name 					&twt_arg, 0,
4814*5113495bSYour Name 					WLAN_HDD_ID_OBJ_MGR);
4815*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
4816*5113495bSYour Name 				hdd_err("2port concurrency,SAP/STA not in MCC");
4817*5113495bSYour Name 				return;
4818*5113495bSYour Name 			}
4819*5113495bSYour Name 		} else if (policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc)) {
4820*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
4821*5113495bSYour Name 					hdd_ctx->pdev,
4822*5113495bSYour Name 					WLAN_VDEV_OP,
4823*5113495bSYour Name 					hdd_twt_concurrency_update_on_dbs,
4824*5113495bSYour Name 					&twt_arg, 0,
4825*5113495bSYour Name 					WLAN_HDD_ID_OBJ_MGR);
4826*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
4827*5113495bSYour Name 				hdd_err("2port concurrency,SAP/STA not in DBS");
4828*5113495bSYour Name 				return;
4829*5113495bSYour Name 			}
4830*5113495bSYour Name 		}
4831*5113495bSYour Name 		break;
4832*5113495bSYour Name 	case 3:
4833*5113495bSYour Name 		if (policy_mgr_current_concurrency_is_scc(hdd_ctx->psoc)) {
4834*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
4835*5113495bSYour Name 					hdd_ctx->pdev,
4836*5113495bSYour Name 					WLAN_VDEV_OP,
4837*5113495bSYour Name 					hdd_twt_concurrency_update_on_scc,
4838*5113495bSYour Name 					&twt_arg, 0,
4839*5113495bSYour Name 					WLAN_HDD_ID_OBJ_MGR);
4840*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
4841*5113495bSYour Name 				hdd_err("3port concurrency,SAP/STA not in SCC");
4842*5113495bSYour Name 				return;
4843*5113495bSYour Name 			}
4844*5113495bSYour Name 		}
4845*5113495bSYour Name 		if (policy_mgr_current_concurrency_is_mcc(hdd_ctx->psoc)) {
4846*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
4847*5113495bSYour Name 					hdd_ctx->pdev,
4848*5113495bSYour Name 					WLAN_VDEV_OP,
4849*5113495bSYour Name 					hdd_twt_concurrency_update_on_mcc,
4850*5113495bSYour Name 					&twt_arg, 0,
4851*5113495bSYour Name 					WLAN_HDD_ID_OBJ_MGR);
4852*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
4853*5113495bSYour Name 				hdd_err("3port concurrency,SAP/STA not in MCC");
4854*5113495bSYour Name 				return;
4855*5113495bSYour Name 			}
4856*5113495bSYour Name 		}
4857*5113495bSYour Name 		break;
4858*5113495bSYour Name 	default:
4859*5113495bSYour Name 		hdd_debug("Unexpected number of connection");
4860*5113495bSYour Name 		break;
4861*5113495bSYour Name 	}
4862*5113495bSYour Name }
4863*5113495bSYour Name 
hdd_twt_update_work_handler(void * data)4864*5113495bSYour Name void hdd_twt_update_work_handler(void *data)
4865*5113495bSYour Name {
4866*5113495bSYour Name 	struct hdd_context *hdd_ctx = (struct hdd_context *)data;
4867*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
4868*5113495bSYour Name 	int ret;
4869*5113495bSYour Name 
4870*5113495bSYour Name 	ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync);
4871*5113495bSYour Name 
4872*5113495bSYour Name 	if (ret == -EAGAIN) {
4873*5113495bSYour Name 		qdf_sleep(TWT_WORK_RESCHED_WAIT_TIME);
4874*5113495bSYour Name 		hdd_debug("rescheduling TWT work");
4875*5113495bSYour Name 		wlan_twt_concurrency_update(hdd_ctx);
4876*5113495bSYour Name 		return;
4877*5113495bSYour Name 	} else if (ret) {
4878*5113495bSYour Name 		hdd_err("can not handle TWT update %d", ret);
4879*5113495bSYour Name 		return;
4880*5113495bSYour Name 	}
4881*5113495bSYour Name 
4882*5113495bSYour Name 	__hdd_twt_update_work_handler(hdd_ctx);
4883*5113495bSYour Name 
4884*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
4885*5113495bSYour Name }
4886*5113495bSYour Name 
wlan_twt_concurrency_update(struct hdd_context * hdd_ctx)4887*5113495bSYour Name void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx)
4888*5113495bSYour Name {
4889*5113495bSYour Name 	qdf_sched_work(0, &hdd_ctx->twt_en_dis_work);
4890*5113495bSYour Name }
4891*5113495bSYour Name 
hdd_twt_del_dialog_in_ps_disable(struct hdd_context * hdd_ctx,struct qdf_mac_addr * mac_addr,uint8_t vdev_id)4892*5113495bSYour Name void hdd_twt_del_dialog_in_ps_disable(struct hdd_context *hdd_ctx,
4893*5113495bSYour Name 				      struct qdf_mac_addr *mac_addr,
4894*5113495bSYour Name 				      uint8_t vdev_id)
4895*5113495bSYour Name {
4896*5113495bSYour Name 	struct wmi_twt_del_dialog_param params = {0};
4897*5113495bSYour Name 	int ret;
4898*5113495bSYour Name 
4899*5113495bSYour Name 	params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
4900*5113495bSYour Name 	params.vdev_id = vdev_id;
4901*5113495bSYour Name 	qdf_mem_copy(params.peer_macaddr, mac_addr->bytes, QDF_MAC_ADDR_SIZE);
4902*5113495bSYour Name 
4903*5113495bSYour Name 	if (ucfg_mlme_is_twt_setup_done(hdd_ctx->psoc, mac_addr,
4904*5113495bSYour Name 					params.dialog_id)) {
4905*5113495bSYour Name 		hdd_debug("vdev%d: Terminate existing TWT session %d due to ps disable",
4906*5113495bSYour Name 			  params.vdev_id, params.dialog_id);
4907*5113495bSYour Name 		ret = hdd_send_twt_del_dialog_cmd(hdd_ctx, &params);
4908*5113495bSYour Name 		if (ret)
4909*5113495bSYour Name 			hdd_debug("TWT teardown is failed on vdev: %d", vdev_id);
4910*5113495bSYour Name 	}
4911*5113495bSYour Name }
4912*5113495bSYour Name 
wlan_hdd_twt_init(struct hdd_context * hdd_ctx)4913*5113495bSYour Name void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
4914*5113495bSYour Name {
4915*5113495bSYour Name 	QDF_STATUS status;
4916*5113495bSYour Name 	struct twt_callbacks twt_cb;
4917*5113495bSYour Name 
4918*5113495bSYour Name 	hdd_ctx->twt_state = TWT_INIT;
4919*5113495bSYour Name 
4920*5113495bSYour Name 	sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
4921*5113495bSYour Name 	twt_cb.twt_enable_cb = hdd_twt_enable_comp_cb;
4922*5113495bSYour Name 	twt_cb.twt_disable_cb = hdd_twt_disable_comp_cb;
4923*5113495bSYour Name 	twt_cb.twt_add_dialog_cb = hdd_twt_add_dialog_comp_cb;
4924*5113495bSYour Name 	twt_cb.twt_del_dialog_cb = hdd_twt_del_dialog_comp_cb;
4925*5113495bSYour Name 	twt_cb.twt_pause_dialog_cb = hdd_twt_pause_dialog_comp_cb;
4926*5113495bSYour Name 	twt_cb.twt_resume_dialog_cb = hdd_twt_resume_dialog_comp_cb;
4927*5113495bSYour Name 	twt_cb.twt_notify_cb = hdd_twt_notify_cb;
4928*5113495bSYour Name 	twt_cb.twt_nudge_dialog_cb = hdd_twt_nudge_dialog_comp_cb;
4929*5113495bSYour Name 	twt_cb.twt_ack_comp_cb = hdd_twt_ack_comp_cb;
4930*5113495bSYour Name 
4931*5113495bSYour Name 	status = sme_register_twt_callbacks(hdd_ctx->mac_handle, &twt_cb);
4932*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
4933*5113495bSYour Name 		hdd_err("Register twt enable complete failed");
4934*5113495bSYour Name 		return;
4935*5113495bSYour Name 	}
4936*5113495bSYour Name 
4937*5113495bSYour Name 	status = qdf_event_create(&hdd_ctx->twt_enable_comp_evt);
4938*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
4939*5113495bSYour Name 		sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
4940*5113495bSYour Name 		hdd_err("twt_enable_comp_evt init failed");
4941*5113495bSYour Name 		return;
4942*5113495bSYour Name 	}
4943*5113495bSYour Name 
4944*5113495bSYour Name 	status = qdf_event_create(&hdd_ctx->twt_disable_comp_evt);
4945*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
4946*5113495bSYour Name 		sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
4947*5113495bSYour Name 		hdd_err("twt_disable_comp_evt init failed");
4948*5113495bSYour Name 		return;
4949*5113495bSYour Name 	}
4950*5113495bSYour Name 
4951*5113495bSYour Name 	hdd_send_twt_requestor_enable_cmd(hdd_ctx);
4952*5113495bSYour Name 	qdf_create_work(0, &hdd_ctx->twt_en_dis_work,
4953*5113495bSYour Name 			hdd_twt_update_work_handler, hdd_ctx);
4954*5113495bSYour Name }
4955*5113495bSYour Name 
wlan_hdd_twt_deinit(struct hdd_context * hdd_ctx)4956*5113495bSYour Name void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)
4957*5113495bSYour Name {
4958*5113495bSYour Name 	QDF_STATUS status;
4959*5113495bSYour Name 
4960*5113495bSYour Name 	qdf_flush_work(&hdd_ctx->twt_en_dis_work);
4961*5113495bSYour Name 	qdf_destroy_work(NULL, &hdd_ctx->twt_en_dis_work);
4962*5113495bSYour Name 
4963*5113495bSYour Name 	status = qdf_event_destroy(&hdd_ctx->twt_disable_comp_evt);
4964*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
4965*5113495bSYour Name 		hdd_err("Failed to destroy twt_disable_comp_evt");
4966*5113495bSYour Name 
4967*5113495bSYour Name 	status = qdf_event_destroy(&hdd_ctx->twt_enable_comp_evt);
4968*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
4969*5113495bSYour Name 		hdd_err("Failed to destroy twt_enable_comp_evt");
4970*5113495bSYour Name 
4971*5113495bSYour Name 	status = sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
4972*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
4973*5113495bSYour Name 		hdd_err("De-register of twt disable cb failed: %d", status);
4974*5113495bSYour Name 
4975*5113495bSYour Name 	hdd_ctx->twt_state = TWT_CLOSED;
4976*5113495bSYour Name }
4977*5113495bSYour Name 
hdd_get_twt_requestor(struct wlan_objmgr_psoc * psoc,bool * val)4978*5113495bSYour Name QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val)
4979*5113495bSYour Name {
4980*5113495bSYour Name 	return ucfg_mlme_get_twt_requestor(psoc, val);
4981*5113495bSYour Name }
4982*5113495bSYour Name 
hdd_get_twt_responder(struct wlan_objmgr_psoc * psoc,bool * val)4983*5113495bSYour Name QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val)
4984*5113495bSYour Name {
4985*5113495bSYour Name 	return ucfg_mlme_get_twt_responder(psoc, val);
4986*5113495bSYour Name }
4987*5113495bSYour Name 
4988*5113495bSYour Name #endif
4989*5113495bSYour Name 
4990*5113495bSYour Name /**
4991*5113495bSYour Name  * __wlan_hdd_cfg80211_wifi_twt_config() - Wifi TWT configuration
4992*5113495bSYour Name  * vendor command
4993*5113495bSYour Name  * @wiphy: wiphy device pointer
4994*5113495bSYour Name  * @wdev: wireless device pointer
4995*5113495bSYour Name  * @data: Vendor command data buffer
4996*5113495bSYour Name  * @data_len: Buffer length
4997*5113495bSYour Name  *
4998*5113495bSYour Name  * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX.
4999*5113495bSYour Name  *
5000*5113495bSYour Name  * Return: 0 for Success and negative value for failure
5001*5113495bSYour Name  */
5002*5113495bSYour Name static int
__wlan_hdd_cfg80211_wifi_twt_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5003*5113495bSYour Name __wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
5004*5113495bSYour Name 				    struct wireless_dev *wdev,
5005*5113495bSYour Name 				    const void *data, int data_len)
5006*5113495bSYour Name {
5007*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
5008*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
5009*5113495bSYour Name 	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
5010*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1];
5011*5113495bSYour Name 	int errno;
5012*5113495bSYour Name 
5013*5113495bSYour Name 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
5014*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
5015*5113495bSYour Name 		return -EPERM;
5016*5113495bSYour Name 	}
5017*5113495bSYour Name 
5018*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
5019*5113495bSYour Name 	if (errno)
5020*5113495bSYour Name 		return errno;
5021*5113495bSYour Name 
5022*5113495bSYour Name 	errno = hdd_validate_adapter(adapter);
5023*5113495bSYour Name 	if (errno)
5024*5113495bSYour Name 		return errno;
5025*5113495bSYour Name 
5026*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX,
5027*5113495bSYour Name 				    data,
5028*5113495bSYour Name 				    data_len,
5029*5113495bSYour Name 				    wlan_hdd_wifi_twt_config_policy)) {
5030*5113495bSYour Name 		hdd_err("invalid twt attr");
5031*5113495bSYour Name 		return -EINVAL;
5032*5113495bSYour Name 	}
5033*5113495bSYour Name 
5034*5113495bSYour Name 	errno = hdd_twt_configure(adapter, tb);
5035*5113495bSYour Name 
5036*5113495bSYour Name 	return errno;
5037*5113495bSYour Name }
5038*5113495bSYour Name 
wlan_hdd_cfg80211_wifi_twt_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)5039*5113495bSYour Name int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy,
5040*5113495bSYour Name 				      struct wireless_dev *wdev,
5041*5113495bSYour Name 				      const void *data,
5042*5113495bSYour Name 				      int data_len)
5043*5113495bSYour Name {
5044*5113495bSYour Name 	int errno;
5045*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
5046*5113495bSYour Name 
5047*5113495bSYour Name 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
5048*5113495bSYour Name 	if (errno)
5049*5113495bSYour Name 		return errno;
5050*5113495bSYour Name 
5051*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_wifi_twt_config(wiphy, wdev, data,
5052*5113495bSYour Name 						    data_len);
5053*5113495bSYour Name 
5054*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
5055*5113495bSYour Name 
5056*5113495bSYour Name 	return errno;
5057*5113495bSYour Name }
5058*5113495bSYour Name 
wlan_hdd_resume_pmo_twt(struct hdd_context * hdd_ctx)5059*5113495bSYour Name void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx)
5060*5113495bSYour Name {
5061*5113495bSYour Name 	wlan_twt_concurrency_update(hdd_ctx);
5062*5113495bSYour Name }
5063*5113495bSYour Name 
wlan_hdd_suspend_pmo_twt(struct hdd_context * hdd_ctx)5064*5113495bSYour Name void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx)
5065*5113495bSYour Name {
5066*5113495bSYour Name 	qdf_flush_work(&hdd_ctx->twt_en_dis_work);
5067*5113495bSYour Name }
5068*5113495bSYour Name 
wlan_hdd_is_twt_pmo_allowed(struct hdd_context * hdd_ctx)5069*5113495bSYour Name bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx)
5070*5113495bSYour Name {
5071*5113495bSYour Name 	bool twt_pmo_allowed = false;
5072*5113495bSYour Name 
5073*5113495bSYour Name 	twt_pmo_allowed = ucfg_twt_get_pmo_allowed(hdd_ctx->psoc);
5074*5113495bSYour Name 	hdd_debug("twt_disabled_allowed %d ", twt_pmo_allowed);
5075*5113495bSYour Name 
5076*5113495bSYour Name 	return twt_pmo_allowed;
5077*5113495bSYour Name }
5078*5113495bSYour Name 
5079