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