1 /*
2 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /**
18 * DOC: osif_twt_ext_rsp.c
19 *
20 */
21 #include <wlan_cfg80211.h>
22 #include <osif_twt_ext_req.h>
23 #include <osif_twt_rsp.h>
24 #include <osif_twt_ext_rsp.h>
25 #include <wlan_objmgr_psoc_obj.h>
26 #include <wlan_osif_priv.h>
27 #include <wlan_osif_request_manager.h>
28 #include <wlan_cm_api.h>
29 #include <wlan_twt_ucfg_api.h>
30 #include <wlan_cm_ucfg_api.h>
31 #include <wlan_reg_ucfg_api.h>
32 #include <wlan_twt_ucfg_ext_api.h>
33 #include <wlan_twt_ucfg_ext_cfg.h>
34 #include <wlan_cp_stats_ucfg_api.h>
35
36 /**
37 * osif_twt_get_setup_event_len() - Calculates the length of twt
38 * setup nl response
39 * @additional_params_present: if true, then length required for
40 * fixed and additional parameters is returned. if false,
41 * then length required for fixed parameters is returned.
42 *
43 * Return: Length of twt setup nl response
44 */
45 static
osif_twt_get_setup_event_len(bool additional_params_present)46 uint32_t osif_twt_get_setup_event_len(bool additional_params_present)
47 {
48 uint32_t len = 0;
49
50 len += NLMSG_HDRLEN;
51
52 /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */
53 len += NLA_HDRLEN;
54
55 /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */
56 len += nla_total_size(sizeof(u8));
57
58 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
59 len += nla_total_size(sizeof(u8));
60 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
61 len += nla_total_size(sizeof(u8));
62
63 if (!additional_params_present)
64 return len;
65
66 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE */
67 len += nla_total_size(sizeof(u8));
68 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE*/
69 len += nla_total_size(sizeof(u8));
70 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION*/
71 len += nla_total_size(sizeof(u32));
72 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA*/
73 len += nla_total_size(sizeof(u32));
74 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/
75 len += nla_total_size(sizeof(u8));
76 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF*/
77 len += nla_total_size(sizeof(u64));
78 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME*/
79 len += nla_total_size(sizeof(u32));
80 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER*/
81 len += nla_total_size(sizeof(u8));
82 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION*/
83 len += nla_total_size(sizeof(u8));
84 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST*/
85 len += nla_total_size(sizeof(u8));
86 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED*/
87 len += nla_total_size(sizeof(u8));
88 /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
89 len += nla_total_size(QDF_MAC_ADDR_SIZE);
90
91 return len;
92 }
93
94 /**
95 * osif_twt_get_event_len() - calculate length of skb
96 * required for sending twt terminate, pause and resume
97 * command responses.
98 *
99 * Return: length of skb
100 */
osif_twt_get_event_len(void)101 static uint32_t osif_twt_get_event_len(void)
102 {
103 uint32_t len = 0;
104
105 len += NLMSG_HDRLEN;
106 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
107 len += nla_total_size(sizeof(u8));
108 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
109 len += nla_total_size(sizeof(u8));
110 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
111 len += nla_total_size(QDF_MAC_ADDR_SIZE);
112
113 return len;
114 }
115
116 /**
117 * twt_add_status_to_vendor_twt_status() - convert from
118 * HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status
119 * @status: HOST_ADD_TWT_STATUS value from firmware
120 *
121 * Return: qca_wlan_vendor_twt_status values corresponding
122 * to HOST_ADD_TWT_STATUS.
123 */
124 static enum qca_wlan_vendor_twt_status
twt_add_status_to_vendor_twt_status(enum HOST_ADD_TWT_STATUS status)125 twt_add_status_to_vendor_twt_status(enum HOST_ADD_TWT_STATUS status)
126 {
127 switch (status) {
128 case HOST_ADD_TWT_STATUS_OK:
129 return QCA_WLAN_VENDOR_TWT_STATUS_OK;
130 case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
131 return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED;
132 case HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
133 return QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID;
134 case HOST_ADD_TWT_STATUS_INVALID_PARAM:
135 return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
136 case HOST_ADD_TWT_STATUS_NOT_READY:
137 return QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY;
138 case HOST_ADD_TWT_STATUS_NO_RESOURCE:
139 return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
140 case HOST_ADD_TWT_STATUS_NO_ACK:
141 return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
142 case HOST_ADD_TWT_STATUS_NO_RESPONSE:
143 return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE;
144 case HOST_ADD_TWT_STATUS_DENIED:
145 return QCA_WLAN_VENDOR_TWT_STATUS_DENIED;
146 case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
147 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
148 case HOST_ADD_TWT_STATUS_AP_PARAMS_NOT_IN_RANGE:
149 return QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE;
150 case HOST_ADD_TWT_STATUS_AP_IE_VALIDATION_FAILED:
151 return QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID;
152 case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
153 return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
154 case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
155 return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
156 case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
157 return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
158 default:
159 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
160 }
161 }
162
163 /**
164 * twt_del_status_to_vendor_twt_status() - convert from
165 * HOST_DEL_TWT_STATUS to qca_wlan_vendor_twt_status
166 * @status: HOST_DEL_TWT_STATUS value from firmware
167 *
168 * Return: qca_wlan_vendor_twt_status values corresponding
169 * to HOST_DEL_TWT_STATUS.
170 */
171 static enum qca_wlan_vendor_twt_status
twt_del_status_to_vendor_twt_status(enum HOST_TWT_DEL_STATUS status)172 twt_del_status_to_vendor_twt_status(enum HOST_TWT_DEL_STATUS status)
173 {
174 switch (status) {
175 case HOST_TWT_DEL_STATUS_OK:
176 return QCA_WLAN_VENDOR_TWT_STATUS_OK;
177 case HOST_TWT_DEL_STATUS_DIALOG_ID_NOT_EXIST:
178 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
179 case HOST_TWT_DEL_STATUS_INVALID_PARAM:
180 return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
181 case HOST_TWT_DEL_STATUS_DIALOG_ID_BUSY:
182 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
183 case HOST_TWT_DEL_STATUS_NO_RESOURCE:
184 return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
185 case HOST_TWT_DEL_STATUS_NO_ACK:
186 return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
187 case HOST_TWT_DEL_STATUS_UNKNOWN_ERROR:
188 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
189 case HOST_TWT_DEL_STATUS_PEER_INIT_TEARDOWN:
190 return QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE;
191 case HOST_TWT_DEL_STATUS_ROAMING:
192 return QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE;
193 case HOST_TWT_DEL_STATUS_CONCURRENCY:
194 return QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE;
195 case HOST_TWT_DEL_STATUS_CHAN_SW_IN_PROGRESS:
196 return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
197 case HOST_TWT_DEL_STATUS_SCAN_IN_PROGRESS:
198 return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
199 case HOST_TWT_DEL_STATUS_PS_DISABLE_TEARDOWN:
200 return QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE;
201 default:
202 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
203 }
204 }
205
206 /**
207 * twt_resume_status_to_vendor_twt_status() - convert from
208 * HOST_TWT_RESUME_STATUS to qca_wlan_vendor_twt_status
209 * @status: HOST_TWT_RESUME_STATUS value from firmware
210 *
211 * Return: qca_wlan_vendor_twt_status values corresponding
212 * to the firmware failure status
213 */
214 static int
twt_resume_status_to_vendor_twt_status(enum HOST_TWT_RESUME_STATUS status)215 twt_resume_status_to_vendor_twt_status(enum HOST_TWT_RESUME_STATUS status)
216 {
217 switch (status) {
218 case HOST_TWT_RESUME_STATUS_OK:
219 return QCA_WLAN_VENDOR_TWT_STATUS_OK;
220 case HOST_TWT_RESUME_STATUS_DIALOG_ID_NOT_EXIST:
221 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
222 case HOST_TWT_RESUME_STATUS_INVALID_PARAM:
223 return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
224 case HOST_TWT_RESUME_STATUS_DIALOG_ID_BUSY:
225 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
226 case HOST_TWT_RESUME_STATUS_NOT_PAUSED:
227 return QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED;
228 case HOST_TWT_RESUME_STATUS_NO_RESOURCE:
229 return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
230 case HOST_TWT_RESUME_STATUS_NO_ACK:
231 return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
232 case HOST_TWT_RESUME_STATUS_UNKNOWN_ERROR:
233 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
234 case HOST_TWT_RESUME_STATUS_CHAN_SW_IN_PROGRESS:
235 return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
236 case HOST_TWT_RESUME_STATUS_ROAM_IN_PROGRESS:
237 return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
238 case HOST_TWT_RESUME_STATUS_SCAN_IN_PROGRESS:
239 return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS;
240 default:
241 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
242 }
243 }
244
245 /**
246 * twt_nudge_status_to_vendor_twt_status() - convert from
247 * HOST_TWT_NUDGE_STATUS to qca_wlan_vendor_twt_status
248 * @status: HOST_TWT_NUDGE_STATUS value from firmware
249 *
250 * Return: qca_wlan_vendor_twt_status values corresponding
251 * to the firmware failure status
252 */
253 static int
twt_nudge_status_to_vendor_twt_status(enum HOST_TWT_NUDGE_STATUS status)254 twt_nudge_status_to_vendor_twt_status(enum HOST_TWT_NUDGE_STATUS status)
255 {
256 switch (status) {
257 case HOST_TWT_NUDGE_STATUS_OK:
258 return QCA_WLAN_VENDOR_TWT_STATUS_OK;
259 case HOST_TWT_NUDGE_STATUS_DIALOG_ID_NOT_EXIST:
260 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
261 case HOST_TWT_NUDGE_STATUS_INVALID_PARAM:
262 return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
263 case HOST_TWT_NUDGE_STATUS_DIALOG_ID_BUSY:
264 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
265 case HOST_TWT_NUDGE_STATUS_NO_RESOURCE:
266 return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
267 case HOST_TWT_NUDGE_STATUS_NO_ACK:
268 return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
269 case HOST_TWT_NUDGE_STATUS_UNKNOWN_ERROR:
270 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
271 case HOST_TWT_NUDGE_STATUS_ALREADY_PAUSED:
272 return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED;
273 case HOST_TWT_NUDGE_STATUS_CHAN_SW_IN_PROGRESS:
274 return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
275 default:
276 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
277 }
278 }
279
280 /**
281 * twt_add_cmd_to_vendor_twt_resp_type() - convert from
282 * HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type
283 * @type: HOST_TWT_COMMAND value from firmware
284 *
285 * Return: qca_wlan_vendor_twt_setup_resp_type values for valid
286 * HOST_TWT_COMMAND value and -EINVAL for invalid value
287 */
288 static
twt_add_cmd_to_vendor_twt_resp_type(enum HOST_TWT_COMMAND type)289 int twt_add_cmd_to_vendor_twt_resp_type(enum HOST_TWT_COMMAND type)
290 {
291 switch (type) {
292 case HOST_TWT_COMMAND_ACCEPT_TWT:
293 return QCA_WLAN_VENDOR_TWT_RESP_ACCEPT;
294 case HOST_TWT_COMMAND_ALTERNATE_TWT:
295 return QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE;
296 case HOST_TWT_COMMAND_DICTATE_TWT:
297 return QCA_WLAN_VENDOR_TWT_RESP_DICTATE;
298 case HOST_TWT_COMMAND_REJECT_TWT:
299 return QCA_WLAN_VENDOR_TWT_RESP_REJECT;
300 default:
301 return -EINVAL;
302 }
303 }
304
305 /**
306 * osif_twt_setup_pack_resp_nlmsg() - pack nlmsg response for setup
307 * @reply_skb: pointer to the response skb structure
308 * @event: twt event buffer with firmware response
309 *
310 * Pack the nl response with parameters and additional parameters
311 * received from firmware.
312 * Firmware sends additional parameters only for 2 conditions
313 * 1) TWT Negotiation is accepted by AP - Firmware sends
314 * QCA_WLAN_VENDOR_TWT_STATUS_OK with appropriate response type
315 * in additional parameters
316 * 2) AP has proposed Alternate values - In this case firmware sends
317 * QCA_WLAN_VENDOR_TWT_STATUS_DENIED with appropriate response type
318 * in additional parameters
319 *
320 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
321 * on failure
322 */
323 static QDF_STATUS
osif_twt_setup_pack_resp_nlmsg(struct sk_buff * reply_skb,struct twt_add_dialog_complete_event * event)324 osif_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb,
325 struct twt_add_dialog_complete_event *event)
326 {
327 struct nlattr *config_attr;
328 uint64_t sp_offset_tsf;
329 enum qca_wlan_vendor_twt_status vendor_status;
330 int response_type, attr;
331 uint32_t wake_duration;
332 uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu;
333
334 if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
335 QCA_WLAN_TWT_SET)) {
336 osif_err("Failed to put TWT operation");
337 return QDF_STATUS_E_FAILURE;
338 }
339
340 config_attr = nla_nest_start(reply_skb,
341 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
342 if (!config_attr) {
343 osif_err("nla_nest_start error");
344 return QDF_STATUS_E_INVAL;
345 }
346
347 sp_offset_tsf = event->additional_params.sp_tsf_us_hi;
348 sp_offset_tsf = (sp_offset_tsf << 32) |
349 event->additional_params.sp_tsf_us_lo;
350
351 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
352 if (nla_put_u8(reply_skb, attr, event->params.dialog_id)) {
353 osif_err("Failed to put dialog_id");
354 return QDF_STATUS_E_FAILURE;
355 }
356
357 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
358 vendor_status = twt_add_status_to_vendor_twt_status(
359 event->params.status);
360 if (nla_put_u8(reply_skb, attr, vendor_status)) {
361 osif_err("Failed to put setup status");
362 return QDF_STATUS_E_FAILURE;
363 }
364
365 if (event->params.num_additional_twt_params == 0) {
366 nla_nest_end(reply_skb, config_attr);
367 return QDF_STATUS_SUCCESS;
368 }
369
370 response_type = twt_add_cmd_to_vendor_twt_resp_type(
371 event->additional_params.twt_cmd);
372 if (response_type == -EINVAL) {
373 osif_err("Invalid response type from firmware");
374 return QDF_STATUS_E_FAILURE;
375 }
376
377 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE;
378 if (nla_put_u8(reply_skb, attr, response_type)) {
379 osif_err("Failed to put setup response type");
380 return QDF_STATUS_E_FAILURE;
381 }
382
383 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
384 if (nla_put_u8(reply_skb, attr, event->additional_params.announce)) {
385 osif_err("Failed to put setup flow type");
386 return QDF_STATUS_E_FAILURE;
387 }
388
389 osif_debug("wake_dur_us %d", event->additional_params.wake_dur_us);
390 wake_duration = (event->additional_params.wake_dur_us /
391 TWT_WAKE_DURATION_MULTIPLICATION_FACTOR);
392
393 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
394 if (nla_put_u32(reply_skb, attr, wake_duration)) {
395 osif_err("Failed to put wake duration");
396 return QDF_STATUS_E_FAILURE;
397 }
398
399 wake_intvl_mantis_us = event->additional_params.wake_intvl_us;
400 if (nla_put_u32(reply_skb,
401 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA,
402 wake_intvl_mantis_us)) {
403 osif_err("Failed to put wake interval mantissa in us");
404 return QDF_STATUS_E_FAILURE;
405 }
406
407 wake_intvl_mantis_tu = (event->additional_params.wake_intvl_us /
408 TWT_WAKE_INTVL_MULTIPLICATION_FACTOR);
409
410 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
411 if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) {
412 osif_err("Failed to put wake interval mantissa in tu");
413 return QDF_STATUS_E_FAILURE;
414 }
415 osif_debug("Send mantissa_us:%d, mantissa_tu:%d to userspace",
416 wake_intvl_mantis_us, wake_intvl_mantis_tu);
417
418 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
419 if (nla_put_u8(reply_skb, attr, 0)) {
420 osif_err("Failed to put wake interval exp");
421 return QDF_STATUS_E_FAILURE;
422 }
423
424 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
425 if (wlan_cfg80211_nla_put_u64(reply_skb, attr, sp_offset_tsf)) {
426 osif_err("Failed to put sp_offset_tsf");
427 return QDF_STATUS_E_FAILURE;
428 }
429
430 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
431 if (nla_put_u32(reply_skb, attr,
432 event->additional_params.sp_offset_us)) {
433 osif_err("Failed to put sp_offset_us");
434 return QDF_STATUS_E_FAILURE;
435 }
436
437 if (event->additional_params.trig_en) {
438 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
439 if (nla_put_flag(reply_skb, attr)) {
440 osif_err("Failed to put trig type");
441 return QDF_STATUS_E_FAILURE;
442 }
443 }
444
445 if (event->additional_params.protection) {
446 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
447 if (nla_put_flag(reply_skb, attr)) {
448 osif_err("Failed to put protection flag");
449 return QDF_STATUS_E_FAILURE;
450 }
451 }
452
453 if (event->additional_params.bcast) {
454 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
455 if (nla_put_flag(reply_skb, attr)) {
456 osif_err("Failed to put bcast flag");
457 return QDF_STATUS_E_FAILURE;
458 }
459 }
460
461 if (!event->additional_params.info_frame_disabled) {
462 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED;
463 if (nla_put_flag(reply_skb, attr)) {
464 osif_err("Failed to put twt info enable flag");
465 return QDF_STATUS_E_FAILURE;
466 }
467 }
468
469 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
470 if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
471 event->params.peer_macaddr.bytes)) {
472 osif_err("Failed to put mac_addr");
473 return QDF_STATUS_E_INVAL;
474 }
475
476 nla_nest_end(reply_skb, config_attr);
477
478 return QDF_STATUS_SUCCESS;
479 }
480
481 /**
482 * twt_notify_status_to_vendor_twt_status() - convert from
483 * HOST_NOTIFY_TWT_STATUS to qca_wlan_vendor_twt_notify_status
484 * @status: HOST_TWT_NOTIFY_STATUS value from firmware
485 *
486 * Return: qca_wlan_vendor_twt_status values corresponding
487 * to the firmware failure status
488 */
489 static enum qca_wlan_vendor_twt_status
twt_notify_status_to_vendor_twt_status(enum HOST_TWT_NOTIFY_STATUS status)490 twt_notify_status_to_vendor_twt_status(enum HOST_TWT_NOTIFY_STATUS status)
491 {
492 switch (status) {
493 case HOST_TWT_NOTIFY_EVENT_AP_TWT_REQ_BIT_SET:
494 return QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED;
495 case HOST_TWT_NOTIFY_EVENT_AP_TWT_REQ_BIT_CLEAR:
496 return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED;
497 default:
498 return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED;
499 }
500 }
501
502 /**
503 * osif_twt_notify_pack_nlmsg() - pack nlmsg response for TWT notify
504 * @reply_skb: pointer to the response skb structure
505 * @event: twt event buffer with firmware response
506 *
507 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
508 * on failure
509 */
510 static QDF_STATUS
osif_twt_notify_pack_nlmsg(struct sk_buff * reply_skb,struct twt_notify_event_param * event)511 osif_twt_notify_pack_nlmsg(struct sk_buff *reply_skb,
512 struct twt_notify_event_param *event)
513 {
514 int attr;
515 enum qca_wlan_vendor_twt_status vendor_status;
516 enum qca_wlan_twt_operation twt_op;
517
518 if (event->status == HOST_TWT_NOTIFY_EVENT_READY)
519 twt_op = QCA_WLAN_TWT_SETUP_READY_NOTIFY;
520 else
521 twt_op = QCA_WLAN_TWT_NOTIFY;
522
523 if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
524 twt_op)) {
525 osif_err("Failed to put TWT notify operation");
526 return QDF_STATUS_E_FAILURE;
527 }
528
529 if (event->status != HOST_TWT_NOTIFY_EVENT_READY) {
530 attr = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS;
531 vendor_status = twt_notify_status_to_vendor_twt_status(
532 event->status);
533 if (nla_put_u8(reply_skb, attr, vendor_status)) {
534 osif_err("Failed to put notify status");
535 return QDF_STATUS_E_FAILURE;
536 }
537 }
538
539 return QDF_STATUS_SUCCESS;
540 }
541
542 /**
543 * osif_twt_teardown_pack_resp_nlmsg() - pack nlmsg response for teardown
544 * @reply_skb: pointer to the response skb structure
545 * @event: twt event buffer with firmware response
546 *
547 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
548 * on failure
549 */
550 static QDF_STATUS
osif_twt_teardown_pack_resp_nlmsg(struct sk_buff * reply_skb,struct twt_del_dialog_complete_event_param * event)551 osif_twt_teardown_pack_resp_nlmsg(struct sk_buff *reply_skb,
552 struct twt_del_dialog_complete_event_param *event)
553 {
554 struct nlattr *config_attr;
555 enum qca_wlan_vendor_twt_status vendor_status;
556 int attr;
557
558 if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
559 QCA_WLAN_TWT_TERMINATE)) {
560 osif_err("Failed to put TWT operation");
561 return QDF_STATUS_E_FAILURE;
562 }
563
564 config_attr = nla_nest_start(reply_skb,
565 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
566 if (!config_attr) {
567 osif_err("nla_nest_start error");
568 return QDF_STATUS_E_INVAL;
569 }
570
571 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
572 if (nla_put_u8(reply_skb, attr, event->dialog_id)) {
573 osif_debug("Failed to put dialog_id");
574 return QDF_STATUS_E_FAILURE;
575 }
576
577 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
578 vendor_status = twt_del_status_to_vendor_twt_status(event->status);
579 if (nla_put_u8(reply_skb, attr, vendor_status)) {
580 osif_err("Failed to put QCA_WLAN_TWT_TERMINATE");
581 return QDF_STATUS_E_FAILURE;
582 }
583
584 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
585 if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
586 event->peer_macaddr.bytes)) {
587 osif_err("Failed to put mac_addr");
588 return QDF_STATUS_E_INVAL;
589 }
590
591 nla_nest_end(reply_skb, config_attr);
592
593 return QDF_STATUS_SUCCESS;
594 }
595
596 /**
597 * osif_twt_resume_pack_resp_nlmsg() - pack the skb with
598 * firmware response for twt resume command
599 * @reply_skb: skb to store the response
600 * @event: Pointer to resume dialog complete event buffer
601 *
602 * Return: QDF_STATUS
603 */
604 static QDF_STATUS
osif_twt_resume_pack_resp_nlmsg(struct sk_buff * reply_skb,struct twt_resume_dialog_complete_event_param * event)605 osif_twt_resume_pack_resp_nlmsg(struct sk_buff *reply_skb,
606 struct twt_resume_dialog_complete_event_param *event)
607 {
608 struct nlattr *config_attr;
609 int vendor_status, attr;
610
611 if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
612 QCA_WLAN_TWT_RESUME)) {
613 osif_err("Failed to put TWT operation");
614 return QDF_STATUS_E_FAILURE;
615 }
616
617 config_attr = nla_nest_start(reply_skb,
618 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
619 if (!config_attr) {
620 osif_err("nla_nest_start error");
621 return QDF_STATUS_E_INVAL;
622 }
623
624 attr = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID;
625 if (nla_put_u8(reply_skb, attr, event->dialog_id)) {
626 osif_debug("Failed to put dialog_id");
627 return QDF_STATUS_E_FAILURE;
628 }
629
630 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
631 vendor_status = twt_resume_status_to_vendor_twt_status(event->status);
632 if (nla_put_u8(reply_skb, attr, vendor_status)) {
633 osif_err("Failed to put QCA_WLAN_TWT_RESUME status");
634 return QDF_STATUS_E_FAILURE;
635 }
636
637 attr = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR;
638 if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
639 event->peer_macaddr.bytes)) {
640 osif_err("Failed to put mac_addr");
641 return QDF_STATUS_E_INVAL;
642 }
643
644 nla_nest_end(reply_skb, config_attr);
645
646 return QDF_STATUS_SUCCESS;
647 }
648
649 /**
650 * osif_twt_nudge_pack_resp_nlmsg() - pack the skb with
651 * firmware response for twt nudge command
652 * @reply_skb: skb to store the response
653 * @event: Pointer to nudge dialog complete event buffer
654 *
655 * Return: QDF_STATUS
656 */
657 static QDF_STATUS
osif_twt_nudge_pack_resp_nlmsg(struct sk_buff * reply_skb,struct twt_nudge_dialog_complete_event_param * event)658 osif_twt_nudge_pack_resp_nlmsg(struct sk_buff *reply_skb,
659 struct twt_nudge_dialog_complete_event_param *event)
660 {
661 struct nlattr *config_attr;
662 int vendor_status, attr;
663 uint64_t tsf_val;
664
665 if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
666 QCA_WLAN_TWT_NUDGE)) {
667 osif_err("Failed to put TWT operation");
668 return QDF_STATUS_E_FAILURE;
669 }
670
671 config_attr = nla_nest_start(reply_skb,
672 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
673 if (!config_attr) {
674 osif_err("nla_nest_start error");
675 return QDF_STATUS_E_INVAL;
676 }
677
678 attr = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID;
679 if (nla_put_u8(reply_skb, attr, event->dialog_id)) {
680 osif_debug("Failed to put dialog_id");
681 return QDF_STATUS_E_FAILURE;
682 }
683
684 tsf_val = event->next_twt_tsf_us_hi;
685 tsf_val = (tsf_val << 32) | event->next_twt_tsf_us_lo;
686 if (wlan_cfg80211_nla_put_u64(reply_skb,
687 QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF,
688 tsf_val)) {
689 osif_err("get_params failed to put TSF Value");
690 return QDF_STATUS_E_INVAL;
691 }
692
693 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
694 vendor_status = twt_nudge_status_to_vendor_twt_status(event->status);
695 if (nla_put_u8(reply_skb, attr, vendor_status)) {
696 osif_err("Failed to put QCA_WLAN_TWT_NUDGE status");
697 return QDF_STATUS_E_FAILURE;
698 }
699
700 attr = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR;
701 if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
702 event->peer_macaddr.bytes)) {
703 osif_err("Failed to put mac_addr");
704 return QDF_STATUS_E_INVAL;
705 }
706
707 nla_nest_end(reply_skb, config_attr);
708
709 return QDF_STATUS_SUCCESS;
710 }
711
712 QDF_STATUS
osif_twt_send_get_capabilities_response(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev)713 osif_twt_send_get_capabilities_response(struct wlan_objmgr_psoc *psoc,
714 struct wlan_objmgr_vdev *vdev)
715 {
716 struct vdev_osif_priv *osif_priv;
717 struct nlattr *config_attr;
718 struct sk_buff *reply_skb;
719 size_t skb_len = NLMSG_HDRLEN;
720 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
721 enum band_info connected_band;
722 uint8_t peer_cap = 0, self_cap = 0;
723 bool twt_req = false, twt_bcast_req = false;
724 bool is_twt_24ghz_allowed = true, val;
725 struct qdf_mac_addr peer_mac;
726 int ret;
727
728 /*
729 * Userspace will query the TWT get capabilities before
730 * issuing a get capabilities request. If the STA is
731 * connected, then check the "enable_twt_24ghz" ini
732 * value to advertise the TWT requestor capability.
733 */
734 connected_band = ucfg_cm_get_connected_band(vdev);
735 ucfg_twt_cfg_get_24ghz_enabled(psoc, &val);
736
737 osif_debug("connected_band: %d val: %d", connected_band, val);
738 if (connected_band == BAND_2G && !val)
739 is_twt_24ghz_allowed = false;
740
741 /* fill the self_capability bitmap */
742 ucfg_twt_cfg_get_requestor(psoc, &twt_req);
743 osif_debug("is_twt_24ghz_allowed: %d twt_req: %d",
744 is_twt_24ghz_allowed, twt_req);
745 if (twt_req && is_twt_24ghz_allowed)
746 self_cap |= QCA_WLAN_TWT_CAPA_REQUESTOR;
747
748 ucfg_twt_cfg_get_bcast_requestor(psoc, &twt_bcast_req);
749 osif_debug("twt_bcast_req: %d", twt_bcast_req);
750 self_cap |= (twt_bcast_req ? QCA_WLAN_TWT_CAPA_BROADCAST : 0);
751
752 ucfg_twt_cfg_get_flex_sched(psoc, &val);
753 osif_debug("flex sched: %d", val);
754 if (val)
755 self_cap |= QCA_WLAN_TWT_CAPA_FLEXIBLE;
756
757 ret = osif_fill_peer_macaddr(vdev, peer_mac.bytes);
758 if (ret)
759 return QDF_STATUS_E_INVAL;
760
761 qdf_status = ucfg_twt_get_peer_capabilities(psoc, &peer_mac, &peer_cap);
762 if (QDF_IS_STATUS_ERROR(qdf_status))
763 return qdf_status;
764
765 osif_debug("self_cap: 0x%x peer_cap: 0x%x", self_cap, peer_cap);
766 osif_priv = wlan_vdev_get_ospriv(vdev);
767 /*
768 * Length of attribute QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF &
769 * QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER
770 */
771 skb_len += 2 * nla_total_size(sizeof(u16)) + NLA_HDRLEN;
772
773 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(
774 osif_priv->wdev->wiphy,
775 skb_len);
776 if (!reply_skb) {
777 osif_err("TWT: get_caps alloc reply skb failed");
778 return QDF_STATUS_E_NOMEM;
779 }
780
781 config_attr = nla_nest_start(reply_skb,
782 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
783 if (!config_attr) {
784 osif_err("TWT: nla_nest_start error");
785 qdf_status = QDF_STATUS_E_FAILURE;
786 goto free_skb;
787 }
788
789 if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF,
790 self_cap)) {
791 osif_err("TWT: Failed to fill capabilities");
792 qdf_status = QDF_STATUS_E_FAILURE;
793 goto free_skb;
794 }
795
796 if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER,
797 peer_cap)) {
798 osif_err("TWT: Failed to fill capabilities");
799 qdf_status = QDF_STATUS_E_FAILURE;
800 goto free_skb;
801 }
802
803 nla_nest_end(reply_skb, config_attr);
804
805 if (wlan_cfg80211_vendor_cmd_reply(reply_skb))
806 qdf_status = QDF_STATUS_E_INVAL;
807 return qdf_status;
808
809 free_skb:
810 wlan_cfg80211_vendor_free_skb(reply_skb);
811 return qdf_status;
812 }
813
814 static void
osif_twt_setup_response(struct wlan_objmgr_psoc * psoc,struct twt_add_dialog_complete_event * event)815 osif_twt_setup_response(struct wlan_objmgr_psoc *psoc,
816 struct twt_add_dialog_complete_event *event)
817 {
818 struct sk_buff *twt_vendor_event;
819 struct wireless_dev *wdev;
820 struct wlan_objmgr_vdev *vdev;
821 struct vdev_osif_priv *osif_priv;
822 size_t data_len;
823 QDF_STATUS status;
824 bool additional_params_present = false;
825
826 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
827 event->params.vdev_id,
828 WLAN_TWT_ID);
829 if (!vdev) {
830 osif_err("vdev is null");
831 return;
832 }
833
834 osif_priv = wlan_vdev_get_ospriv(vdev);
835 if (!osif_priv) {
836 osif_err("osif_priv is null");
837 goto fail;
838 }
839
840 wdev = osif_priv->wdev;
841 if (!wdev) {
842 osif_err("wireless dev is null");
843 goto fail;
844 }
845
846 if (event->params.num_additional_twt_params != 0)
847 additional_params_present = true;
848
849 data_len = osif_twt_get_setup_event_len(additional_params_present);
850 twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
851 wdev->wiphy, wdev, data_len,
852 QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
853 GFP_KERNEL);
854 if (!twt_vendor_event) {
855 osif_err("TWT: Alloc setup resp skb fail");
856 goto fail;
857 }
858
859 status = osif_twt_setup_pack_resp_nlmsg(twt_vendor_event, event);
860 if (QDF_IS_STATUS_ERROR(status)) {
861 osif_err("Failed to pack nl add dialog response");
862 wlan_cfg80211_vendor_free_skb(twt_vendor_event);
863 goto fail;
864 }
865
866 wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
867
868 fail:
869 wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
870 }
871
872 static void
osif_twt_teardown_response(struct wlan_objmgr_psoc * psoc,struct twt_del_dialog_complete_event_param * event)873 osif_twt_teardown_response(struct wlan_objmgr_psoc *psoc,
874 struct twt_del_dialog_complete_event_param *event)
875 {
876 struct sk_buff *twt_vendor_event;
877 struct wireless_dev *wdev;
878 struct wlan_objmgr_vdev *vdev;
879 struct vdev_osif_priv *osif_priv;
880 size_t data_len;
881 QDF_STATUS status;
882
883 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
884 event->vdev_id, WLAN_TWT_ID);
885 if (!vdev) {
886 osif_err("vdev is null");
887 return;
888 }
889
890 osif_priv = wlan_vdev_get_ospriv(vdev);
891 if (!osif_priv) {
892 osif_err("osif_priv is null");
893 goto fail;
894 }
895
896 wdev = osif_priv->wdev;
897 if (!wdev) {
898 osif_err("wireless dev is null");
899 goto fail;
900 }
901
902 data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8));
903 data_len += NLA_HDRLEN;
904 twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
905 wdev->wiphy, wdev, data_len,
906 QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
907 GFP_KERNEL);
908 if (!twt_vendor_event) {
909 osif_err("TWT: Alloc teardown resp skb fail");
910 goto fail;
911 }
912
913 status = osif_twt_teardown_pack_resp_nlmsg(twt_vendor_event, event);
914 if (QDF_IS_STATUS_ERROR(status)) {
915 osif_err("Failed to pack nl del dialog response");
916 wlan_cfg80211_vendor_free_skb(twt_vendor_event);
917 goto fail;
918 }
919
920 wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
921
922 fail:
923 wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
924 }
925
926 QDF_STATUS
osif_twt_setup_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_add_dialog_complete_event * event,bool renego_fail)927 osif_twt_setup_complete_cb(struct wlan_objmgr_psoc *psoc,
928 struct twt_add_dialog_complete_event *event,
929 bool renego_fail)
930 {
931 uint32_t vdev_id = event->params.vdev_id;
932
933 osif_debug("TWT: add dialog_id:%d, status:%d vdev_id:%d renego_fail:%d peer mac_addr "
934 QDF_MAC_ADDR_FMT, event->params.dialog_id,
935 event->params.status, vdev_id, renego_fail,
936 QDF_MAC_ADDR_REF(event->params.peer_macaddr.bytes));
937
938 osif_twt_setup_response(psoc, event);
939
940 if (renego_fail)
941 osif_twt_handle_renego_failure(psoc, event);
942
943 return QDF_STATUS_SUCCESS;
944 }
945
946 QDF_STATUS
osif_twt_teardown_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_del_dialog_complete_event_param * event)947 osif_twt_teardown_complete_cb(struct wlan_objmgr_psoc *psoc,
948 struct twt_del_dialog_complete_event_param *event)
949 {
950 uint32_t vdev_id = event->vdev_id;
951
952 osif_debug("TWT: del dialog_id:%d status:%d vdev_id:%d peer mac_addr "
953 QDF_MAC_ADDR_FMT, event->dialog_id,
954 event->status, vdev_id,
955 QDF_MAC_ADDR_REF(event->peer_macaddr.bytes));
956
957 osif_twt_teardown_response(psoc, event);
958
959 return QDF_STATUS_SUCCESS;
960 }
961
962 QDF_STATUS
osif_twt_resume_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_resume_dialog_complete_event_param * event)963 osif_twt_resume_complete_cb(struct wlan_objmgr_psoc *psoc,
964 struct twt_resume_dialog_complete_event_param *event)
965 {
966 struct wireless_dev *wdev;
967 struct vdev_osif_priv *osif_priv;
968 struct wlan_objmgr_vdev *vdev;
969 uint32_t vdev_id = event->vdev_id;
970 struct sk_buff *twt_vendor_event;
971 size_t data_len;
972 QDF_STATUS status = QDF_STATUS_E_FAILURE;
973
974 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
975 WLAN_TWT_ID);
976 if (!vdev) {
977 osif_err("vdev is null");
978 return status;
979 }
980
981 osif_priv = wlan_vdev_get_ospriv(vdev);
982 if (!osif_priv) {
983 osif_err("osif_priv is null");
984 goto fail;
985 }
986
987 wdev = osif_priv->wdev;
988 if (!wdev) {
989 osif_err("wireless dev is null");
990 goto fail;
991 }
992
993 osif_debug("TWT: resume dialog_id:%d status:%d vdev_id:%d peer macaddr "
994 QDF_MAC_ADDR_FMT, event->dialog_id,
995 event->status, vdev_id,
996 QDF_MAC_ADDR_REF(event->peer_macaddr.bytes));
997
998 data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8));
999 data_len += NLA_HDRLEN;
1000
1001 twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
1002 wdev->wiphy, wdev, data_len,
1003 QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
1004 GFP_KERNEL);
1005 if (!twt_vendor_event) {
1006 osif_err("TWT: Alloc resume resp skb fail");
1007 goto fail;
1008 }
1009
1010 status = osif_twt_resume_pack_resp_nlmsg(twt_vendor_event, event);
1011 if (QDF_IS_STATUS_ERROR(status)) {
1012 osif_err("Failed to pack nl resume dialog response");
1013 wlan_cfg80211_vendor_free_skb(twt_vendor_event);
1014 goto fail;
1015 }
1016 wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
1017
1018 fail:
1019 wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
1020 return status;
1021 }
1022
1023 QDF_STATUS
osif_twt_nudge_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_nudge_dialog_complete_event_param * event)1024 osif_twt_nudge_complete_cb(struct wlan_objmgr_psoc *psoc,
1025 struct twt_nudge_dialog_complete_event_param *event)
1026 {
1027 struct wireless_dev *wdev;
1028 struct vdev_osif_priv *osif_priv;
1029 struct wlan_objmgr_vdev *vdev;
1030 uint32_t vdev_id = event->vdev_id;
1031 struct sk_buff *twt_vendor_event;
1032 size_t data_len;
1033 QDF_STATUS status = QDF_STATUS_E_FAILURE;
1034
1035 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
1036 WLAN_TWT_ID);
1037 if (!vdev) {
1038 osif_err("vdev is null");
1039 return status;
1040 }
1041
1042 osif_priv = wlan_vdev_get_ospriv(vdev);
1043 if (!osif_priv) {
1044 osif_err("osif_priv is null");
1045 goto fail;
1046 }
1047
1048 wdev = osif_priv->wdev;
1049 if (!wdev) {
1050 osif_err("wireless dev is null");
1051 goto fail;
1052 }
1053
1054 osif_debug("TWT: nudge dialog_id:%d status:%d vdev_id:%d peer macaddr "
1055 QDF_MAC_ADDR_FMT, event->dialog_id,
1056 event->status, vdev_id,
1057 QDF_MAC_ADDR_REF(event->peer_macaddr.bytes));
1058
1059 data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8)) +
1060 nla_total_size(sizeof(u64));
1061 data_len += NLA_HDRLEN;
1062
1063 twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
1064 wdev->wiphy, wdev, data_len,
1065 QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
1066 GFP_KERNEL);
1067 if (!twt_vendor_event) {
1068 osif_err("TWT: Alloc nudge resp skb fail");
1069 goto fail;
1070 }
1071
1072 status = osif_twt_nudge_pack_resp_nlmsg(twt_vendor_event, event);
1073 if (QDF_IS_STATUS_ERROR(status)) {
1074 osif_err("Failed to pack nl add dialog response");
1075 wlan_cfg80211_vendor_free_skb(twt_vendor_event);
1076 goto fail;
1077 }
1078 wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
1079
1080 fail:
1081 wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
1082 return status;
1083
1084 }
1085
1086 /**
1087 * osif_twt_get_notify_event_len() - calculates the length of twt
1088 * notify nl response
1089 *
1090 * Return: Length of twt notify nl response
1091 */
1092 static
osif_twt_get_notify_event_len(void)1093 uint32_t osif_twt_get_notify_event_len(void)
1094 {
1095 uint32_t len = 0;
1096
1097 len += NLMSG_HDRLEN;
1098
1099 /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */
1100 len += nla_total_size(sizeof(u8));
1101
1102 /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS */
1103 len += nla_total_size(sizeof(u8));
1104
1105 return len;
1106 }
1107
1108 QDF_STATUS
osif_twt_notify_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_notify_event_param * event)1109 osif_twt_notify_complete_cb(struct wlan_objmgr_psoc *psoc,
1110 struct twt_notify_event_param *event)
1111 {
1112 struct wireless_dev *wdev;
1113 struct sk_buff *twt_vendor_event;
1114 size_t data_len;
1115 QDF_STATUS status;
1116 struct vdev_osif_priv *osif_priv;
1117 struct wlan_objmgr_vdev *vdev;
1118
1119 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
1120 WLAN_TWT_ID);
1121 if (!vdev) {
1122 osif_err("vdev is null");
1123 return QDF_STATUS_E_INVAL;
1124 }
1125
1126 osif_priv = wlan_vdev_get_ospriv(vdev);
1127 if (!osif_priv) {
1128 osif_err("osif_priv is null");
1129 status = QDF_STATUS_E_INVAL;
1130 goto end;
1131 }
1132
1133 wdev = osif_priv->wdev;
1134 if (!wdev) {
1135 osif_err("wireless dev is null");
1136 status = QDF_STATUS_E_INVAL;
1137 goto end;
1138 }
1139
1140 data_len = osif_twt_get_notify_event_len();
1141 data_len += NLA_HDRLEN;
1142
1143 twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
1144 wdev->wiphy, wdev, data_len,
1145 QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
1146 GFP_KERNEL);
1147 if (!twt_vendor_event) {
1148 osif_err("Notify skb alloc failed");
1149 status = QDF_STATUS_E_INVAL;
1150 goto end;
1151 }
1152
1153 osif_debug("TWT: twt Notify vdev_id: %d, status: %d", event->vdev_id,
1154 event->status);
1155
1156 status = osif_twt_notify_pack_nlmsg(twt_vendor_event, event);
1157 if (QDF_IS_STATUS_ERROR(status)) {
1158 osif_err("Failed to pack nl notify event");
1159 wlan_cfg80211_vendor_free_skb(twt_vendor_event);
1160 status = QDF_STATUS_E_INVAL;
1161 goto end;
1162 }
1163
1164 wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
1165 status = QDF_STATUS_SUCCESS;
1166
1167 end:
1168 wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
1169 return status;
1170 }
1171
1172 /**
1173 * twt_pause_status_to_vendor_twt_status() - convert from
1174 * HOST_TWT_PAUSE_STATUS to qca_wlan_vendor_twt_status
1175 * @status: HOST_TWT_PAUSE_STATUS value from firmware
1176 *
1177 * Return: qca_wlan_vendor_twt_status values corresponding
1178 * to the firmware failure status
1179 */
1180 static int
twt_pause_status_to_vendor_twt_status(enum HOST_TWT_PAUSE_STATUS status)1181 twt_pause_status_to_vendor_twt_status(enum HOST_TWT_PAUSE_STATUS status)
1182 {
1183 switch (status) {
1184 case HOST_TWT_PAUSE_STATUS_OK:
1185 return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1186 case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST:
1187 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
1188 case HOST_TWT_PAUSE_STATUS_INVALID_PARAM:
1189 return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1190 case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY:
1191 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
1192 case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED:
1193 return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED;
1194 case HOST_TWT_PAUSE_STATUS_NO_RESOURCE:
1195 return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
1196 case HOST_TWT_PAUSE_STATUS_NO_ACK:
1197 return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
1198 case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR:
1199 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1200 case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS:
1201 return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
1202 case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS:
1203 return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
1204 default:
1205 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1206 }
1207 }
1208
1209 /**
1210 * osif_twt_pause_pack_resp_nlmsg() - pack the skb with
1211 * firmware response for twt pause command
1212 * @reply_skb: skb to store the response
1213 * @event: Pointer to pause dialog complete event buffer
1214 *
1215 * Return: QDF_STATUS
1216 */
1217 static QDF_STATUS
osif_twt_pause_pack_resp_nlmsg(struct sk_buff * reply_skb,struct twt_pause_dialog_complete_event_param * event)1218 osif_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb,
1219 struct twt_pause_dialog_complete_event_param *event)
1220 {
1221 struct nlattr *config_attr;
1222 int vendor_status, attr;
1223
1224 if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
1225 QCA_WLAN_TWT_SUSPEND)) {
1226 osif_err("Failed to put TWT operation");
1227 return QDF_STATUS_E_FAILURE;
1228 }
1229
1230 config_attr = nla_nest_start(reply_skb,
1231 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
1232 if (!config_attr) {
1233 osif_err("nla_nest_start error");
1234 return QDF_STATUS_E_INVAL;
1235 }
1236
1237 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1238 if (nla_put_u8(reply_skb, attr, event->dialog_id)) {
1239 osif_debug("Failed to put dialog_id");
1240 return QDF_STATUS_E_FAILURE;
1241 }
1242
1243 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
1244 vendor_status = twt_pause_status_to_vendor_twt_status(event->status);
1245 if (nla_put_u8(reply_skb, attr, vendor_status)) {
1246 osif_err("Failed to put QCA_WLAN_TWT_PAUSE status");
1247 return QDF_STATUS_E_FAILURE;
1248 }
1249
1250 attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1251 if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
1252 event->peer_macaddr.bytes)) {
1253 osif_err("Failed to put mac_addr");
1254 return QDF_STATUS_E_INVAL;
1255 }
1256
1257 nla_nest_end(reply_skb, config_attr);
1258
1259 return QDF_STATUS_SUCCESS;
1260 }
1261
1262 QDF_STATUS
osif_twt_pause_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_pause_dialog_complete_event_param * event)1263 osif_twt_pause_complete_cb(struct wlan_objmgr_psoc *psoc,
1264 struct twt_pause_dialog_complete_event_param *event)
1265
1266 {
1267 struct wireless_dev *wdev;
1268 struct vdev_osif_priv *osif_priv;
1269 struct wlan_objmgr_vdev *vdev;
1270 uint32_t vdev_id = event->vdev_id;
1271 struct sk_buff *twt_vendor_event;
1272 size_t data_len;
1273 QDF_STATUS status = QDF_STATUS_E_FAILURE;
1274
1275 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
1276 WLAN_TWT_ID);
1277 if (!vdev) {
1278 osif_err("vdev is null");
1279 return status;
1280 }
1281
1282 osif_priv = wlan_vdev_get_ospriv(vdev);
1283 if (!osif_priv) {
1284 osif_err("osif_priv is null");
1285 goto fail;
1286 }
1287
1288 wdev = osif_priv->wdev;
1289 if (!wdev) {
1290 osif_err("wireless dev is null");
1291 goto fail;
1292 }
1293
1294 osif_debug("TWT: pause dialog_id:%d status:%d vdev_id:%d peer macaddr "
1295 QDF_MAC_ADDR_FMT, event->dialog_id,
1296 event->status, vdev_id,
1297 QDF_MAC_ADDR_REF(event->peer_macaddr.bytes));
1298
1299 data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8));
1300 data_len += NLA_HDRLEN;
1301
1302 twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
1303 wdev->wiphy, wdev, data_len,
1304 QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
1305 GFP_KERNEL);
1306 if (!twt_vendor_event) {
1307 osif_err("TWT: Alloc pause resp skb fail");
1308 goto fail;
1309 }
1310
1311 status = osif_twt_pause_pack_resp_nlmsg(twt_vendor_event, event);
1312 if (QDF_IS_STATUS_ERROR(status)) {
1313 osif_err("Failed to pack nl add dialog response");
1314 wlan_cfg80211_vendor_free_skb(twt_vendor_event);
1315 goto fail;
1316 }
1317 wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
1318
1319 fail:
1320 wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
1321 return status;
1322 }
1323
1324 QDF_STATUS
osif_twt_ack_complete_cb(struct wlan_objmgr_psoc * psoc,struct twt_ack_complete_event_param * params,void * context)1325 osif_twt_ack_complete_cb(struct wlan_objmgr_psoc *psoc,
1326 struct twt_ack_complete_event_param *params,
1327 void *context)
1328 {
1329 struct osif_request *request = NULL;
1330 struct twt_ack_context *status_priv;
1331
1332 request = osif_request_get(context);
1333 if (!request) {
1334 osif_err("obsolete request");
1335 return QDF_STATUS_E_FAILURE;
1336 }
1337
1338 status_priv = osif_request_priv(request);
1339 if (!status_priv) {
1340 osif_err("obsolete status_priv");
1341 return QDF_STATUS_E_FAILURE;
1342 }
1343
1344 if (status_priv->twt_cmd_ack == params->twt_cmd_ack) {
1345 status_priv->vdev_id = params->vdev_id;
1346 qdf_copy_macaddr(&status_priv->peer_macaddr,
1347 ¶ms->peer_macaddr);
1348 status_priv->dialog_id = params->dialog_id;
1349 status_priv->status = params->status;
1350 osif_request_complete(request);
1351 } else {
1352 osif_err("Invalid TWT ack. Expected cmd: %d Actual cmd: %d",
1353 status_priv->twt_cmd_ack, params->twt_cmd_ack);
1354 }
1355
1356 osif_request_put(request);
1357 return QDF_STATUS_SUCCESS;
1358 }
1359
1360 static uint32_t
osif_get_session_wake_duration(struct wlan_objmgr_vdev * vdev,uint32_t dialog_id,struct qdf_mac_addr * peer_macaddr)1361 osif_get_session_wake_duration(struct wlan_objmgr_vdev *vdev,
1362 uint32_t dialog_id,
1363 struct qdf_mac_addr *peer_macaddr)
1364 {
1365 struct wlan_objmgr_psoc *psoc;
1366 struct twt_session_stats_info params = {0};
1367 int num_twt_session = 0;
1368
1369 psoc = wlan_vdev_get_psoc(vdev);
1370 params.dialog_id = dialog_id;
1371 qdf_copy_macaddr(¶ms.peer_mac, peer_macaddr);
1372
1373 osif_debug("Get_params peer mac_addr " QDF_MAC_ADDR_FMT,
1374 QDF_MAC_ADDR_REF(params.peer_mac.bytes));
1375
1376 num_twt_session = ucfg_cp_stats_twt_get_peer_session_params(psoc,
1377 ¶ms);
1378 if (num_twt_session)
1379 return params.wake_dura_us;
1380
1381 return 0;
1382 }
1383
1384 static int
twt_get_stats_status_to_vendor_twt_status(enum HOST_TWT_GET_STATS_STATUS status)1385 twt_get_stats_status_to_vendor_twt_status(enum HOST_TWT_GET_STATS_STATUS status)
1386 {
1387 switch (status) {
1388 case HOST_TWT_GET_STATS_STATUS_OK:
1389 return QCA_WLAN_VENDOR_TWT_STATUS_OK;
1390 case HOST_TWT_GET_STATS_STATUS_DIALOG_ID_NOT_EXIST:
1391 return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
1392 case HOST_TWT_GET_STATS_STATUS_INVALID_PARAM:
1393 return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
1394 default:
1395 return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
1396 }
1397 }
1398
1399 /**
1400 * osif_twt_pack_get_stats_resp_nlmsg() - Packs and sends twt get stats response
1401 * @vdev: vdev
1402 * @reply_skb: pointer to response skb buffer
1403 * @params: Pointer to twt session parameter buffer
1404 * @num_session_stats: number of twt statistics
1405 *
1406 * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
1407 */
1408 static QDF_STATUS
osif_twt_pack_get_stats_resp_nlmsg(struct wlan_objmgr_vdev * vdev,struct sk_buff * reply_skb,struct twt_infra_cp_stats_event * params,uint32_t num_session_stats)1409 osif_twt_pack_get_stats_resp_nlmsg(struct wlan_objmgr_vdev *vdev,
1410 struct sk_buff *reply_skb,
1411 struct twt_infra_cp_stats_event *params,
1412 uint32_t num_session_stats)
1413 {
1414 struct nlattr *config_attr, *nla_params;
1415 int i, attr;
1416 int vendor_status;
1417 uint32_t duration;
1418
1419 config_attr = nla_nest_start(reply_skb,
1420 QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
1421
1422 if (!config_attr) {
1423 osif_err("get_params nla_nest_start error");
1424 return QDF_STATUS_E_INVAL;
1425 }
1426
1427 for (i = 0; i < num_session_stats; i++) {
1428 nla_params = nla_nest_start(reply_skb, i);
1429 if (!nla_params) {
1430 osif_err("get_stats nla_nest_start error");
1431 return QDF_STATUS_E_INVAL;
1432 }
1433
1434 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR;
1435 if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
1436 params[i].peer_macaddr.bytes)) {
1437 osif_err("get_stats failed to put mac_addr");
1438 return QDF_STATUS_E_INVAL;
1439 }
1440
1441 osif_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT,
1442 QDF_MAC_ADDR_REF(params[i].peer_macaddr.bytes));
1443
1444 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
1445 if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) {
1446 osif_err("get_stats failed to put dialog_id");
1447 return QDF_STATUS_E_INVAL;
1448 }
1449
1450 duration = osif_get_session_wake_duration(vdev,
1451 params[i].dialog_id,
1452 ¶ms[i].peer_macaddr);
1453 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION;
1454 if (nla_put_u32(reply_skb, attr, duration)) {
1455 osif_err("get_params failed to put Wake duration");
1456 return QDF_STATUS_E_INVAL;
1457 }
1458
1459 osif_debug("dialog_id %d wake duration %d num sp cycles %d",
1460 params[i].dialog_id, duration,
1461 params[i].num_sp_cycles);
1462
1463 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS;
1464 if (nla_put_u32(reply_skb, attr, params[i].num_sp_cycles)) {
1465 osif_err("get_params failed to put num_sp_cycles");
1466 return QDF_STATUS_E_INVAL;
1467 }
1468
1469 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION;
1470 if (nla_put_u32(reply_skb, attr, params[i].avg_sp_dur_us)) {
1471 osif_err("get_params failed to put avg_sp_dur_us");
1472 return QDF_STATUS_E_INVAL;
1473 }
1474
1475 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION;
1476 if (nla_put_u32(reply_skb, attr, params[i].min_sp_dur_us)) {
1477 osif_err("get_params failed to put min_sp_dur_us");
1478 return QDF_STATUS_E_INVAL;
1479 }
1480
1481 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION;
1482 if (nla_put_u32(reply_skb, attr, params[i].max_sp_dur_us)) {
1483 osif_err("get_params failed to put max_sp_dur_us");
1484 return QDF_STATUS_E_INVAL;
1485 }
1486
1487 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU;
1488 if (nla_put_u32(reply_skb, attr, params[i].tx_mpdu_per_sp)) {
1489 osif_err("get_params failed to put tx_mpdu_per_sp");
1490 return QDF_STATUS_E_INVAL;
1491 }
1492
1493 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU;
1494 if (nla_put_u32(reply_skb, attr, params[i].rx_mpdu_per_sp)) {
1495 osif_err("get_params failed to put rx_mpdu_per_sp");
1496 return QDF_STATUS_E_INVAL;
1497 }
1498
1499 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE;
1500 if (nla_put_u32(reply_skb, attr, params[i].tx_bytes_per_sp)) {
1501 osif_err("get_params failed to put tx_bytes_per_sp");
1502 return QDF_STATUS_E_INVAL;
1503 }
1504
1505 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE;
1506 if (nla_put_u32(reply_skb, attr, params[i].rx_bytes_per_sp)) {
1507 osif_err("get_params failed to put rx_bytes_per_sp");
1508 return QDF_STATUS_E_INVAL;
1509 }
1510
1511 attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS;
1512 vendor_status =
1513 twt_get_stats_status_to_vendor_twt_status(params[i].status);
1514 if (nla_put_u32(reply_skb, attr, vendor_status)) {
1515 osif_err("get_params failed to put status");
1516 return QDF_STATUS_E_INVAL;
1517 }
1518
1519 nla_nest_end(reply_skb, nla_params);
1520 }
1521
1522 nla_nest_end(reply_skb, config_attr);
1523
1524 return QDF_STATUS_SUCCESS;
1525 }
1526
1527 /**
1528 * osif_get_twt_get_stats_event_len() - calculate length of skb
1529 * required for sending twt get statistics command responses.
1530 *
1531 * Return: length of skb
1532 */
osif_get_twt_get_stats_event_len(void)1533 static uint32_t osif_get_twt_get_stats_event_len(void)
1534 {
1535 uint32_t len = 0;
1536
1537 len += NLMSG_HDRLEN;
1538
1539 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
1540 len += nla_total_size(sizeof(u8));
1541
1542 /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
1543 len += nla_total_size(sizeof(u8));
1544
1545 return len;
1546 }
1547
osif_twt_get_stats_response(struct wlan_objmgr_vdev * vdev,struct twt_infra_cp_stats_event * params,uint32_t num_session_stats)1548 QDF_STATUS osif_twt_get_stats_response(struct wlan_objmgr_vdev *vdev,
1549 struct twt_infra_cp_stats_event *params,
1550 uint32_t num_session_stats)
1551 {
1552 int skb_len;
1553 struct vdev_osif_priv *osif_priv;
1554 struct wireless_dev *wdev;
1555 QDF_STATUS status = QDF_STATUS_E_INVAL;
1556 struct sk_buff *reply_skb;
1557 int ret;
1558
1559 osif_priv = wlan_vdev_get_ospriv(vdev);
1560 if (!osif_priv) {
1561 osif_err("osif_priv is null");
1562 return QDF_STATUS_E_INVAL;
1563 }
1564
1565 wdev = osif_priv->wdev;
1566 if (!wdev) {
1567 osif_err("wireless dev is null");
1568 return QDF_STATUS_E_INVAL;
1569 }
1570
1571 skb_len = osif_get_twt_get_stats_event_len();
1572 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy,
1573 skb_len);
1574 if (!reply_skb) {
1575 osif_err("Get stats - alloc reply_skb failed");
1576 return QDF_STATUS_E_NOMEM;
1577 }
1578
1579 status = osif_twt_pack_get_stats_resp_nlmsg(vdev, reply_skb, params,
1580 num_session_stats);
1581 if (QDF_IS_STATUS_ERROR(status)) {
1582 osif_err("Get stats - Failed to pack nl response");
1583 wlan_cfg80211_vendor_free_skb(reply_skb);
1584 return qdf_status_to_os_return(status);
1585 }
1586
1587 ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
1588 return qdf_status_from_os_return(ret);
1589 }
1590
1591