1 /*
2  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  *  DOC: osif_twt_ext_req.c
19  *  This file contains twt component's osif API implementation
20  */
21 #include <wlan_objmgr_vdev_obj.h>
22 #include <wlan_twt_ucfg_api.h>
23 #include <wlan_twt_ucfg_ext_api.h>
24 #include <wlan_twt_ucfg_ext_cfg.h>
25 #include <osif_twt_req.h>
26 #include <osif_twt_ext_req.h>
27 #include <wlan_policy_mgr_api.h>
28 #include <wlan_cm_api.h>
29 #include <wlan_cfg80211.h>
30 #include <wlan_cm_roam_api.h>
31 #include <osif_twt_internal.h>
32 #include <wlan_osif_request_manager.h>
33 #include <wlan_osif_priv.h>
34 #include "wlan_cp_stats_mc_ucfg_api.h"
35 #include "wlan_mlme_ucfg_api.h"
36 #include "wlan_cp_stats_ucfg_api.h"
37 #include "osif_vdev_sync.h"
38 
39 #define TWT_ACK_COMPLETE_TIMEOUT 1000
40 
41 #define TWT_FLOW_TYPE_ANNOUNCED 0
42 #define TWT_FLOW_TYPE_UNANNOUNCED 1
43 
44 #define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX       0xFFFF
45 #define TWT_SETUP_WAKE_DURATION_MAX             0xFFFF
46 #define TWT_SETUP_WAKE_INTVL_EXP_MAX            31
47 #define TWT_MAX_NEXT_TWT_SIZE                   3
48 #define TWT_DEL_DIALOG_REQ_MAX_RETRY            10
49 #define TWT_TEARDOWN_IN_PS_DISABLE_WAIT_TIME    500
50 
51 static const struct nla_policy
52 qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = {
53 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 },
54 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG },
55 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 },
56 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG },
57 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID] = {.type = NLA_U8 },
58 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 },
59 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG },
60 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 },
61 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 },
62 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 },
63 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 },
64 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 },
65 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 },
66 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 },
67 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA] = {.type = NLA_U32 },
68 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
69 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID] = {.type = NLA_U8 },
70 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION] = {
71 							.type = NLA_U8 },
72 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE] = {.type = NLA_U8 },
73 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF] = {.type = NLA_U64 },
74 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT] = {.type = NLA_U32 },
75 };
76 
77 static const struct nla_policy
78 qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1] = {
79 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID] = {.type = NLA_U8 },
80 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT] = {.type = NLA_U8 },
81 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE] = {.type = NLA_U32 },
82 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 },
83 };
84 
85 static const struct nla_policy
86 qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = {
87 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 },
88 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME] = {.type = NLA_U32 },
89 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE] = {.type = NLA_U32 },
90 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
91 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET] = {.type = NLA_S32},
92 };
93 
94 static const struct nla_policy
95 qca_wlan_vendor_twt_set_param_policy[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1] = {
96 	[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE] = {.type = NLA_U8 },
97 };
98 
99 static const struct nla_policy
100 qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1] = {
101 	[QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 },
102 };
103 
osif_is_twt_command_allowed(struct wlan_objmgr_vdev * vdev,uint8_t vdev_id,struct wlan_objmgr_psoc * psoc)104 static int osif_is_twt_command_allowed(struct wlan_objmgr_vdev *vdev,
105 				       uint8_t vdev_id,
106 				       struct wlan_objmgr_psoc *psoc)
107 {
108 	enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev);
109 
110 	if (mode != QDF_STA_MODE &&
111 	    mode != QDF_P2P_CLIENT_MODE)
112 		return -EOPNOTSUPP;
113 
114 	if (!wlan_cm_is_vdev_connected(vdev)) {
115 		osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode);
116 		return -EAGAIN;
117 	}
118 
119 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
120 		return -EBUSY;
121 
122 	if (wlan_get_vdev_status(vdev)) {
123 		osif_err_rl("Scan in progress");
124 		return -EBUSY;
125 	}
126 
127 	return 0;
128 }
129 
osif_twt_setup_conc_allowed(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)130 static bool osif_twt_setup_conc_allowed(struct wlan_objmgr_psoc *psoc,
131 					uint8_t vdev_id)
132 {
133 	return policy_mgr_current_concurrency_is_mcc(psoc) ||
134 	       policy_mgr_is_scc_with_this_vdev_id(psoc, vdev_id);
135 }
136 
137 /**
138  * osif_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd
139  * @req_type: twt setup request type
140  * @twt_cmd: pointer to store twt command
141  *
142  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
143  */
144 static QDF_STATUS
osif_twt_setup_req_type_to_cmd(u8 req_type,enum HOST_TWT_COMMAND * twt_cmd)145 osif_twt_setup_req_type_to_cmd(u8 req_type, enum HOST_TWT_COMMAND *twt_cmd)
146 {
147 	if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST) {
148 		*twt_cmd = HOST_TWT_COMMAND_REQUEST_TWT;
149 	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST) {
150 		*twt_cmd = HOST_TWT_COMMAND_SUGGEST_TWT;
151 	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND) {
152 		*twt_cmd = HOST_TWT_COMMAND_DEMAND_TWT;
153 	} else {
154 		osif_err_rl("Invalid TWT_SETUP_REQ_TYPE %d", req_type);
155 		return QDF_STATUS_E_INVAL;
156 	}
157 	return QDF_STATUS_SUCCESS;
158 }
159 
160 /**
161  * osif_twt_parse_add_dialog_attrs() - Get TWT add dialog parameter
162  * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
163  * @tb: nl attributes
164  * @params: wmi twt add dialog parameters
165  *
166  * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX
167  *
168  * Return: 0 or -EINVAL.
169  */
170 static int
osif_twt_parse_add_dialog_attrs(struct nlattr ** tb,struct twt_add_dialog_param * params)171 osif_twt_parse_add_dialog_attrs(struct nlattr **tb,
172 				struct twt_add_dialog_param *params)
173 {
174 	uint32_t wake_intvl_exp, result;
175 	int cmd_id;
176 	QDF_STATUS qdf_status;
177 
178 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
179 	if (tb[cmd_id]) {
180 		params->dialog_id = nla_get_u8(tb[cmd_id]);
181 		if (params->dialog_id > TWT_MAX_DIALOG_ID) {
182 			osif_err_rl("Flow id (%u) invalid", params->dialog_id);
183 			return -EINVAL;
184 		}
185 	} else {
186 		params->dialog_id = 0;
187 		osif_debug("TWT_SETUP_FLOW_ID not specified. set to zero");
188 	}
189 
190 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
191 	if (!tb[cmd_id]) {
192 		osif_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must");
193 		return -EINVAL;
194 	}
195 	wake_intvl_exp = nla_get_u8(tb[cmd_id]);
196 	if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) {
197 		osif_err_rl("Invalid wake_intvl_exp %u > %u",
198 			   wake_intvl_exp,
199 			   TWT_SETUP_WAKE_INTVL_EXP_MAX);
200 		return -EINVAL;
201 	}
202 
203 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
204 	params->flag_bcast = nla_get_flag(tb[cmd_id]);
205 
206 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
207 	if (tb[cmd_id]) {
208 		params->dialog_id = nla_get_u8(tb[cmd_id]);
209 		osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id);
210 	}
211 
212 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION;
213 	if (tb[cmd_id]) {
214 		params->b_twt_recommendation = nla_get_u8(tb[cmd_id]);
215 		osif_debug("TWT_SETUP_BCAST_RECOMM %d",
216 			  params->b_twt_recommendation);
217 	}
218 
219 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE;
220 	if (tb[cmd_id]) {
221 		params->b_twt_persistence = nla_get_u8(tb[cmd_id]);
222 		osif_debug("TWT_SETUP_BCAST_PERSIS %d",
223 			  params->b_twt_persistence);
224 	}
225 
226 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE;
227 	if (!tb[cmd_id]) {
228 		osif_err_rl("TWT_SETUP_REQ_TYPE is must");
229 		return -EINVAL;
230 	}
231 	qdf_status = osif_twt_setup_req_type_to_cmd(nla_get_u8(tb[cmd_id]),
232 						   &params->twt_cmd);
233 	if (QDF_IS_STATUS_ERROR(qdf_status))
234 		return qdf_status_to_os_return(qdf_status);
235 
236 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
237 	params->flag_trigger = nla_get_flag(tb[cmd_id]);
238 
239 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
240 	if (!tb[cmd_id]) {
241 		osif_err_rl("TWT_SETUP_FLOW_TYPE is must");
242 		return -EINVAL;
243 	}
244 	params->flag_flow_type = nla_get_u8(tb[cmd_id]);
245 	if (params->flag_flow_type != TWT_FLOW_TYPE_ANNOUNCED &&
246 	    params->flag_flow_type != TWT_FLOW_TYPE_UNANNOUNCED)
247 		return -EINVAL;
248 
249 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
250 	params->flag_protection = nla_get_flag(tb[cmd_id]);
251 
252 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
253 	if (tb[cmd_id])
254 		params->sp_offset_us = nla_get_u32(tb[cmd_id]);
255 
256 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
257 	if (!tb[cmd_id]) {
258 		osif_err_rl("TWT_SETUP_WAKE_DURATION is must");
259 		return -EINVAL;
260 	}
261 	params->wake_dura_us = TWT_WAKE_DURATION_MULTIPLICATION_FACTOR *
262 			       nla_get_u32(tb[cmd_id]);
263 	if (params->wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) {
264 		osif_err_rl("Invalid wake_dura_us %u",
265 			   params->wake_dura_us);
266 		return -EINVAL;
267 	}
268 
269 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION;
270 	if (tb[cmd_id])
271 		params->min_wake_dura_us = nla_get_u32(tb[cmd_id]);
272 
273 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION;
274 	if (tb[cmd_id])
275 		params->max_wake_dura_us = nla_get_u32(tb[cmd_id]);
276 
277 	if (params->min_wake_dura_us > params->max_wake_dura_us) {
278 		osif_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero",
279 			   params->min_wake_dura_us, params->max_wake_dura_us);
280 		params->min_wake_dura_us = 0;
281 		params->max_wake_dura_us = 0;
282 	}
283 
284 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
285 	if (!tb[cmd_id]) {
286 		osif_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
287 		return -EINVAL;
288 	}
289 	params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
290 
291 	/*
292 	 * If mantissa in microsecond is present then take precedence over
293 	 * mantissa in TU. And send mantissa in microsecond to firmware.
294 	 */
295 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
296 	if (tb[cmd_id])
297 		params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
298 
299 	if (params->wake_intvl_mantis >
300 	    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
301 		osif_err_rl("Invalid wake_intvl_mantis %u",
302 			   params->wake_intvl_mantis);
303 		return -EINVAL;
304 	}
305 
306 	if (wake_intvl_exp && params->wake_intvl_mantis) {
307 		result = 2 << (wake_intvl_exp - 1);
308 		if (result >
309 		    (UINT_MAX / params->wake_intvl_mantis)) {
310 			osif_err_rl("Invalid exp %d mantissa %d",
311 				   wake_intvl_exp,
312 				   params->wake_intvl_mantis);
313 			return -EINVAL;
314 		}
315 		params->wake_intvl_us =
316 			params->wake_intvl_mantis * result;
317 	} else {
318 		params->wake_intvl_us = params->wake_intvl_mantis;
319 	}
320 
321 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL;
322 	if (tb[cmd_id])
323 		params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]);
324 
325 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL;
326 	if (tb[cmd_id])
327 		params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]);
328 
329 	if (params->min_wake_intvl_us > params->max_wake_intvl_us) {
330 		osif_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero",
331 			   params->min_wake_intvl_us,
332 			   params->max_wake_intvl_us);
333 		params->min_wake_dura_us = 0;
334 		params->max_wake_dura_us = 0;
335 	}
336 
337 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
338 	if (tb[cmd_id])
339 		params->wake_time_tsf = nla_get_u64(tb[cmd_id]);
340 	else
341 		params->wake_time_tsf = 0;
342 
343 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT;
344 	if (tb[cmd_id])
345 		params->announce_timeout_us = nla_get_u32(tb[cmd_id]);
346 	else
347 		params->announce_timeout_us = 0;
348 
349 	osif_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d",
350 		  params->dialog_id, params->vdev_id, params->wake_intvl_us,
351 		  params->min_wake_intvl_us, params->max_wake_intvl_us,
352 		  params->wake_intvl_mantis);
353 
354 	osif_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d",
355 		  params->wake_dura_us, params->min_wake_dura_us,
356 		  params->max_wake_dura_us, params->sp_offset_us,
357 		  params->twt_cmd);
358 	osif_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d wake_tsf 0x%llx",
359 		  params->flag_bcast, params->flag_trigger,
360 		  params->flag_flow_type,
361 		  params->flag_protection,
362 		  params->wake_time_tsf);
363 	osif_debug("twt: peer mac_addr "
364 		  QDF_MAC_ADDR_FMT,
365 		  QDF_MAC_ADDR_REF(params->peer_macaddr.bytes));
366 	osif_debug("twt: announce timeout(in us) %u",
367 		   params->announce_timeout_us);
368 	return 0;
369 }
370 
371 /**
372  * osif_twt_parse_del_dialog_attrs() - Parse TWT del dialog parameters
373  * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
374  * @tb: nl attributes
375  * @params: twt del dialog parameters
376  *
377  * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX
378  *
379  * Return: 0 or -EINVAL.
380  */
381 static int
osif_twt_parse_del_dialog_attrs(struct nlattr ** tb,struct twt_del_dialog_param * params)382 osif_twt_parse_del_dialog_attrs(struct nlattr **tb,
383 				struct twt_del_dialog_param *params)
384 {
385 	int cmd_id;
386 
387 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
388 	if (tb[cmd_id]) {
389 		params->dialog_id = nla_get_u8(tb[cmd_id]);
390 	} else {
391 		params->dialog_id = 0;
392 		osif_debug("TWT_TERMINATE_FLOW_ID not specified. set to zero");
393 	}
394 
395 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
396 	if (tb[cmd_id]) {
397 		params->dialog_id = nla_get_u8(tb[cmd_id]);
398 		osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id);
399 	}
400 
401 	osif_debug("twt: dialog_id %d vdev %d peer mac_addr "QDF_MAC_ADDR_FMT,
402 		   params->dialog_id, params->vdev_id,
403 		   QDF_MAC_ADDR_REF(params->peer_macaddr.bytes));
404 
405 	return 0;
406 }
407 
osif_fill_peer_macaddr(struct wlan_objmgr_vdev * vdev,uint8_t * mac_addr)408 int osif_fill_peer_macaddr(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr)
409 {
410 	struct wlan_objmgr_peer *peer;
411 
412 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TWT_ID);
413 	if (!peer) {
414 		osif_err("peer is null");
415 		return -EAGAIN;
416 	}
417 	wlan_peer_obj_lock(peer);
418 	qdf_mem_copy(mac_addr, wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
419 	wlan_peer_obj_unlock(peer);
420 
421 	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
422 	return 0;
423 }
424 
425 /**
426  * osif_twt_ack_wait_response: TWT wait for ack event if it's supported
427  * @psoc: psoc context
428  * @request: OSIF request cookie
429  * @twt_cmd: TWT command for which ack event come
430  *
431  * Return: QDF_STATUS
432  */
433 static QDF_STATUS
osif_twt_ack_wait_response(struct wlan_objmgr_psoc * psoc,struct osif_request * request,int twt_cmd)434 osif_twt_ack_wait_response(struct wlan_objmgr_psoc *psoc,
435 			   struct osif_request *request, int twt_cmd)
436 {
437 	struct twt_ack_context *ack_priv;
438 	int ret = 0;
439 	bool twt_ack_cap;
440 
441 	ucfg_twt_get_twt_ack_supported(psoc, &twt_ack_cap);
442 
443 	if (!twt_ack_cap) {
444 		osif_err("TWT ack is not supported. No need to wait");
445 		return QDF_STATUS_SUCCESS;
446 	}
447 
448 	ack_priv = osif_request_priv(request);
449 	ack_priv->twt_cmd_ack = twt_cmd;
450 
451 	ret = osif_request_wait_for_response(request);
452 	if (ret) {
453 		osif_err("TWT ack response timed out");
454 		return QDF_STATUS_E_TIMEOUT;
455 	}
456 
457 	osif_debug("TWT ack info: vdev_id %d dialog_id %d twt_cmd %d status %d peer_macaddr "
458 			  QDF_MAC_ADDR_FMT, ack_priv->vdev_id, ack_priv->dialog_id,
459 			  ack_priv->twt_cmd_ack, ack_priv->status,
460 			  QDF_MAC_ADDR_REF(ack_priv->peer_macaddr.bytes));
461 
462 	return QDF_STATUS_SUCCESS;
463 }
464 
465 static void
osif_send_twt_delete_cmd(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * peer_mac,uint8_t dialog_id,bool is_ps_disabled)466 osif_send_twt_delete_cmd(struct wlan_objmgr_vdev *vdev,
467 			 struct qdf_mac_addr *peer_mac, uint8_t dialog_id,
468 			 bool is_ps_disabled)
469 {
470 	uint32_t twt_next_action = HOST_TWT_SEND_DELETE_CMD;
471 
472 	ucfg_twt_set_work_params(vdev, peer_mac, dialog_id, is_ps_disabled,
473 				 twt_next_action);
474 	qdf_sched_work(0, &vdev->twt_work);
475 }
476 
477 static int
osif_send_twt_setup_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_add_dialog_param * twt_params)478 osif_send_twt_setup_req(struct wlan_objmgr_vdev *vdev,
479 			struct wlan_objmgr_psoc *psoc,
480 			struct twt_add_dialog_param *twt_params)
481 {
482 	QDF_STATUS status;
483 	int twt_cmd, ret = 0;
484 	struct osif_request *request;
485 	struct twt_ack_context *ack_priv;
486 	void *context;
487 	static const struct osif_request_params params = {
488 				.priv_size = sizeof(*ack_priv),
489 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
490 	};
491 
492 	request = osif_request_alloc(&params);
493 	if (!request) {
494 		osif_err("Request allocation failure");
495 		return -ENOMEM;
496 	}
497 
498 	context = osif_request_cookie(request);
499 
500 	status = ucfg_twt_setup_req(psoc, twt_params, context);
501 	if (QDF_IS_STATUS_ERROR(status)) {
502 		ret = qdf_status_to_os_return(status);
503 		osif_err("Failed to send add dialog command");
504 		goto cleanup;
505 	}
506 
507 	twt_cmd = HOST_TWT_ADD_DIALOG_CMDID;
508 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
509 	if (QDF_IS_STATUS_ERROR(status)) {
510 		/*
511 		 * If the TWT ack event comes after the timeout or
512 		 * if the event is not received from the firmware, then
513 		 * initialize the context (reset the active command),
514 		 * otherwise future commands shall be blocked.
515 		 */
516 		ucfg_twt_init_context(psoc, &twt_params->peer_macaddr,
517 				      twt_params->dialog_id);
518 		ret = qdf_status_to_os_return(status);
519 		goto cleanup;
520 	}
521 
522 	ack_priv = osif_request_priv(request);
523 	if (ack_priv->status) {
524 		osif_err("Received TWT ack error: %d. Reset twt command",
525 			 ack_priv->status);
526 
527 		if (ucfg_twt_is_setup_done(psoc,
528 					   &twt_params->peer_macaddr,
529 					   twt_params->dialog_id)) {
530 			/* If TWT setup is already done then this is
531 			 * renegotiation failure scenario.
532 			 * Terminate TWT session on renegotiation failure.
533 			 */
534 			osif_debug("setup_done set, renego failure");
535 			osif_send_twt_delete_cmd(vdev,
536 						 &twt_params->peer_macaddr,
537 						 twt_params->dialog_id, false);
538 		} else {
539 			ucfg_twt_init_context(psoc, &twt_params->peer_macaddr,
540 					      twt_params->dialog_id);
541 		}
542 
543 		switch (ack_priv->status) {
544 		case HOST_ADD_TWT_STATUS_INVALID_PARAM:
545 		case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
546 		case HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
547 			ret = -EINVAL;
548 			break;
549 		case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
550 		case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
551 		case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
552 		case HOST_ADD_TWT_STATUS_LINK_SWITCH_IN_PROGRESS:
553 		case HOST_ADD_TWT_STATUS_UNSUPPORTED_MODE_MLMR:
554 			ret = -EBUSY;
555 			break;
556 		case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
557 			ret = -EOPNOTSUPP;
558 			break;
559 		case HOST_ADD_TWT_STATUS_NOT_READY:
560 			ret = -EAGAIN;
561 			break;
562 		case HOST_ADD_TWT_STATUS_NO_RESOURCE:
563 			ret = -ENOMEM;
564 			break;
565 		default:
566 			ret = -EINVAL;
567 			break;
568 		}
569 	}
570 
571 cleanup:
572 	osif_request_put(request);
573 	return ret;
574 }
575 
576 /**
577  * osif_send_twt_pause_req() - Send TWT pause dialog command to target
578  * @vdev: vdev
579  * @psoc: psoc
580  * @twt_params: Pointer to pause dialog cmd params structure
581  *
582  * Return: 0 on success, negative value on failure
583  */
584 static int
osif_send_twt_pause_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_pause_dialog_cmd_param * twt_params)585 osif_send_twt_pause_req(struct wlan_objmgr_vdev *vdev,
586 			struct wlan_objmgr_psoc *psoc,
587 			struct twt_pause_dialog_cmd_param *twt_params)
588 {
589 	QDF_STATUS status;
590 	int ret = 0, twt_cmd;
591 	struct osif_request *request;
592 	struct twt_ack_context *ack_priv;
593 	void *context;
594 	static const struct osif_request_params params = {
595 				.priv_size = sizeof(*ack_priv),
596 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
597 	};
598 
599 	request = osif_request_alloc(&params);
600 	if (!request) {
601 		osif_err("Request allocation failure");
602 		return -ENOMEM;
603 	}
604 
605 	context = osif_request_cookie(request);
606 
607 	status = ucfg_twt_pause_req(psoc, twt_params, context);
608 	if (QDF_IS_STATUS_ERROR(status)) {
609 		osif_err("Failed to send pause dialog command");
610 		ret = qdf_status_to_os_return(status);
611 		goto cleanup;
612 	}
613 
614 	twt_cmd = HOST_TWT_PAUSE_DIALOG_CMDID;
615 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
616 	if (QDF_IS_STATUS_ERROR(status)) {
617 		ret = qdf_status_to_os_return(status);
618 		goto cleanup;
619 	}
620 
621 	ack_priv = osif_request_priv(request);
622 	if (ack_priv->status != HOST_TWT_PAUSE_STATUS_OK) {
623 		osif_err("Received TWT ack error:%d. Reset twt command",
624 			 ack_priv->status);
625 
626 		switch (ack_priv->status) {
627 		case HOST_TWT_PAUSE_STATUS_INVALID_PARAM:
628 		case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED:
629 		case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR:
630 			ret = -EINVAL;
631 			break;
632 		case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST:
633 			ret = -EAGAIN;
634 			break;
635 		case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY:
636 			ret = -EINPROGRESS;
637 			break;
638 		case HOST_TWT_PAUSE_STATUS_NO_RESOURCE:
639 			ret = -ENOMEM;
640 			break;
641 		case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS:
642 		case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS:
643 		case HOST_TWT_PAUSE_STATUS_SCAN_IN_PROGRESS:
644 			ret = -EBUSY;
645 			break;
646 		default:
647 			ret = -EAGAIN;
648 			break;
649 		}
650 	}
651 
652 cleanup:
653 	osif_request_put(request);
654 	return ret;
655 }
656 
657 static int
osif_send_sta_twt_teardown_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_del_dialog_param * twt_params)658 osif_send_sta_twt_teardown_req(struct wlan_objmgr_vdev *vdev,
659 			       struct wlan_objmgr_psoc *psoc,
660 			       struct twt_del_dialog_param *twt_params)
661 {
662 	QDF_STATUS status;
663 	int twt_cmd, ret = 0;
664 	struct osif_request *request;
665 	struct twt_ack_context *ack_priv;
666 	void *context;
667 	static const struct osif_request_params params = {
668 				.priv_size = sizeof(*ack_priv),
669 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
670 	};
671 
672 	request = osif_request_alloc(&params);
673 	if (!request) {
674 		osif_err("Request allocation failure");
675 		return -ENOMEM;
676 	}
677 
678 	context = osif_request_cookie(request);
679 
680 	status = ucfg_twt_teardown_req(psoc, twt_params, context);
681 	if (QDF_IS_STATUS_ERROR(status)) {
682 		ret = qdf_status_to_os_return(status);
683 		osif_err("Failed to send del dialog command");
684 		goto cleanup;
685 	}
686 
687 	twt_cmd = HOST_TWT_DEL_DIALOG_CMDID;
688 
689 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
690 	if (QDF_IS_STATUS_ERROR(status)) {
691 		ucfg_twt_reset_active_command(psoc, &twt_params->peer_macaddr,
692 					      twt_params->dialog_id);
693 		ret = qdf_status_to_os_return(status);
694 		goto cleanup;
695 	}
696 
697 	ack_priv = osif_request_priv(request);
698 	if (ack_priv->status != HOST_TWT_DEL_STATUS_OK) {
699 		osif_err("Received TWT ack error:%d. Reset twt command",
700 			  ack_priv->status);
701 
702 		switch (ack_priv->status) {
703 		case HOST_TWT_DEL_STATUS_INVALID_PARAM:
704 		case HOST_TWT_DEL_STATUS_UNKNOWN_ERROR:
705 			ret = -EINVAL;
706 			break;
707 		case HOST_TWT_DEL_STATUS_DIALOG_ID_NOT_EXIST:
708 			ret = -EAGAIN;
709 			break;
710 		case HOST_TWT_DEL_STATUS_DIALOG_ID_BUSY:
711 			ret = -EINPROGRESS;
712 			break;
713 		case HOST_TWT_DEL_STATUS_NO_RESOURCE:
714 			ret = -ENOMEM;
715 			break;
716 		case HOST_TWT_DEL_STATUS_ROAMING:
717 		case HOST_TWT_DEL_STATUS_CHAN_SW_IN_PROGRESS:
718 		case HOST_TWT_DEL_STATUS_SCAN_IN_PROGRESS:
719 			ret = -EBUSY;
720 			break;
721 		case HOST_TWT_DEL_STATUS_CONCURRENCY:
722 			ret = -EAGAIN;
723 			break;
724 		default:
725 			ret = -EAGAIN;
726 			break;
727 		}
728 	}
729 
730 cleanup:
731 	osif_request_put(request);
732 	return ret;
733 }
734 
735 /**
736  * osif_send_twt_resume_req() - Send TWT resume dialog command to target
737  * @vdev: vdev
738  * @psoc: psoc
739  * @twt_params: Pointer to resume dialog cmd params structure
740  *
741  * Return: 0 on success, negative value on failure
742  */
743 static int
osif_send_twt_resume_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_resume_dialog_cmd_param * twt_params)744 osif_send_twt_resume_req(struct wlan_objmgr_vdev *vdev,
745 			struct wlan_objmgr_psoc *psoc,
746 			struct twt_resume_dialog_cmd_param *twt_params)
747 {
748 	QDF_STATUS status;
749 	int ret = 0, twt_cmd;
750 	struct osif_request *request;
751 	struct twt_ack_context *ack_priv;
752 	void *context;
753 	static const struct osif_request_params params = {
754 				.priv_size = sizeof(*ack_priv),
755 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
756 	};
757 
758 	request = osif_request_alloc(&params);
759 	if (!request) {
760 		osif_err("Request allocation failure");
761 		return -ENOMEM;
762 	}
763 
764 	context = osif_request_cookie(request);
765 
766 	status = ucfg_twt_resume_req(psoc, twt_params, context);
767 	if (QDF_IS_STATUS_ERROR(status)) {
768 		osif_err("Failed to send resume dialog command");
769 		ret = qdf_status_to_os_return(status);
770 		goto cleanup;
771 	}
772 
773 	twt_cmd = HOST_TWT_RESUME_DIALOG_CMDID;
774 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
775 	if (QDF_IS_STATUS_ERROR(status)) {
776 		ret = qdf_status_to_os_return(status);
777 		goto cleanup;
778 	}
779 
780 	ack_priv = osif_request_priv(request);
781 	if (ack_priv->status != HOST_TWT_RESUME_STATUS_OK) {
782 		osif_err("Received TWT ack error:%d. Reset twt command",
783 			 ack_priv->status);
784 
785 		switch (ack_priv->status) {
786 		case HOST_TWT_RESUME_STATUS_INVALID_PARAM:
787 		case HOST_TWT_RESUME_STATUS_UNKNOWN_ERROR:
788 			ret = -EINVAL;
789 			break;
790 		case HOST_TWT_RESUME_STATUS_DIALOG_ID_NOT_EXIST:
791 		case HOST_TWT_RESUME_STATUS_NOT_PAUSED:
792 			ret = -EAGAIN;
793 			break;
794 		case HOST_TWT_RESUME_STATUS_DIALOG_ID_BUSY:
795 			ret = -EINPROGRESS;
796 			break;
797 		case HOST_TWT_RESUME_STATUS_NO_RESOURCE:
798 			ret = -ENOMEM;
799 			break;
800 		case HOST_TWT_RESUME_STATUS_CHAN_SW_IN_PROGRESS:
801 		case HOST_TWT_RESUME_STATUS_ROAM_IN_PROGRESS:
802 		case HOST_TWT_RESUME_STATUS_SCAN_IN_PROGRESS:
803 			ret = -EBUSY;
804 			break;
805 		default:
806 			ret = -EINVAL;
807 			break;
808 		}
809 	}
810 
811 cleanup:
812 	osif_request_put(request);
813 	return ret;
814 }
815 
816 /**
817  * osif_send_twt_nudge_req() - Send TWT nudge dialog command to target
818  * @vdev: vdev
819  * @psoc: psoc
820  * @twt_params: Pointer to nudge dialog cmd params structure
821  *
822  * Return: 0 on success, negative value on failure
823  */
824 static int
osif_send_twt_nudge_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_nudge_dialog_cmd_param * twt_params)825 osif_send_twt_nudge_req(struct wlan_objmgr_vdev *vdev,
826 			struct wlan_objmgr_psoc *psoc,
827 			struct twt_nudge_dialog_cmd_param *twt_params)
828 {
829 	QDF_STATUS status;
830 	int ret = 0, twt_cmd;
831 	struct osif_request *request;
832 	struct twt_ack_context *ack_priv;
833 	void *context;
834 	static const struct osif_request_params params = {
835 				.priv_size = sizeof(*ack_priv),
836 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
837 	};
838 
839 	request = osif_request_alloc(&params);
840 	if (!request) {
841 		osif_err("Request allocation failure");
842 		return -ENOMEM;
843 	}
844 
845 	context = osif_request_cookie(request);
846 
847 	status = ucfg_twt_nudge_req(psoc, twt_params, context);
848 	if (QDF_IS_STATUS_ERROR(status)) {
849 		osif_err("Failed to send nudge dialog command");
850 		ret = qdf_status_to_os_return(status);
851 		goto cleanup;
852 	}
853 
854 	twt_cmd = HOST_TWT_NUDGE_DIALOG_CMDID;
855 
856 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
857 	if (QDF_IS_STATUS_ERROR(status)) {
858 		ret = qdf_status_to_os_return(status);
859 		goto cleanup;
860 	}
861 
862 	ack_priv = osif_request_priv(request);
863 	if (ack_priv->status != HOST_TWT_NUDGE_STATUS_OK) {
864 		osif_err("Received TWT ack error:%d. Reset twt command",
865 			 ack_priv->status);
866 
867 		switch (ack_priv->status) {
868 		case HOST_TWT_NUDGE_STATUS_INVALID_PARAM:
869 		case HOST_TWT_NUDGE_STATUS_UNKNOWN_ERROR:
870 			ret = -EINVAL;
871 			break;
872 		case HOST_TWT_NUDGE_STATUS_DIALOG_ID_NOT_EXIST:
873 			ret = -EAGAIN;
874 			break;
875 		case HOST_TWT_NUDGE_STATUS_DIALOG_ID_BUSY:
876 			ret = -EINPROGRESS;
877 			break;
878 		case HOST_TWT_NUDGE_STATUS_NO_RESOURCE:
879 			ret = -ENOMEM;
880 			break;
881 		case HOST_TWT_NUDGE_STATUS_CHAN_SW_IN_PROGRESS:
882 		case HOST_TWT_NUDGE_STATUS_ROAM_IN_PROGRESS:
883 		case HOST_TWT_NUDGE_STATUS_SCAN_IN_PROGRESS:
884 			ret = -EBUSY;
885 			break;
886 		default:
887 			ret = -EINVAL;
888 			break;
889 		}
890 	}
891 
892 cleanup:
893 	osif_request_put(request);
894 	return ret;
895 }
896 
osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)897 int osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc *psoc,
898 				       uint8_t pdev_id)
899 {
900 	struct twt_enable_param req = {0};
901 
902 	req.pdev_id = pdev_id;
903 	req.ext_conf_present = true;
904 
905 	return osif_twt_requestor_enable(psoc, &req);
906 }
907 
osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)908 int osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc *psoc,
909 				       uint8_t pdev_id)
910 {
911 	struct twt_enable_param req = {0};
912 
913 	req.pdev_id = pdev_id;
914 	req.ext_conf_present = true;
915 
916 	return osif_twt_responder_enable(psoc, &req);
917 }
918 
osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id,uint32_t reason)919 int osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc *psoc,
920 					uint8_t pdev_id, uint32_t reason)
921 {
922 	struct twt_disable_param req = {0};
923 
924 	req.pdev_id = pdev_id;
925 	req.ext_conf_present = true;
926 	req.dis_reason_code = reason;
927 
928 	return osif_twt_requestor_disable(psoc, &req);
929 }
930 
osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id,uint32_t reason)931 int osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc *psoc,
932 					uint8_t pdev_id, uint32_t reason)
933 {
934 	struct twt_disable_param req = {0};
935 
936 	req.pdev_id = pdev_id;
937 	req.ext_conf_present = true;
938 	req.dis_reason_code = reason;
939 
940 	return osif_twt_responder_disable(psoc, &req);
941 }
942 
osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc * psoc,struct qdf_mac_addr * mac_addr,uint8_t vdev_id)943 void osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc *psoc,
944 				     struct qdf_mac_addr *mac_addr,
945 				     uint8_t vdev_id)
946 {
947 	struct twt_del_dialog_param params = {0};
948 	int ret;
949 	struct wlan_objmgr_vdev *vdev;
950 
951 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_TWT_ID);
952 	if (!vdev) {
953 		osif_err("vdev is NULL");
954 		return;
955 	}
956 
957 	params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
958 	params.vdev_id = vdev_id;
959 	qdf_copy_macaddr(&params.peer_macaddr, mac_addr);
960 
961 	if (ucfg_twt_is_setup_done(psoc, mac_addr, params.dialog_id)) {
962 		osif_debug("vdev%d: Terminate existing TWT session %d due to ps disable",
963 			  params.vdev_id, params.dialog_id);
964 		ret = osif_send_sta_twt_teardown_req(vdev, psoc, &params);
965 		if (ret) {
966 			osif_debug("TWT teardown is failed on vdev: %d",
967 				   vdev_id);
968 			osif_send_twt_delete_cmd(vdev, mac_addr,
969 						 params.dialog_id, true);
970 		}
971 	}
972 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
973 }
974 
osif_twt_get_capabilities(struct wlan_objmgr_vdev * vdev)975 int osif_twt_get_capabilities(struct wlan_objmgr_vdev *vdev)
976 {
977 	struct wlan_objmgr_psoc *psoc;
978 	enum QDF_OPMODE mode;
979 	QDF_STATUS status;
980 	uint8_t vdev_id;
981 
982 	psoc = wlan_vdev_get_psoc(vdev);
983 	if (!psoc)
984 		return -EINVAL;
985 
986 	vdev_id = wlan_vdev_get_id(vdev);
987 	mode = wlan_vdev_mlme_get_opmode(vdev);
988 	if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE)
989 		return -EOPNOTSUPP;
990 
991 	if (!wlan_cm_is_vdev_connected(vdev)) {
992 		osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode);
993 		return -EAGAIN;
994 	}
995 
996 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
997 		return -EBUSY;
998 
999 	status = osif_twt_send_get_capabilities_response(psoc, vdev);
1000 	if (QDF_IS_STATUS_ERROR(status))
1001 		osif_err_rl("TWT: Get capabilities failed");
1002 
1003 	return qdf_status_to_os_return(status);
1004 }
1005 
osif_twt_setup_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1006 int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev,
1007 		       struct nlattr *twt_param_attr)
1008 {
1009 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1010 	struct wlan_objmgr_psoc *psoc;
1011 	int ret = 0;
1012 	uint8_t vdev_id, pdev_id;
1013 	struct twt_add_dialog_param params = {0};
1014 	uint32_t congestion_timeout = 0, reason;
1015 	uint8_t peer_cap;
1016 	QDF_STATUS qdf_status;
1017 
1018 	psoc = wlan_vdev_get_psoc(vdev);
1019 	if (!psoc) {
1020 		osif_err("NULL psoc");
1021 		return -EINVAL;
1022 	}
1023 
1024 	vdev_id = wlan_vdev_get_id(vdev);
1025 
1026 	ret = wlan_cfg80211_nla_parse_nested(tb2,
1027 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1028 					 twt_param_attr,
1029 					 qca_wlan_vendor_twt_add_dialog_policy);
1030 	if (ret)
1031 		return ret;
1032 
1033 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1034 	if (ret)
1035 		return ret;
1036 
1037 	params.vdev_id = vdev_id;
1038 	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
1039 
1040 	ret = osif_twt_parse_add_dialog_attrs(tb2, &params);
1041 	if (ret)
1042 		return ret;
1043 
1044 	qdf_status = ucfg_twt_get_peer_capabilities(psoc, &params.peer_macaddr,
1045 						    &peer_cap);
1046 	if (QDF_IS_STATUS_ERROR(qdf_status))
1047 		return -EINVAL;
1048 
1049 	if (params.flag_bcast && !(peer_cap & WLAN_TWT_CAPA_BROADCAST)) {
1050 		osif_err_rl("TWT setup reject: TWT Broadcast not supported");
1051 		return -EOPNOTSUPP;
1052 	}
1053 
1054 	if (!params.flag_bcast && !(peer_cap & WLAN_TWT_CAPA_RESPONDER)) {
1055 		osif_err_rl("TWT setup reject: TWT responder not supported");
1056 		return -EOPNOTSUPP;
1057 	}
1058 
1059 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1060 	if (ret)
1061 		return ret;
1062 
1063 	if (osif_twt_setup_conc_allowed(psoc, vdev_id)) {
1064 		osif_err_rl("TWT setup reject: SCC or MCC concurrency exists");
1065 		return -EAGAIN;
1066 	}
1067 
1068 	ucfg_twt_cfg_get_congestion_timeout(psoc, &congestion_timeout);
1069 
1070 	if (congestion_timeout) {
1071 		reason = HOST_TWT_DISABLE_REASON_CHANGE_CONGESTION_TIMEOUT;
1072 		ret = osif_twt_send_requestor_disable_cmd(psoc, pdev_id,
1073 							  reason);
1074 		if (ret) {
1075 			osif_err("Failed to disable TWT");
1076 			return ret;
1077 		}
1078 	}
1079 
1080 	ucfg_twt_cfg_set_congestion_timeout(psoc, 0);
1081 
1082 	ret = osif_twt_send_requestor_enable_cmd(psoc, pdev_id);
1083 	if (ret) {
1084 		osif_err("Failed to Enable TWT");
1085 		return ret;
1086 	}
1087 
1088 	return osif_send_twt_setup_req(vdev, psoc, &params);
1089 }
1090 
1091 /**
1092  * osif_twt_handle_renego_failure() - Upon re-nego failure send TWT teardown
1093  * @psoc: Pointer to psoc object
1094  * @event: Pointer to Add dialog complete event structure
1095  *
1096  * Upon re-negotiation failure, this function constructs TWT teardown
1097  * message to the target.
1098  *
1099  * Return: None
1100  */
1101 void
osif_twt_handle_renego_failure(struct wlan_objmgr_psoc * psoc,struct twt_add_dialog_complete_event * event)1102 osif_twt_handle_renego_failure(struct wlan_objmgr_psoc *psoc,
1103 		       struct twt_add_dialog_complete_event *event)
1104 {
1105 	uint8_t pdev_id;
1106 	struct wlan_objmgr_pdev *pdev;
1107 	struct wlan_objmgr_vdev *vdev;
1108 	uint32_t vdev_id;
1109 
1110 	if (!event)
1111 		return;
1112 
1113 	vdev_id = event->params.vdev_id;
1114 	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id,
1115 						WLAN_TWT_ID);
1116 	if (pdev_id == WLAN_INVALID_PDEV_ID) {
1117 		osif_err("Invalid pdev id");
1118 		return;
1119 	}
1120 
1121 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID);
1122 	if (!pdev) {
1123 		osif_err("Invalid pdev");
1124 		return;
1125 	}
1126 
1127 	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
1128 						    WLAN_TWT_ID);
1129 	if (!vdev) {
1130 		osif_err("vdev object is NULL");
1131 		goto end;
1132 	}
1133 
1134 	osif_send_twt_delete_cmd(vdev, &event->params.peer_macaddr,
1135 				 event->params.dialog_id, false);
1136 
1137 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
1138 
1139 end:
1140 	wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID);
1141 }
1142 
osif_twt_sap_teardown_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1143 int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev,
1144 			      struct nlattr *twt_param_attr)
1145 {
1146 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1147 	struct wlan_objmgr_psoc *psoc;
1148 	int id, id1, ret = 0;
1149 	uint8_t vdev_id;
1150 	struct twt_del_dialog_param params = {0};
1151 	QDF_STATUS status;
1152 
1153 	psoc = wlan_vdev_get_psoc(vdev);
1154 	if (!psoc) {
1155 		osif_err("NULL psoc");
1156 		return -EINVAL;
1157 	}
1158 
1159 	vdev_id = wlan_vdev_get_id(vdev);
1160 	params.vdev_id = vdev_id;
1161 
1162 	ret = wlan_cfg80211_nla_parse_nested(tb,
1163 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1164 					 twt_param_attr,
1165 					 qca_wlan_vendor_twt_add_dialog_policy);
1166 	if (ret)
1167 		return ret;
1168 
1169 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1170 	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1171 	if (tb[id] && tb[id1]) {
1172 		params.dialog_id = nla_get_u8(tb[id]);
1173 		nla_memcpy(params.peer_macaddr.bytes, tb[id1],
1174 			   QDF_MAC_ADDR_SIZE);
1175 	} else if (!tb[id] && !tb[id1]) {
1176 		struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
1177 
1178 		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
1179 		qdf_copy_macaddr(&params.peer_macaddr, &bcast_addr);
1180 	} else {
1181 		osif_err_rl("get_params dialog_id or mac_addr is missing");
1182 		return -EINVAL;
1183 	}
1184 
1185 	if (!params.dialog_id)
1186 		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
1187 
1188 	if (params.dialog_id != TWT_ALL_SESSIONS_DIALOG_ID &&
1189 	    qdf_is_macaddr_broadcast(&params.peer_macaddr)) {
1190 		osif_err("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d",
1191 			TWT_ALL_SESSIONS_DIALOG_ID, params.dialog_id);
1192 		return -EINVAL;
1193 	}
1194 
1195 	osif_debug("vdev_id %d dialog_id %d peer mac_addr "
1196 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
1197 		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1198 
1199 	status = ucfg_twt_teardown_req(psoc, &params, NULL);
1200 	if (QDF_IS_STATUS_ERROR(status)) {
1201 		osif_err("Failed to send del dialog command");
1202 		ret = qdf_status_to_os_return(status);
1203 	}
1204 
1205 	return ret;
1206 }
1207 
osif_twt_sta_teardown_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1208 int osif_twt_sta_teardown_req(struct wlan_objmgr_vdev *vdev,
1209 			      struct nlattr *twt_param_attr)
1210 {
1211 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1212 	struct wlan_objmgr_psoc *psoc;
1213 	int ret = 0;
1214 	uint8_t vdev_id, pdev_id;
1215 	struct twt_del_dialog_param params = {0};
1216 
1217 	psoc = wlan_vdev_get_psoc(vdev);
1218 	if (!psoc) {
1219 		osif_err("NULL psoc");
1220 		return -EINVAL;
1221 	}
1222 
1223 	vdev_id = wlan_vdev_get_id(vdev);
1224 
1225 	if (!wlan_cm_is_vdev_connected(vdev)) {
1226 		osif_err_rl("Not associated!, vdev %d", vdev_id);
1227 		/*
1228 		 * Return success, since STA is not associated and there is
1229 		 * no TWT session.
1230 		 */
1231 		return 0;
1232 	}
1233 
1234 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
1235 		return -EBUSY;
1236 
1237 	if (wlan_get_vdev_status(vdev)) {
1238 		osif_err_rl("Scan in progress");
1239 		return -EBUSY;
1240 	}
1241 
1242 	ret = wlan_cfg80211_nla_parse_nested(tb2,
1243 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1244 					 twt_param_attr,
1245 					 qca_wlan_vendor_twt_add_dialog_policy);
1246 	if (ret)
1247 		return ret;
1248 
1249 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1250 	if (ret)
1251 		return ret;
1252 
1253 	params.vdev_id = vdev_id;
1254 	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
1255 
1256 	ret = osif_twt_parse_del_dialog_attrs(tb2, &params);
1257 	if (ret)
1258 		return ret;
1259 
1260 	return osif_send_sta_twt_teardown_req(vdev, psoc, &params);
1261 }
1262 
1263 static void
osif_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1264 osif_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev,
1265 				   void *object, void *arg)
1266 {
1267 	struct wlan_objmgr_vdev *vdev = object;
1268 	struct twt_conc_context *twt_arg = arg;
1269 	QDF_STATUS status;
1270 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1271 	uint32_t reason;
1272 
1273 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
1274 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1275 		osif_debug("Concurrency exist on SAP vdev");
1276 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_SCC;
1277 		status = osif_twt_send_responder_disable_cmd(twt_arg->psoc,
1278 							     pdev_id, reason);
1279 		if (QDF_IS_STATUS_ERROR(status)) {
1280 			osif_err("TWT responder disable cmd to fw failed");
1281 			return;
1282 		}
1283 		ucfg_twt_update_beacon_template();
1284 	}
1285 
1286 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1287 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1288 		osif_debug("Concurrency exist on STA vdev");
1289 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_SCC;
1290 		status = osif_twt_send_requestor_disable_cmd(twt_arg->psoc,
1291 							     pdev_id, reason);
1292 		if (QDF_IS_STATUS_ERROR(status)) {
1293 			osif_err("TWT requestor disable cmd to fw failed");
1294 			return;
1295 		}
1296 	}
1297 }
1298 
1299 static void
osif_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1300 osif_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev,
1301 				   void *object, void *arg)
1302 {
1303 	struct wlan_objmgr_vdev *vdev = object;
1304 	struct twt_conc_context *twt_arg = arg;
1305 	QDF_STATUS status;
1306 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1307 	uint32_t reason;
1308 	uint8_t vdev_id;
1309 	struct wlan_objmgr_psoc *psoc;
1310 
1311 	vdev_id = wlan_vdev_get_id(vdev);
1312 	psoc = wlan_pdev_get_psoc(pdev);
1313 
1314 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
1315 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1316 		if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id))
1317 			return;
1318 
1319 		osif_debug("Concurrency exist on SAP vdev");
1320 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_MCC;
1321 		status = osif_twt_send_responder_disable_cmd(twt_arg->psoc,
1322 							     pdev_id, reason);
1323 		if (QDF_IS_STATUS_ERROR(status)) {
1324 			osif_err("TWT responder disable cmd to fw failed");
1325 			return;
1326 		}
1327 		ucfg_twt_update_beacon_template();
1328 	}
1329 
1330 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1331 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1332 		osif_debug("Concurrency exist on STA vdev");
1333 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_MCC;
1334 		status = osif_twt_send_requestor_disable_cmd(twt_arg->psoc,
1335 							     pdev_id, reason);
1336 		if (QDF_IS_STATUS_ERROR(status)) {
1337 			osif_err("TWT requestor disable cmd to fw failed");
1338 			return;
1339 		}
1340 	}
1341 }
1342 
1343 static void
osif_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1344 osif_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev,
1345 				   void *object, void *arg)
1346 {
1347 	struct wlan_objmgr_vdev *vdev = object;
1348 	struct twt_conc_context *twt_arg = arg;
1349 	QDF_STATUS status;
1350 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1351 
1352 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
1353 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1354 		osif_debug("SAP vdev exist");
1355 		status = osif_twt_send_responder_enable_cmd(twt_arg->psoc,
1356 							    pdev_id);
1357 		if (QDF_IS_STATUS_ERROR(status)) {
1358 			osif_err("TWT responder enable cmd to firmware failed");
1359 			return;
1360 		}
1361 		ucfg_twt_update_beacon_template();
1362 	}
1363 
1364 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1365 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1366 		osif_debug("STA vdev exist");
1367 		status = osif_twt_send_requestor_enable_cmd(twt_arg->psoc,
1368 							    pdev_id);
1369 		if (QDF_IS_STATUS_ERROR(status)) {
1370 			osif_err("TWT requestor enable cmd to firmware failed");
1371 			return;
1372 		}
1373 	}
1374 }
1375 
osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev)1376 void osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc *psoc,
1377 					 struct wlan_objmgr_pdev *pdev)
1378 {
1379 	uint32_t num_connections, sap_count, sta_count;
1380 	QDF_STATUS status;
1381 	struct twt_conc_context twt_arg;
1382 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1383 
1384 	num_connections = policy_mgr_get_connection_count(psoc);
1385 	sta_count = policy_mgr_mode_specific_connection_count(psoc,
1386 							      PM_STA_MODE,
1387 							      NULL);
1388 	sap_count = policy_mgr_get_sap_mode_count(psoc, NULL);
1389 
1390 	twt_arg.psoc = psoc;
1391 
1392 	osif_debug("Total connection %d, sta_count %d, sap_count %d",
1393 		  num_connections, sta_count, sap_count);
1394 	switch (num_connections) {
1395 	case 1:
1396 		if (sta_count == 1) {
1397 			osif_twt_send_requestor_enable_cmd(psoc, pdev_id);
1398 		} else if (sap_count == 1) {
1399 			osif_twt_send_responder_enable_cmd(psoc, pdev_id);
1400 			ucfg_twt_update_beacon_template();
1401 		}
1402 		break;
1403 	case 2:
1404 		if (policy_mgr_current_concurrency_is_scc(psoc)) {
1405 			status = wlan_objmgr_pdev_iterate_obj_list(
1406 					pdev,
1407 					WLAN_VDEV_OP,
1408 					osif_twt_concurrency_update_on_scc,
1409 					&twt_arg, 0,
1410 					WLAN_TWT_ID);
1411 			if (QDF_IS_STATUS_ERROR(status)) {
1412 				osif_err("2port conc: SAP/STA not in SCC");
1413 				return;
1414 			}
1415 		} else if (policy_mgr_current_concurrency_is_mcc(psoc)) {
1416 			status = wlan_objmgr_pdev_iterate_obj_list(
1417 					pdev,
1418 					WLAN_VDEV_OP,
1419 					osif_twt_concurrency_update_on_mcc,
1420 					&twt_arg, 0,
1421 					WLAN_TWT_ID);
1422 			if (QDF_IS_STATUS_ERROR(status)) {
1423 				osif_err("2port conc: SAP/STA not in MCC");
1424 				return;
1425 			}
1426 		} else if (policy_mgr_is_current_hwmode_dbs(psoc)) {
1427 			status = wlan_objmgr_pdev_iterate_obj_list(
1428 					pdev,
1429 					WLAN_VDEV_OP,
1430 					osif_twt_concurrency_update_on_dbs,
1431 					&twt_arg, 0,
1432 					WLAN_TWT_ID);
1433 			if (QDF_IS_STATUS_ERROR(status)) {
1434 				osif_err("SAP not in DBS case");
1435 				return;
1436 			}
1437 		}
1438 		break;
1439 	case 3:
1440 		if (policy_mgr_current_concurrency_is_scc(psoc)) {
1441 			status = wlan_objmgr_pdev_iterate_obj_list(
1442 					pdev,
1443 					WLAN_VDEV_OP,
1444 					osif_twt_concurrency_update_on_scc,
1445 					&twt_arg, 0,
1446 					WLAN_TWT_ID);
1447 			if (QDF_IS_STATUS_ERROR(status)) {
1448 				osif_err("3port conc: SAP/STA not in SCC");
1449 				return;
1450 			}
1451 		} else if (policy_mgr_current_concurrency_is_mcc(psoc)) {
1452 			status = wlan_objmgr_pdev_iterate_obj_list(
1453 					pdev,
1454 					WLAN_VDEV_OP,
1455 					osif_twt_concurrency_update_on_mcc,
1456 					&twt_arg, 0,
1457 					WLAN_TWT_ID);
1458 			if (QDF_IS_STATUS_ERROR(status)) {
1459 				osif_err("3port conc: SAP/STA not in MCC");
1460 				return;
1461 			}
1462 		}
1463 		break;
1464 	default:
1465 		osif_debug("Unexpected number of connections: %d",
1466 			   num_connections);
1467 		break;
1468 	}
1469 }
1470 
osif_twt_pause_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1471 int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev,
1472 		       struct nlattr *twt_param_attr)
1473 {
1474 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1475 	struct wlan_objmgr_psoc *psoc;
1476 	int ret = 0, id;
1477 	uint32_t vdev_id;
1478 	struct  twt_pause_dialog_cmd_param params = {0};
1479 
1480 	psoc = wlan_vdev_get_psoc(vdev);
1481 	if (!psoc) {
1482 		osif_err("NULL psoc");
1483 		return -EINVAL;
1484 	}
1485 
1486 	vdev_id = wlan_vdev_get_id(vdev);
1487 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1488 	if (ret)
1489 		return ret;
1490 
1491 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1492 	if (ret)
1493 		return ret;
1494 
1495 	if (twt_param_attr) {
1496 		ret = wlan_cfg80211_nla_parse_nested(tb,
1497 					QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1498 					twt_param_attr,
1499 					qca_wlan_vendor_twt_add_dialog_policy);
1500 		if (ret)
1501 			return ret;
1502 
1503 		id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1504 		if (tb[id])
1505 			params.dialog_id = nla_get_u8(tb[id]);
1506 		else
1507 			osif_debug("TWT: FLOW_ID not specified. set to zero");
1508 	} else {
1509 		osif_debug("TWT param not present. flow id set to zero");
1510 	}
1511 
1512 	osif_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr "
1513 		  QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id,
1514 		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1515 
1516 	return osif_send_twt_pause_req(vdev, psoc, &params);
1517 }
1518 
osif_twt_resume_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1519 int osif_twt_resume_req(struct wlan_objmgr_vdev *vdev,
1520 		       struct nlattr *twt_param_attr)
1521 {
1522 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1523 	struct wlan_objmgr_psoc *psoc;
1524 	int ret = 0;
1525 	uint32_t vdev_id;
1526 	int id, id2;
1527 	struct  twt_resume_dialog_cmd_param params = {0};
1528 
1529 	psoc = wlan_vdev_get_psoc(vdev);
1530 	if (!psoc) {
1531 		osif_err("NULL psoc");
1532 		return -EINVAL;
1533 	}
1534 
1535 	vdev_id = wlan_vdev_get_id(vdev);
1536 
1537 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1538 	if (ret)
1539 		return ret;
1540 
1541 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1542 	if (ret)
1543 		return ret;
1544 
1545 	ret = wlan_cfg80211_nla_parse_nested(tb,
1546 				QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX,
1547 				twt_param_attr,
1548 				qca_wlan_vendor_twt_resume_dialog_policy);
1549 	if (ret)
1550 		return ret;
1551 
1552 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID;
1553 	if (tb[id])
1554 		params.dialog_id = nla_get_u8(tb[id]);
1555 	else
1556 		osif_debug("TWT_RESUME_FLOW_ID not specified. set to zero");
1557 
1558 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT;
1559 	id2 = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT;
1560 	if (tb[id2])
1561 		params.sp_offset_us = nla_get_u32(tb[id2]);
1562 	else if (tb[id])
1563 		params.sp_offset_us = nla_get_u8(tb[id]);
1564 	else
1565 		params.sp_offset_us = 0;
1566 
1567 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE;
1568 	if (tb[id]) {
1569 		params.next_twt_size = nla_get_u32(tb[id]);
1570 	} else {
1571 		osif_err_rl("TWT_RESUME NEXT_TWT_SIZE is must");
1572 		return -EINVAL;
1573 	}
1574 	if (params.next_twt_size > TWT_MAX_NEXT_TWT_SIZE)
1575 		return -EINVAL;
1576 
1577 	osif_debug("twt_resume: vdev_id %d dialog_id %d peer mac_addr "
1578 		   QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id,
1579 		   QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1580 
1581 	return osif_send_twt_resume_req(vdev, psoc, &params);
1582 }
1583 
osif_twt_nudge_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1584 int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev,
1585 		       struct nlattr *twt_param_attr)
1586 {
1587 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1588 	struct wlan_objmgr_psoc *psoc;
1589 	int ret = 0, id;
1590 	uint32_t vdev_id;
1591 	struct  twt_nudge_dialog_cmd_param params = {0};
1592 	QDF_STATUS status;
1593 
1594 	psoc = wlan_vdev_get_psoc(vdev);
1595 	if (!psoc) {
1596 		osif_err("NULL psoc");
1597 		return -EINVAL;
1598 	}
1599 
1600 	vdev_id = wlan_vdev_get_id(vdev);
1601 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1602 	if (ret)
1603 		return ret;
1604 
1605 	ret = wlan_cfg80211_nla_parse_nested(tb,
1606 				QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX,
1607 				twt_param_attr,
1608 				qca_wlan_vendor_twt_nudge_dialog_policy);
1609 	if (ret)
1610 		return ret;
1611 
1612 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR;
1613 	if (tb[id]) {
1614 		nla_memcpy(params.peer_macaddr.bytes, tb[id],
1615 			   QDF_MAC_ADDR_SIZE);
1616 	} else {
1617 		ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1618 		if (ret)
1619 			return ret;
1620 	}
1621 
1622 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID;
1623 	if (!tb[id]) {
1624 		osif_debug("TWT: FLOW_ID not specified");
1625 		return -EINVAL;
1626 	}
1627 	params.dialog_id = nla_get_u8(tb[id]);
1628 
1629 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME;
1630 	if (!tb[id]) {
1631 		osif_debug("TWT: NEXT_TWT_SIZE not specified");
1632 		return -EINVAL;
1633 	}
1634 
1635 	params.suspend_duration = nla_get_u32(tb[id]);
1636 
1637 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE;
1638 	if (!tb[id]) {
1639 		osif_debug("TWT: NEXT_TWT_SIZE not specified");
1640 		return -EINVAL;
1641 	}
1642 	params.next_twt_size = nla_get_u32(tb[id]);
1643 
1644 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET;
1645 	if (tb[id]) {
1646 		uint8_t peer_cap = 0;
1647 
1648 		status = ucfg_twt_get_peer_capabilities(psoc,
1649 							&params.peer_macaddr,
1650 							&peer_cap);
1651 		if (QDF_IS_STATUS_SUCCESS(status) &&
1652 		    (peer_cap & WLAN_TWT_CAPA_FLEXIBLE)) {
1653 			params.sp_start_offset = nla_get_s32(tb[id]);
1654 		}
1655 	}
1656 
1657 	osif_debug("twt_nudge: vdev_id %d dialog_id %d ", params.vdev_id,
1658 		   params.dialog_id);
1659 	osif_debug("twt_nudge: suspend_duration %d next_twt_size %d",
1660 		   params.suspend_duration, params.next_twt_size);
1661 	osif_debug("peer mac_addr " QDF_MAC_ADDR_FMT,
1662 		   QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1663 	osif_debug("twt_nudge: sp_start_offset %d", params.sp_start_offset);
1664 
1665 	return osif_send_twt_nudge_req(vdev, psoc, &params);
1666 }
1667 
1668 static uint32_t
osif_twt_get_params_resp_len(struct twt_session_stats_info * params)1669 osif_twt_get_params_resp_len(struct twt_session_stats_info *params)
1670 {
1671 	uint32_t len = nla_total_size(0);
1672 
1673 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR */
1674 	len += nla_total_size(QDF_MAC_ADDR_SIZE);
1675 
1676 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
1677 	len += nla_total_size(sizeof(u8));
1678 
1679 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST */
1680 	len += nla_total_size(sizeof(u8));
1681 
1682 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER */
1683 	len += nla_total_size(sizeof(u8));
1684 
1685 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE */
1686 	len += nla_total_size(sizeof(u8));
1687 
1688 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION */
1689 	len += nla_total_size(sizeof(u8));
1690 
1691 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED */
1692 	len += nla_total_size(sizeof(u8));
1693 
1694 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION */
1695 	len += nla_total_size(sizeof(u32));
1696 
1697 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA */
1698 	len += nla_total_size(sizeof(u32));
1699 
1700 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/
1701 	len += nla_total_size(sizeof(u8));
1702 
1703 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF */
1704 	len += nla_total_size(sizeof(u64));
1705 
1706 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE */
1707 	len += nla_total_size(sizeof(u32));
1708 
1709 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE */
1710 	len += nla_total_size(sizeof(u8));
1711 
1712 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA */
1713 	len += nla_total_size(sizeof(u32));
1714 
1715 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */
1716 	if (params->pm_responder_bit_valid)
1717 		len += nla_total_size(sizeof(u8));
1718 
1719 	return len;
1720 }
1721 
1722 static enum qca_wlan_twt_setup_state
osif_get_converted_twt_state(enum wlan_twt_session_state state)1723 osif_get_converted_twt_state(enum wlan_twt_session_state state)
1724 {
1725 	switch (state) {
1726 	case WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED:
1727 		return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
1728 	case WLAN_TWT_SETUP_STATE_ACTIVE:
1729 		return QCA_WLAN_TWT_SETUP_STATE_ACTIVE;
1730 	case WLAN_TWT_SETUP_STATE_SUSPEND:
1731 		return QCA_WLAN_TWT_SETUP_STATE_SUSPEND;
1732 	default:
1733 		return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
1734 	}
1735 }
1736 
1737 static QDF_STATUS
osif_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc * psoc,struct sk_buff * reply_skb,struct twt_session_stats_info * params,int num_twt_session)1738 osif_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc *psoc,
1739 				    struct sk_buff *reply_skb,
1740 				    struct twt_session_stats_info *params,
1741 				    int num_twt_session)
1742 {
1743 	struct nlattr *config_attr, *nla_params;
1744 	enum wlan_twt_session_state state;
1745 	enum qca_wlan_twt_setup_state converted_state;
1746 	uint64_t tsf_val;
1747 	uint32_t wake_duration;
1748 	uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu;
1749 	int i, attr;
1750 
1751 	config_attr = nla_nest_start(reply_skb,
1752 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
1753 	if (!config_attr) {
1754 		osif_err("TWT: get_params nla_nest_start error");
1755 		return QDF_STATUS_E_INVAL;
1756 	}
1757 
1758 	for (i = 0; i < num_twt_session; i++) {
1759 		if (params[i].event_type != HOST_TWT_SESSION_SETUP &&
1760 		    params[i].event_type != HOST_TWT_SESSION_UPDATE)
1761 			continue;
1762 
1763 		nla_params = nla_nest_start(reply_skb, i);
1764 		if (!nla_params) {
1765 			osif_err("TWT: get_params nla_nest_start error");
1766 			return QDF_STATUS_E_INVAL;
1767 		}
1768 
1769 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1770 		if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
1771 			    params[i].peer_mac.bytes)) {
1772 			osif_err("TWT: get_params failed to put mac_addr");
1773 			return QDF_STATUS_E_INVAL;
1774 		}
1775 
1776 		osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT,
1777 			   QDF_MAC_ADDR_REF(params[i].peer_mac.bytes));
1778 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1779 		if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) {
1780 			osif_err("TWT: get_params failed to put dialog_id");
1781 			return QDF_STATUS_E_INVAL;
1782 		}
1783 
1784 		if (params[i].bcast) {
1785 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
1786 			if (nla_put_flag(reply_skb, attr)) {
1787 				osif_err("TWT: get_params fail to put bcast");
1788 				return QDF_STATUS_E_INVAL;
1789 			}
1790 		}
1791 
1792 		if (params[i].trig) {
1793 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
1794 			if (nla_put_flag(reply_skb, attr)) {
1795 				osif_err("TWT: get_params fail to put Trigger");
1796 				return QDF_STATUS_E_INVAL;
1797 			}
1798 		}
1799 
1800 		if (params[i].announ) {
1801 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
1802 			if (nla_put_flag(reply_skb, attr)) {
1803 				osif_err("TWT: get_params fail to put Announce");
1804 				return QDF_STATUS_E_INVAL;
1805 			}
1806 		}
1807 
1808 		if (params[i].protection) {
1809 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
1810 			if (nla_put_flag(reply_skb, attr)) {
1811 				osif_err("TWT: get_params fail to put Protect");
1812 				return QDF_STATUS_E_INVAL;
1813 			}
1814 		}
1815 
1816 		if (params[i].pm_responder_bit_valid) {
1817 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE;
1818 			if (nla_put_u8(reply_skb, attr,
1819 				       params[i].pm_responder_bit)) {
1820 				osif_err("TWT: fail to put pm responder mode");
1821 				return QDF_STATUS_E_INVAL;
1822 			}
1823 		}
1824 
1825 		if (!params[i].info_frame_disabled) {
1826 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED;
1827 			if (nla_put_flag(reply_skb, attr)) {
1828 				osif_err("TWT: get_params put Info Enable fail");
1829 				return QDF_STATUS_E_INVAL;
1830 			}
1831 		}
1832 
1833 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
1834 		wake_duration = (params[i].wake_dura_us /
1835 				TWT_WAKE_DURATION_MULTIPLICATION_FACTOR);
1836 		if (nla_put_u32(reply_skb, attr, wake_duration)) {
1837 			osif_err("TWT: get_params failed to put Wake duration");
1838 			return QDF_STATUS_E_INVAL;
1839 		}
1840 
1841 		wake_intvl_mantis_us = params[i].wake_intvl_us;
1842 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
1843 		if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_us)) {
1844 			osif_err("TWT: get_params failed to put Wake Interval in us");
1845 			return QDF_STATUS_E_INVAL;
1846 		}
1847 
1848 		wake_intvl_mantis_tu = params[i].wake_intvl_us /
1849 					TWT_WAKE_INTVL_MULTIPLICATION_FACTOR;
1850 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
1851 		if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) {
1852 			osif_err("TWT: get_params failed to put Wake Interval");
1853 			return QDF_STATUS_E_INVAL;
1854 		}
1855 
1856 		osif_debug("TWT: Send mantissa_us:%d, mantissa_tu:%d to userspace",
1857 			   wake_intvl_mantis_us, wake_intvl_mantis_tu);
1858 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
1859 		if (nla_put_u8(reply_skb, attr, 0)) {
1860 			osif_err("TWT: get_params put Wake Interval Exp failed");
1861 			return QDF_STATUS_E_INVAL;
1862 		}
1863 
1864 		tsf_val = ((uint64_t)params[i].sp_tsf_us_hi << 32) |
1865 			   params[i].sp_tsf_us_lo;
1866 		osif_debug("TWT: get_params dialog_id %d TSF = 0x%llx",
1867 			   params[i].dialog_id, tsf_val);
1868 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
1869 		if (wlan_cfg80211_nla_put_u64(reply_skb, attr, tsf_val)) {
1870 			osif_err("TWT: get_params failed to put TSF Value");
1871 			return QDF_STATUS_E_INVAL;
1872 		}
1873 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE;
1874 		state = ucfg_twt_get_session_state(psoc,
1875 				   &params[i].peer_mac,
1876 				   params[i].dialog_id);
1877 		converted_state = osif_get_converted_twt_state(state);
1878 		if (nla_put_u32(reply_skb, attr, converted_state)) {
1879 			osif_err("TWT: get_params failed to put TWT state");
1880 			return QDF_STATUS_E_INVAL;
1881 		}
1882 
1883 		nla_nest_end(reply_skb, nla_params);
1884 	}
1885 	nla_nest_end(reply_skb, config_attr);
1886 	return QDF_STATUS_SUCCESS;
1887 }
1888 
1889 static QDF_STATUS
osif_twt_send_get_params_resp(struct wlan_objmgr_vdev * vdev,struct twt_session_stats_info * params,int num_twt_session)1890 osif_twt_send_get_params_resp(struct wlan_objmgr_vdev *vdev,
1891 			      struct twt_session_stats_info *params,
1892 			      int num_twt_session)
1893 {
1894 	struct wlan_objmgr_psoc *psoc;
1895 	struct vdev_osif_priv *osif_priv;
1896 	struct sk_buff *reply_skb;
1897 	uint32_t skb_len = NLMSG_HDRLEN, i;
1898 	QDF_STATUS qdf_status;
1899 	struct wireless_dev *wdev;
1900 
1901 	psoc = wlan_vdev_get_psoc(vdev);
1902 	if (!psoc)
1903 		return QDF_STATUS_E_INVAL;
1904 
1905 	osif_priv = wlan_vdev_get_ospriv(vdev);
1906 	if (!osif_priv) {
1907 		osif_err("osif_priv is null");
1908 		return QDF_STATUS_E_INVAL;
1909 	}
1910 
1911 	wdev = osif_priv->wdev;
1912 	if (!wdev) {
1913 		osif_err("wireless dev is null");
1914 		return QDF_STATUS_E_INVAL;
1915 	}
1916 	/* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */
1917 	skb_len += NLA_HDRLEN;
1918 
1919 	/* Length of twt session parameters */
1920 	for (i = 0; i < num_twt_session; i++) {
1921 		if (params[i].event_type == HOST_TWT_SESSION_SETUP ||
1922 		    params[i].event_type == HOST_TWT_SESSION_UPDATE)
1923 			skb_len += osif_twt_get_params_resp_len(params + i);
1924 	}
1925 
1926 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy,
1927 							     skb_len);
1928 	if (!reply_skb) {
1929 		osif_err("TWT: get_params alloc reply skb failed");
1930 		return QDF_STATUS_E_NOMEM;
1931 	}
1932 
1933 	qdf_status = osif_twt_pack_get_params_resp_nlmsg(psoc, reply_skb,
1934 							 params,
1935 							 num_twt_session);
1936 	if (QDF_IS_STATUS_ERROR(qdf_status))
1937 		goto fail;
1938 
1939 	if (wlan_cfg80211_vendor_cmd_reply(reply_skb))
1940 		qdf_status = QDF_STATUS_E_INVAL;
1941 
1942 	return qdf_status;
1943 fail:
1944 	wlan_cfg80211_vendor_free_skb(reply_skb);
1945 	return qdf_status;
1946 }
1947 
1948 static QDF_STATUS
osif_twt_get_peer_session_params(struct wlan_objmgr_vdev * vdev,struct twt_session_stats_info * params)1949 osif_twt_get_peer_session_params(struct wlan_objmgr_vdev *vdev,
1950 				 struct twt_session_stats_info *params)
1951 {
1952 	struct wlan_objmgr_psoc *psoc;
1953 	int num_twt_session = 0;
1954 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
1955 
1956 	psoc = wlan_vdev_get_psoc(vdev);
1957 
1958 	if (!psoc)
1959 		return qdf_status;
1960 
1961 	num_twt_session = ucfg_cp_stats_twt_get_peer_session_params(psoc,
1962 								    params);
1963 
1964 	if (num_twt_session)
1965 		qdf_status = osif_twt_send_get_params_resp(vdev, params,
1966 							   num_twt_session);
1967 
1968 	return qdf_status;
1969 }
1970 
1971 static QDF_STATUS
osif_send_inactive_session_reply(struct wlan_objmgr_vdev * vdev,struct twt_session_stats_info * params)1972 osif_send_inactive_session_reply(struct wlan_objmgr_vdev *vdev,
1973 				 struct twt_session_stats_info *params)
1974 {
1975 	QDF_STATUS qdf_status;
1976 	int num_twt_session = 0;
1977 
1978 	params[num_twt_session].event_type = HOST_TWT_SESSION_UPDATE;
1979 	num_twt_session++;
1980 
1981 	qdf_status = osif_twt_send_get_params_resp(vdev, params,
1982 						   num_twt_session);
1983 
1984 	return qdf_status;
1985 }
1986 
1987 static int
osif_twt_sap_get_session_params(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1988 osif_twt_sap_get_session_params(struct wlan_objmgr_vdev *vdev,
1989 				struct nlattr *twt_param_attr)
1990 {
1991 	struct wlan_objmgr_psoc *psoc;
1992 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1993 	uint16_t num_peer;
1994 	struct twt_session_stats_info *params;
1995 	int ret, id, id1;
1996 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
1997 	uint8_t vdev_id;
1998 
1999 	ret = wlan_cfg80211_nla_parse_nested(
2000 			tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2001 			twt_param_attr,
2002 			qca_wlan_vendor_twt_add_dialog_policy);
2003 
2004 	if (ret)
2005 		return ret;
2006 
2007 	psoc = wlan_vdev_get_psoc(vdev);
2008 	if (!psoc)
2009 		return -EINVAL;
2010 
2011 	num_peer = wlan_vdev_get_peer_count(vdev);
2012 	params = qdf_mem_malloc(TWT_PEER_MAX_SESSIONS * num_peer *
2013 				sizeof(*params));
2014 
2015 	if (!params)
2016 		return -ENOMEM;
2017 
2018 	vdev_id = wlan_vdev_get_id(vdev);
2019 	params[0].vdev_id = vdev_id;
2020 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2021 	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
2022 
2023 	if (!tb[id] || !tb[id1]) {
2024 		osif_err_rl("TWT: get_params dialog_id or mac_addr is missing");
2025 		goto done;
2026 	}
2027 
2028 	params[0].dialog_id = nla_get_u8(tb[id]);
2029 	nla_memcpy(params[0].peer_mac.bytes, tb[id1], QDF_MAC_ADDR_SIZE);
2030 
2031 	if (qdf_is_macaddr_broadcast(&params[0].peer_mac) &&
2032 	    params[0].dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) {
2033 		osif_err_rl("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d",
2034 			TWT_ALL_SESSIONS_DIALOG_ID, params[0].dialog_id);
2035 		goto done;
2036 	}
2037 
2038 	if (!params[0].dialog_id)
2039 		params[0].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
2040 
2041 	osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT,
2042 		   params[0].dialog_id,
2043 		   QDF_MAC_ADDR_REF(params[0].peer_mac.bytes));
2044 	qdf_status = osif_twt_get_peer_session_params(vdev, params);
2045 
2046 done:
2047 	qdf_mem_free(params);
2048 	return qdf_status_to_os_return(qdf_status);
2049 }
2050 
2051 static int
osif_twt_sta_get_session_params(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2052 osif_twt_sta_get_session_params(struct wlan_objmgr_vdev *vdev,
2053 				struct nlattr *twt_param_attr)
2054 {
2055 	struct wlan_objmgr_psoc *psoc;
2056 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
2057 	struct twt_session_stats_info
2058 		params[TWT_PSOC_MAX_SESSIONS] = { {0} };
2059 	int ret, id;
2060 	QDF_STATUS qdf_status;
2061 	struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
2062 	struct qdf_mac_addr peer_mac;
2063 	uint8_t vdev_id;
2064 
2065 	ret = wlan_cfg80211_nla_parse_nested(tb,
2066 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2067 					 twt_param_attr,
2068 					 qca_wlan_vendor_twt_add_dialog_policy);
2069 	if (ret)
2070 		return ret;
2071 
2072 	psoc = wlan_vdev_get_psoc(vdev);
2073 	if (!psoc)
2074 		return -EINVAL;
2075 
2076 	vdev_id = wlan_vdev_get_id(vdev);
2077 	params[0].vdev_id = vdev_id;
2078 
2079 	/*
2080 	 * Currently twt_get_params nl cmd is sending only dialog_id(STA), fill
2081 	 * mac_addr of STA in params and call osif_twt_get_peer_session_params.
2082 	 * When twt_get_params passes mac_addr and dialog_id of STA/SAP, update
2083 	 * both mac_addr and dialog_id in params before calling
2084 	 * osif_twt_get_peer_session_params. dialog_id if not received,
2085 	 * dialog_id of value 0 will be used as default.
2086 	 */
2087 
2088 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2089 	if (tb[id])
2090 		params[0].dialog_id = (uint32_t)nla_get_u8(tb[id]);
2091 	else
2092 		params[0].dialog_id = 0;
2093 
2094 	if (osif_fill_peer_macaddr(vdev, peer_mac.bytes))
2095 		return -EINVAL;
2096 
2097 	if (params[0].dialog_id <= TWT_MAX_DIALOG_ID) {
2098 		qdf_copy_macaddr(&params[0].peer_mac, &peer_mac);
2099 		osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT,
2100 			   QDF_MAC_ADDR_REF(params[0].peer_mac.bytes));
2101 	} else {
2102 		qdf_copy_macaddr(&params[0].peer_mac, &bcast_addr);
2103 	}
2104 
2105 	if (!ucfg_twt_is_setup_done(psoc, &peer_mac,
2106 				    params[0].dialog_id)) {
2107 		osif_debug("vdev%d: TWT session %d setup incomplete", vdev_id,
2108 			   params[0].dialog_id);
2109 		qdf_status = osif_send_inactive_session_reply(vdev, params);
2110 		return qdf_status_to_os_return(qdf_status);
2111 	}
2112 
2113 	osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT,
2114 		   params[0].dialog_id,
2115 		   QDF_MAC_ADDR_REF(params[0].peer_mac.bytes));
2116 
2117 	qdf_status = osif_twt_get_peer_session_params(vdev, params);
2118 
2119 	return qdf_status_to_os_return(qdf_status);
2120 }
2121 
osif_twt_get_session_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2122 int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev,
2123 			     struct nlattr *twt_param_attr)
2124 {
2125 	enum QDF_OPMODE device_mode;
2126 
2127 	device_mode = wlan_vdev_mlme_get_opmode(vdev);
2128 
2129 	switch (device_mode) {
2130 	case QDF_STA_MODE:
2131 		return osif_twt_sta_get_session_params(vdev, twt_param_attr);
2132 	case QDF_SAP_MODE:
2133 		return osif_twt_sap_get_session_params(vdev, twt_param_attr);
2134 	default:
2135 		osif_err_rl("TWT get session params is not supported on %s",
2136 			    qdf_opmode_str(device_mode));
2137 	}
2138 
2139 	return -EOPNOTSUPP;
2140 }
2141 
2142 /**
2143  * osif_twt_request_session_traffic_stats() - Obtains twt session traffic
2144  * statistics and sends response to the user space
2145  * @vdev: vdev
2146  * @dialog_id: dialog id of the twt session
2147  * @peer_mac: Mac address of the peer
2148  *
2149  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
2150  */
2151 static QDF_STATUS
osif_twt_request_session_traffic_stats(struct wlan_objmgr_vdev * vdev,uint32_t dialog_id,uint8_t * peer_mac)2152 osif_twt_request_session_traffic_stats(struct wlan_objmgr_vdev *vdev,
2153 				       uint32_t dialog_id, uint8_t *peer_mac)
2154 {
2155 	int errno;
2156 	QDF_STATUS status = QDF_STATUS_E_INVAL;
2157 	struct infra_cp_stats_event *event;
2158 
2159 	if (!peer_mac)
2160 		return status;
2161 	event = wlan_cfg80211_mc_twt_get_infra_cp_stats(vdev, dialog_id,
2162 							peer_mac, &errno);
2163 
2164 	if (!event)
2165 		return errno;
2166 
2167 	status = osif_twt_get_stats_response(vdev, event->twt_infra_cp_stats,
2168 					     event->num_twt_infra_cp_stats);
2169 	if (QDF_IS_STATUS_ERROR(status))
2170 		osif_err("TWT: Get_traffic_stats failed status: %d", status);
2171 
2172 	qdf_mem_free(event->twt_infra_cp_stats);
2173 	qdf_mem_free(event);
2174 
2175 	return status;
2176 }
2177 
osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2178 int osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev *vdev,
2179 				       struct nlattr *twt_param_attr)
2180 {
2181 	struct wlan_objmgr_psoc *psoc;
2182 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1];
2183 	int ret, id;
2184 	QDF_STATUS qdf_status;
2185 	uint32_t dialog_id;
2186 	bool is_stats_tgt_cap_enabled;
2187 	struct qdf_mac_addr peer_mac;
2188 
2189 	psoc = wlan_vdev_get_psoc(vdev);
2190 	if (!psoc)
2191 		return -EINVAL;
2192 
2193 	ret = wlan_cfg80211_nla_parse_nested(tb,
2194 					     QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX,
2195 					     twt_param_attr,
2196 					     qca_wlan_vendor_twt_stats_dialog_policy);
2197 
2198 	if (ret)
2199 		return ret;
2200 
2201 	ucfg_twt_get_twt_stats_enabled(psoc, &is_stats_tgt_cap_enabled);
2202 	if (!is_stats_tgt_cap_enabled) {
2203 		osif_debug("TWT Stats not supported by target");
2204 		return -EOPNOTSUPP;
2205 	}
2206 
2207 	if (osif_fill_peer_macaddr(vdev, peer_mac.bytes))
2208 		return -EINVAL;
2209 
2210 	if (ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2211 					    TWT_ALL_SESSIONS_DIALOG_ID,
2212 					    WLAN_TWT_STATISTICS,
2213 					    NULL) ||
2214 	    ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2215 					    TWT_ALL_SESSIONS_DIALOG_ID,
2216 					    WLAN_TWT_CLEAR_STATISTICS,
2217 					    NULL)) {
2218 		osif_warn("Already TWT statistics or clear statistics exists");
2219 		return -EALREADY;
2220 	}
2221 
2222 	id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
2223 	if (tb[id])
2224 		dialog_id = (uint32_t)nla_get_u8(tb[id]);
2225 	else
2226 		dialog_id = 0;
2227 
2228 	osif_debug("get_stats dialog_id %d", dialog_id);
2229 	osif_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT,
2230 		   QDF_MAC_ADDR_REF(peer_mac.bytes));
2231 
2232 	if (!ucfg_twt_is_setup_done(psoc, &peer_mac, dialog_id)) {
2233 		osif_debug("TWT session %d setup incomplete", dialog_id);
2234 		return -EAGAIN;
2235 	}
2236 
2237 	ucfg_twt_set_command_in_progress(psoc, &peer_mac, dialog_id,
2238 					 WLAN_TWT_STATISTICS);
2239 
2240 	qdf_status = osif_twt_request_session_traffic_stats(vdev, dialog_id,
2241 							    peer_mac.bytes);
2242 	ucfg_twt_set_command_in_progress(psoc, &peer_mac,
2243 					 dialog_id, WLAN_TWT_NONE);
2244 
2245 	return qdf_status_to_os_return(qdf_status);
2246 }
2247 
osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2248 int osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev *vdev,
2249 					 struct nlattr *twt_param_attr)
2250 {
2251 	struct wlan_objmgr_psoc *psoc;
2252 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1];
2253 	int ret, id;
2254 	uint32_t dialog_id;
2255 	bool is_stats_tgt_cap_enabled;
2256 	QDF_STATUS status;
2257 	struct qdf_mac_addr peer_mac;
2258 
2259 	psoc = wlan_vdev_get_psoc(vdev);
2260 	if (!psoc)
2261 		return -EINVAL;
2262 
2263 	ret = wlan_cfg80211_nla_parse_nested(tb,
2264 				QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX,
2265 				twt_param_attr,
2266 				qca_wlan_vendor_twt_stats_dialog_policy);
2267 
2268 	if (ret)
2269 		return ret;
2270 
2271 	ucfg_twt_get_twt_stats_enabled(psoc, &is_stats_tgt_cap_enabled);
2272 	if (!is_stats_tgt_cap_enabled) {
2273 		osif_debug("TWT Stats not supported by target");
2274 		return -EOPNOTSUPP;
2275 	}
2276 
2277 	id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
2278 	if (!tb[id]) {
2279 		osif_err_rl("TWT Clear stats - dialog id param is must");
2280 		return -EINVAL;
2281 	}
2282 
2283 	if (osif_fill_peer_macaddr(vdev, peer_mac.bytes))
2284 		return -EINVAL;
2285 
2286 	dialog_id = (uint32_t)nla_get_u8(tb[id]);
2287 	osif_debug("dialog_id %d peer mac_addr "QDF_MAC_ADDR_FMT,
2288 		   dialog_id, QDF_MAC_ADDR_REF(peer_mac.bytes));
2289 
2290 	status = ucfg_twt_check_all_twt_support(psoc, dialog_id);
2291 	if (QDF_IS_STATUS_ERROR(status)) {
2292 		osif_debug("All TWT sessions not supported by target");
2293 		return -EOPNOTSUPP;
2294 	}
2295 
2296 	if (ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2297 					    TWT_ALL_SESSIONS_DIALOG_ID,
2298 					    WLAN_TWT_STATISTICS, NULL) ||
2299 	    ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2300 					    TWT_ALL_SESSIONS_DIALOG_ID,
2301 					    WLAN_TWT_CLEAR_STATISTICS,
2302 					    NULL)) {
2303 		osif_warn("Already TWT statistics or clear statistics exists");
2304 		return -EALREADY;
2305 	}
2306 
2307 	if (!ucfg_twt_is_setup_done(psoc, &peer_mac, dialog_id)) {
2308 		osif_debug("TWT session %d setup incomplete", dialog_id);
2309 		return -EAGAIN;
2310 	}
2311 
2312 	ret = wlan_cfg80211_mc_twt_clear_infra_cp_stats(vdev, dialog_id,
2313 							peer_mac.bytes);
2314 
2315 	return ret;
2316 }
2317 
2318 /**
2319  * osif_twt_convert_ac_value() - map ac setting to the value to be used in FW.
2320  * @ac_value: ac value to be mapped.
2321  *
2322  * Return: enum twt_traffic_ac
2323  */
2324 static inline
osif_twt_convert_ac_value(enum qca_wlan_ac_type ac_value)2325 enum twt_traffic_ac osif_twt_convert_ac_value(enum qca_wlan_ac_type ac_value)
2326 {
2327 	switch (ac_value) {
2328 	case QCA_WLAN_AC_BE:
2329 		return TWT_AC_BE;
2330 	case QCA_WLAN_AC_BK:
2331 		return TWT_AC_BK;
2332 	case QCA_WLAN_AC_VI:
2333 		return TWT_AC_VI;
2334 	case QCA_WLAN_AC_VO:
2335 		return TWT_AC_VO;
2336 	case QCA_WLAN_AC_ALL:
2337 		return TWT_AC_MAX;
2338 	}
2339 	osif_err("invalid enum: %u", ac_value);
2340 	return TWT_AC_MAX;
2341 }
2342 
2343 /**
2344  * osif_twt_add_ac_config() - pdev TWT param send
2345  * @vdev: Pointer to vdev object
2346  * @twt_ac: TWT access category
2347  *
2348  * Return: QDF Status
2349  */
osif_twt_add_ac_config(struct wlan_objmgr_vdev * vdev,enum qca_wlan_ac_type twt_ac)2350 static int osif_twt_add_ac_config(struct wlan_objmgr_vdev *vdev,
2351 				  enum qca_wlan_ac_type twt_ac)
2352 {
2353 	bool is_responder_en;
2354 	int ret = 0;
2355 	struct wlan_objmgr_psoc *psoc;
2356 	enum QDF_OPMODE device_mode;
2357 
2358 	psoc = wlan_vdev_get_psoc(vdev);
2359 	if (!psoc)
2360 		return -EINVAL;
2361 
2362 	device_mode = wlan_vdev_mlme_get_opmode(vdev);
2363 
2364 	if (twt_ac < QCA_WLAN_AC_BE || twt_ac > QCA_WLAN_AC_VO) {
2365 		osif_err_rl("Invalid AC parameter. Value: %d", twt_ac);
2366 		return -EINVAL;
2367 	}
2368 
2369 	ucfg_twt_cfg_get_responder(psoc, &is_responder_en);
2370 
2371 	if (device_mode == QDF_SAP_MODE && is_responder_en) {
2372 		ret = ucfg_twt_ac_pdev_param_send(psoc,
2373 						  osif_twt_convert_ac_value(twt_ac));
2374 	} else {
2375 		osif_err_rl("Undesired device mode. Mode: %d and responder: %d",
2376 			    device_mode, is_responder_en);
2377 		return -EINVAL;
2378 	}
2379 
2380 	return ret;
2381 }
2382 
osif_twt_set_param(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2383 int osif_twt_set_param(struct wlan_objmgr_vdev *vdev,
2384 		       struct nlattr *twt_param_attr)
2385 {
2386 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1];
2387 	int ret;
2388 	int cmd_id;
2389 	enum qca_wlan_ac_type twt_ac;
2390 
2391 	ret = wlan_cfg80211_nla_parse_nested
2392 					(tb,
2393 					 QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX,
2394 					 twt_param_attr,
2395 					 qca_wlan_vendor_twt_set_param_policy);
2396 	if (ret)
2397 		return ret;
2398 
2399 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE;
2400 
2401 	if (tb[cmd_id]) {
2402 		twt_ac = nla_get_u8(tb[cmd_id]);
2403 		osif_debug("TWT_AC_CONFIG_VALUE: %d", twt_ac);
2404 		ret = osif_twt_add_ac_config(vdev, twt_ac);
2405 
2406 		if (ret) {
2407 			osif_err("Fail to set TWT AC parameter, errno %d",
2408 				 ret);
2409 			return ret;
2410 		}
2411 	}
2412 
2413 	return ret;
2414 }
2415 
osif_twt_teardown_req_retry(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_del_dialog_param params)2416 static void osif_twt_teardown_req_retry(struct wlan_objmgr_vdev *vdev,
2417 					struct wlan_objmgr_psoc *psoc,
2418 					struct twt_del_dialog_param params)
2419 {
2420 	int retries = 1;
2421 	int ret;
2422 
2423 	while (retries < TWT_DEL_DIALOG_REQ_MAX_RETRY) {
2424 		qdf_sleep(TWT_TEARDOWN_IN_PS_DISABLE_WAIT_TIME);
2425 		osif_debug("Implicitly TWT teardown req retry count:%d", retries);
2426 		ret = osif_send_sta_twt_teardown_req(vdev, psoc, &params);
2427 		if (ret != -EBUSY)
2428 			break;
2429 		retries++;
2430 	}
2431 
2432 	if (retries >= TWT_DEL_DIALOG_REQ_MAX_RETRY)
2433 		osif_debug("TWT Del Dialog req max retries reached");
2434 }
2435 
__osif_twt_work_handler(struct wlan_objmgr_vdev * vdev)2436 void __osif_twt_work_handler(struct wlan_objmgr_vdev *vdev)
2437 {
2438 	struct twt_del_dialog_param params = {0};
2439 	struct twt_work_params twt_work_params = {0};
2440 	struct wlan_objmgr_psoc *psoc;
2441 	uint8_t vdev_id;
2442 	uint32_t next_action;
2443 	int ret;
2444 
2445 	psoc = wlan_vdev_get_psoc(vdev);
2446 	if (!psoc) {
2447 		osif_err("psoc is null");
2448 		return;
2449 	}
2450 
2451 	vdev_id = wlan_vdev_get_id(vdev);
2452 	ucfg_twt_get_work_params(vdev, &twt_work_params, &next_action);
2453 
2454 	if (next_action != HOST_TWT_SEND_DELETE_CMD) {
2455 		osif_debug("Do not send STA teardown req as TWT renegotiation or power save work is not scheduled");
2456 		return;
2457 	}
2458 
2459 	qdf_copy_macaddr(&params.peer_macaddr, &twt_work_params.peer_macaddr);
2460 	params.dialog_id = twt_work_params.dialog_id;
2461 	params.vdev_id = vdev_id;
2462 
2463 	ret = osif_send_sta_twt_teardown_req(vdev, psoc, &params);
2464 
2465 	/*
2466 	 * In case of FW returns ack_event with status as scan_in_progress or
2467 	 * Channel switch in progress and TWT teardown happens due to power
2468 	 * save disable then host will retry the TWT teardown cmd.
2469 	 */
2470 	if (ret == -EBUSY && twt_work_params.is_ps_disabled)
2471 		osif_twt_teardown_req_retry(vdev, psoc, params);
2472 }
2473 
osif_twt_work_handler(void * data)2474 void osif_twt_work_handler(void *data)
2475 {
2476 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)data;
2477 	struct net_device *net_dev;
2478 	struct osif_vdev_sync *vdev_sync;
2479 	struct vdev_osif_priv *priv;
2480 	int errno;
2481 
2482 	if (!vdev) {
2483 		osif_err("vdev is null");
2484 		return;
2485 	}
2486 
2487 	priv = wlan_vdev_get_ospriv(vdev);
2488 	if (!priv || !priv->wdev || !priv->wdev->netdev)
2489 		return;
2490 
2491 	net_dev = priv->wdev->netdev;
2492 	errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
2493 	if (errno)
2494 		return;
2495 
2496 	__osif_twt_work_handler(vdev);
2497 
2498 	osif_vdev_sync_op_stop(vdev_sync);
2499 }
2500 
osif_twt_create_work(struct wlan_objmgr_vdev * vdev)2501 QDF_STATUS osif_twt_create_work(struct wlan_objmgr_vdev *vdev)
2502 {
2503 	qdf_create_work(0, &vdev->twt_work,
2504 			osif_twt_work_handler, vdev);
2505 
2506 	return QDF_STATUS_SUCCESS;
2507 }
2508 
osif_twt_destroy_work(struct wlan_objmgr_vdev * vdev)2509 QDF_STATUS osif_twt_destroy_work(struct wlan_objmgr_vdev *vdev)
2510 {
2511 	qdf_flush_work(&vdev->twt_work);
2512 	qdf_destroy_work(NULL, &vdev->twt_work);
2513 
2514 	return QDF_STATUS_SUCCESS;
2515 }
2516