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 ¶ms->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, ¶ms);
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(¶ms));
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(¶ms));
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 ¶ms[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 ¶ms[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, ¶ms);
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 ¶ms->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(¶ms);
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, ¶ms);
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, ¶ms);
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(¶ms, 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, ¶ms);
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(¶ms);
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, ¶ms);
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, ¶ms);
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(¶ms);
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, ¶ms);
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(¶ms);
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, ¶ms);
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(¶ms);
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, ¶ms);
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 ¶ms);
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 ¶ms[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, ¶ms);
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