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