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: wlan_twt_common.c
19 */
20 #include "include/wlan_mlme_cmn.h"
21 #include "wlan_twt_common.h"
22 #include "wlan_twt_priv.h"
23 #include <wlan_twt_public_structs.h>
24 #include <wlan_objmgr_peer_obj.h>
25 #include <wlan_twt_tgt_if_tx_api.h>
26 #include "twt/core/src/wlan_twt_cfg.h"
27
28 QDF_STATUS
wlan_twt_tgt_caps_get_responder(struct wlan_objmgr_psoc * psoc,bool * val)29 wlan_twt_tgt_caps_get_responder(struct wlan_objmgr_psoc *psoc, bool *val)
30 {
31 struct twt_psoc_priv_obj *twt_psoc;
32
33 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
34 WLAN_UMAC_COMP_TWT);
35 if (!twt_psoc) {
36 twt_err("null twt psoc priv obj");
37 return QDF_STATUS_E_FAILURE;
38 }
39
40 *val = twt_psoc->twt_caps.twt_responder;
41 return QDF_STATUS_SUCCESS;
42 }
43
44 QDF_STATUS
wlan_twt_tgt_caps_get_nudge_enabled(struct wlan_objmgr_psoc * psoc,bool * val)45 wlan_twt_tgt_caps_get_nudge_enabled(struct wlan_objmgr_psoc *psoc,
46 bool *val)
47 {
48 struct twt_psoc_priv_obj *twt_psoc;
49
50 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
51 WLAN_UMAC_COMP_TWT);
52 if (!twt_psoc) {
53 twt_err("null twt psoc priv obj");
54 return QDF_STATUS_E_FAILURE;
55 }
56
57 *val = twt_psoc->twt_caps.twt_nudge_enabled;
58 return QDF_STATUS_SUCCESS;
59 }
60
61 QDF_STATUS
wlan_twt_tgt_caps_get_all_twt_enabled(struct wlan_objmgr_psoc * psoc,bool * val)62 wlan_twt_tgt_caps_get_all_twt_enabled(struct wlan_objmgr_psoc *psoc,
63 bool *val)
64 {
65 struct twt_psoc_priv_obj *twt_psoc;
66
67 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
68 WLAN_UMAC_COMP_TWT);
69 if (!twt_psoc) {
70 twt_err("null twt psoc priv obj");
71 return QDF_STATUS_E_FAILURE;
72 }
73
74 *val = twt_psoc->twt_caps.all_twt_enabled;
75 return QDF_STATUS_SUCCESS;
76 }
77
78 QDF_STATUS
wlan_twt_tgt_caps_get_stats_enabled(struct wlan_objmgr_psoc * psoc,bool * val)79 wlan_twt_tgt_caps_get_stats_enabled(struct wlan_objmgr_psoc *psoc,
80 bool *val)
81 {
82 struct twt_psoc_priv_obj *twt_psoc;
83
84 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
85 WLAN_UMAC_COMP_TWT);
86 if (!twt_psoc) {
87 twt_err("null twt psoc priv obj");
88 return QDF_STATUS_E_FAILURE;
89 }
90
91 *val = twt_psoc->twt_caps.twt_stats_enabled;
92 return QDF_STATUS_SUCCESS;
93 }
94
wlan_twt_check_all_twt_support(struct wlan_objmgr_psoc * psoc,uint32_t dialog_id)95 QDF_STATUS wlan_twt_check_all_twt_support(struct wlan_objmgr_psoc *psoc,
96 uint32_t dialog_id)
97 {
98 bool is_all_twt_enabled = false;
99 QDF_STATUS status;
100
101 /* Cap check is check NOT required if id is for a single session */
102 if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)
103 return QDF_STATUS_SUCCESS;
104
105 status = wlan_twt_tgt_caps_get_all_twt_enabled(psoc,
106 &is_all_twt_enabled);
107 if (QDF_IS_STATUS_ERROR(status))
108 return QDF_STATUS_E_INVAL;
109
110 if (!is_all_twt_enabled)
111 return QDF_STATUS_E_NOSUPPORT;
112
113 return QDF_STATUS_SUCCESS;
114 }
115
116 QDF_STATUS
wlan_twt_tgt_caps_get_ack_supported(struct wlan_objmgr_psoc * psoc,bool * val)117 wlan_twt_tgt_caps_get_ack_supported(struct wlan_objmgr_psoc *psoc,
118 bool *val)
119 {
120 struct twt_psoc_priv_obj *twt_psoc;
121
122 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
123 WLAN_UMAC_COMP_TWT);
124 if (!twt_psoc) {
125 twt_err("null twt psoc priv obj");
126 *val = false;
127 return QDF_STATUS_E_FAILURE;
128 }
129
130 *val = twt_psoc->twt_caps.twt_ack_supported;
131 return QDF_STATUS_SUCCESS;
132 }
133
134 QDF_STATUS
wlan_twt_tgt_caps_get_restricted_support(struct wlan_objmgr_psoc * psoc,bool * val)135 wlan_twt_tgt_caps_get_restricted_support(struct wlan_objmgr_psoc *psoc,
136 bool *val)
137 {
138 struct twt_psoc_priv_obj *twt_psoc;
139
140 if (!psoc) {
141 twt_err("null psoc");
142 return QDF_STATUS_E_FAILURE;
143 }
144
145 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
146 WLAN_UMAC_COMP_TWT);
147 if (!twt_psoc) {
148 twt_err("null twt psoc priv obj");
149 return QDF_STATUS_E_FAILURE;
150 }
151
152 *val = twt_psoc->twt_caps.restricted_twt_support;
153 return QDF_STATUS_SUCCESS;
154 }
155
156 QDF_STATUS
wlan_twt_requestor_disable(struct wlan_objmgr_psoc * psoc,struct twt_disable_param * req,void * context)157 wlan_twt_requestor_disable(struct wlan_objmgr_psoc *psoc,
158 struct twt_disable_param *req,
159 void *context)
160 {
161 struct twt_psoc_priv_obj *twt_psoc;
162
163 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
164 WLAN_UMAC_COMP_TWT);
165 if (!twt_psoc) {
166 twt_err("null twt psoc priv obj");
167 return QDF_STATUS_E_FAILURE;
168 }
169
170 twt_psoc->disable_context.twt_role = TWT_ROLE_REQUESTOR;
171 twt_psoc->disable_context.context = context;
172
173 req->twt_role = TWT_ROLE_REQUESTOR;
174
175 twt_debug("TWT req disable: pdev_id:%d role:%d ext:%d reason_code:%d",
176 req->pdev_id, req->twt_role, req->ext_conf_present,
177 req->dis_reason_code);
178
179 return tgt_twt_disable_req_send(psoc, req);
180 }
181
182 QDF_STATUS
wlan_twt_responder_disable(struct wlan_objmgr_psoc * psoc,struct twt_disable_param * req,void * context)183 wlan_twt_responder_disable(struct wlan_objmgr_psoc *psoc,
184 struct twt_disable_param *req,
185 void *context)
186 {
187 struct twt_psoc_priv_obj *twt_psoc;
188
189 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
190 WLAN_UMAC_COMP_TWT);
191 if (!twt_psoc) {
192 twt_err("null twt psoc priv obj");
193 return QDF_STATUS_E_FAILURE;
194 }
195
196 twt_psoc->disable_context.twt_role = TWT_ROLE_RESPONDER;
197 twt_psoc->disable_context.context = context;
198
199 req->twt_role = TWT_ROLE_RESPONDER;
200
201 twt_debug("TWT res disable: pdev_id:%d role:%d ext:%d reason_code:%d",
202 req->pdev_id, req->twt_role, req->ext_conf_present,
203 req->dis_reason_code);
204
205 return tgt_twt_disable_req_send(psoc, req);
206 }
207
208 QDF_STATUS
wlan_twt_requestor_enable(struct wlan_objmgr_psoc * psoc,struct twt_enable_param * req,void * context)209 wlan_twt_requestor_enable(struct wlan_objmgr_psoc *psoc,
210 struct twt_enable_param *req,
211 void *context)
212 {
213 struct twt_psoc_priv_obj *twt_psoc;
214 bool requestor_en = false, twt_bcast_requestor = false;
215 bool rtwt_requestor = false, restricted_support = false;
216
217 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
218 WLAN_UMAC_COMP_TWT);
219 if (!twt_psoc) {
220 twt_err("null twt psoc priv obj");
221 return QDF_STATUS_E_FAILURE;
222 }
223
224 wlan_twt_cfg_get_requestor(psoc, &requestor_en);
225 if (!requestor_en) {
226 twt_warn("twt requestor ini is not enabled");
227 return QDF_STATUS_E_FAILURE;
228 }
229
230 twt_psoc->enable_context.twt_role = TWT_ROLE_REQUESTOR;
231 twt_psoc->enable_context.context = context;
232
233 wlan_twt_cfg_get_congestion_timeout(psoc, &req->sta_cong_timer_ms);
234 wlan_twt_cfg_get_bcast_requestor(psoc, &twt_bcast_requestor);
235 req->b_twt_enable = twt_bcast_requestor;
236 req->twt_role = TWT_ROLE_REQUESTOR;
237 if (twt_bcast_requestor)
238 req->twt_oper = TWT_OPERATION_BROADCAST;
239 else
240 req->twt_oper = TWT_OPERATION_INDIVIDUAL;
241
242 wlan_twt_cfg_get_rtwt_requestor(psoc, &rtwt_requestor);
243 wlan_twt_tgt_caps_get_restricted_support(psoc, &restricted_support);
244
245 req->r_twt_enable = QDF_MIN(restricted_support, rtwt_requestor);
246
247 twt_debug("TWT req enable: pdev_id:%d cong:%d bcast:%d rtwt:%d",
248 req->pdev_id, req->sta_cong_timer_ms, req->b_twt_enable,
249 req->r_twt_enable);
250 twt_debug("TWT req enable: role:%d ext:%d oper:%d",
251 req->twt_role, req->ext_conf_present, req->twt_oper);
252
253 return tgt_twt_enable_req_send(psoc, req);
254 }
255
256 QDF_STATUS
wlan_twt_responder_enable(struct wlan_objmgr_psoc * psoc,struct twt_enable_param * req,void * context)257 wlan_twt_responder_enable(struct wlan_objmgr_psoc *psoc,
258 struct twt_enable_param *req,
259 void *context)
260 {
261 struct twt_psoc_priv_obj *twt_psoc;
262 bool responder_en = false, twt_bcast_responder = false;
263
264 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
265 WLAN_UMAC_COMP_TWT);
266 if (!twt_psoc) {
267 twt_err("null twt psoc priv obj");
268 return QDF_STATUS_E_FAILURE;
269 }
270
271 wlan_twt_cfg_get_responder(psoc, &responder_en);
272 if (!responder_en) {
273 twt_warn("twt responder ini is not enabled");
274 return QDF_STATUS_E_FAILURE;
275 }
276
277 twt_psoc->enable_context.twt_role = TWT_ROLE_RESPONDER;
278 twt_psoc->enable_context.context = context;
279
280 wlan_twt_cfg_get_bcast_responder(psoc, &twt_bcast_responder);
281 req->b_twt_enable = twt_bcast_responder;
282 req->twt_role = TWT_ROLE_RESPONDER;
283 if (twt_bcast_responder)
284 req->twt_oper = TWT_OPERATION_BROADCAST;
285 else
286 req->twt_oper = TWT_OPERATION_INDIVIDUAL;
287
288 twt_debug("TWT res enable: pdev_id:%d bcast:%d",
289 req->pdev_id, req->b_twt_enable);
290 twt_debug("TWT res enable: role:%d ext:%d oper:%d",
291 req->twt_role, req->ext_conf_present, req->twt_oper);
292
293 return tgt_twt_enable_req_send(psoc, req);
294 }
295
296 QDF_STATUS
wlan_twt_set_peer_capabilities(struct wlan_objmgr_psoc * psoc,struct qdf_mac_addr * peer_mac,uint8_t peer_cap)297 wlan_twt_set_peer_capabilities(struct wlan_objmgr_psoc *psoc,
298 struct qdf_mac_addr *peer_mac,
299 uint8_t peer_cap)
300 {
301 struct twt_peer_priv_obj *peer_priv;
302 struct wlan_objmgr_peer *peer;
303
304 peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
305 WLAN_TWT_ID);
306 if (!peer) {
307 twt_debug("Peer object not found " QDF_MAC_ADDR_FMT,
308 QDF_MAC_ADDR_REF(peer_mac->bytes));
309 return QDF_STATUS_E_FAILURE;
310 }
311
312 peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
313 WLAN_UMAC_COMP_TWT);
314 if (!peer_priv) {
315 wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
316 twt_err("peer twt component object is NULL");
317 return QDF_STATUS_E_FAILURE;
318 }
319
320 twt_lock_acquire(&peer_priv->twt_peer_lock);
321 peer_priv->peer_capability = peer_cap;
322 twt_lock_release(&peer_priv->twt_peer_lock);
323
324 twt_debug("set peer cap: 0x%x", peer_cap);
325 wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
326 return QDF_STATUS_SUCCESS;
327 }
328
329 QDF_STATUS
wlan_twt_get_peer_capabilities(struct wlan_objmgr_psoc * psoc,struct qdf_mac_addr * peer_mac,uint8_t * peer_cap)330 wlan_twt_get_peer_capabilities(struct wlan_objmgr_psoc *psoc,
331 struct qdf_mac_addr *peer_mac,
332 uint8_t *peer_cap)
333 {
334 struct twt_peer_priv_obj *peer_priv;
335 struct wlan_objmgr_peer *peer;
336
337 peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
338 WLAN_TWT_ID);
339 if (!peer) {
340 twt_err("Peer object not found "QDF_MAC_ADDR_FMT,
341 QDF_MAC_ADDR_REF(peer_mac->bytes));
342 *peer_cap = 0;
343 return QDF_STATUS_E_FAILURE;
344 }
345
346 peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
347 WLAN_UMAC_COMP_TWT);
348 if (!peer_priv) {
349 wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
350 *peer_cap = 0;
351 twt_err("peer twt component object is NULL");
352 return QDF_STATUS_E_FAILURE;
353 }
354
355 twt_lock_acquire(&peer_priv->twt_peer_lock);
356 *peer_cap = peer_priv->peer_capability;
357 twt_lock_release(&peer_priv->twt_peer_lock);
358
359 twt_debug("get peer cap: 0x%x", *peer_cap);
360 wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
361 return QDF_STATUS_SUCCESS;
362 }
363
364 QDF_STATUS
wlan_twt_enable_event_handler(struct wlan_objmgr_psoc * psoc,struct twt_enable_complete_event_param * event)365 wlan_twt_enable_event_handler(struct wlan_objmgr_psoc *psoc,
366 struct twt_enable_complete_event_param *event)
367 {
368 struct twt_psoc_priv_obj *twt_psoc;
369 struct twt_en_dis_context *twt_context;
370
371 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
372 WLAN_UMAC_COMP_TWT);
373 if (!twt_psoc) {
374 twt_err("null twt psoc priv obj");
375 return QDF_STATUS_E_FAILURE;
376 }
377
378 twt_context = &twt_psoc->enable_context;
379
380 twt_debug("pdev_id:%d status:%d twt_role:%d",
381 event->pdev_id, event->status, twt_context->twt_role);
382 switch (event->status) {
383 case HOST_TWT_ENABLE_STATUS_OK:
384 case HOST_TWT_ENABLE_STATUS_ALREADY_ENABLED:
385 if (twt_context->twt_role == TWT_ROLE_REQUESTOR)
386 wlan_twt_cfg_set_requestor_flag(psoc, true);
387 else if (twt_context->twt_role == TWT_ROLE_RESPONDER)
388 wlan_twt_cfg_set_responder_flag(psoc, true);
389 else
390 twt_err("Invalid role:%d", twt_context->twt_role);
391
392 break;
393
394 default:
395 twt_err("twt enable status:%d", event->status);
396 break;
397 }
398
399 return mlme_twt_osif_enable_complete_ind(psoc, event,
400 twt_context->context);
401 }
402
403 QDF_STATUS
wlan_twt_disable_event_handler(struct wlan_objmgr_psoc * psoc,struct twt_disable_complete_event_param * event)404 wlan_twt_disable_event_handler(struct wlan_objmgr_psoc *psoc,
405 struct twt_disable_complete_event_param *event)
406 {
407 struct twt_psoc_priv_obj *twt_psoc;
408 struct twt_en_dis_context *twt_context;
409
410 twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
411 WLAN_UMAC_COMP_TWT);
412 if (!twt_psoc) {
413 twt_err("null twt psoc priv obj");
414 return QDF_STATUS_E_FAILURE;
415 }
416
417 twt_context = &twt_psoc->disable_context;
418
419 twt_debug("pdev_id:%d status:%d twt_role:%d",
420 event->pdev_id, event->status, twt_context->twt_role);
421 switch (event->status) {
422 case HOST_TWT_DISABLE_STATUS_OK:
423 if (twt_context->twt_role == TWT_ROLE_REQUESTOR)
424 wlan_twt_cfg_set_requestor_flag(psoc, false);
425 else if (twt_context->twt_role == TWT_ROLE_RESPONDER)
426 wlan_twt_cfg_set_responder_flag(psoc, false);
427 else
428 twt_err("Invalid role:%d", twt_context->twt_role);
429
430 break;
431
432 default:
433 twt_err("twt disable status:%d", event->status);
434 break;
435 }
436
437 return mlme_twt_osif_disable_complete_ind(psoc, event,
438 twt_context->context);
439 }
440
441