xref: /wlan-driver/qcacld-3.0/os_if/twt/src/osif_twt_ext_rsp.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
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 				 &params->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(&params.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 								    &params);
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 						&params[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