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