1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @brief File containing WiFi management operation implementations
9 * for the Zephyr OS.
10 */
11
12 #include <stdlib.h>
13
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16
17 #include "util.h"
18 #include "system/fmac_api.h"
19 #include "system/fmac_tx.h"
20 #include "common/fmac_util.h"
21 #include "fmac_main.h"
22 #include "wifi_mgmt.h"
23
24 LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
25
26 extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
27
nrf_wifi_set_power_save(const struct device * dev,struct wifi_ps_params * params)28 int nrf_wifi_set_power_save(const struct device *dev,
29 struct wifi_ps_params *params)
30 {
31 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
32 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
33 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
34 int ret = -1;
35 unsigned int uapsd_queue = UAPSD_Q_MIN; /* Legacy mode */
36
37 if (!dev || !params) {
38 LOG_ERR("%s: dev or params is NULL", __func__);
39 return ret;
40 }
41
42 vif_ctx_zep = dev->data;
43
44 if (!vif_ctx_zep) {
45 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
46 return ret;
47 }
48
49 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
50
51 if (!rpu_ctx_zep) {
52 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
53 return ret;
54 }
55
56 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
57 if (!rpu_ctx_zep->rpu_ctx) {
58 LOG_DBG("%s: RPU context not initialized", __func__);
59 goto out;
60 }
61
62 switch (params->type) {
63 case WIFI_PS_PARAM_LISTEN_INTERVAL:
64 if ((params->listen_interval <
65 NRF_WIFI_LISTEN_INTERVAL_MIN) ||
66 (params->listen_interval >
67 WIFI_LISTEN_INTERVAL_MAX)) {
68 params->fail_reason =
69 WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID;
70 return -EINVAL;
71 }
72 status = nrf_wifi_sys_fmac_set_listen_interval(
73 rpu_ctx_zep->rpu_ctx,
74 vif_ctx_zep->vif_idx,
75 params->listen_interval);
76 break;
77 case WIFI_PS_PARAM_TIMEOUT:
78 if ((vif_ctx_zep->if_type != NRF_WIFI_IFTYPE_STATION)
79 #ifdef CONFIG_NRF70_RAW_DATA_TX
80 && (vif_ctx_zep->if_type != NRF_WIFI_STA_TX_INJECTOR)
81 #endif /* CONFIG_NRF70_RAW_DATA_TX */
82 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
83 && (vif_ctx_zep->if_type != NRF_WIFI_STA_PROMISC_TX_INJECTOR)
84 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
85 ) {
86 LOG_ERR("%s: Operation supported only in STA enabled mode",
87 __func__);
88 params->fail_reason =
89 WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
90 goto out;
91 }
92
93 status = nrf_wifi_sys_fmac_set_power_save_timeout(
94 rpu_ctx_zep->rpu_ctx,
95 vif_ctx_zep->vif_idx,
96 params->timeout_ms);
97 break;
98 case WIFI_PS_PARAM_MODE:
99 if (params->mode == WIFI_PS_MODE_WMM) {
100 uapsd_queue = UAPSD_Q_MAX; /* WMM mode */
101 }
102
103 status = nrf_wifi_sys_fmac_set_uapsd_queue(rpu_ctx_zep->rpu_ctx,
104 vif_ctx_zep->vif_idx,
105 uapsd_queue);
106 break;
107 case WIFI_PS_PARAM_STATE:
108 status = nrf_wifi_sys_fmac_set_power_save(rpu_ctx_zep->rpu_ctx,
109 vif_ctx_zep->vif_idx,
110 params->enabled);
111 break;
112 case WIFI_PS_PARAM_WAKEUP_MODE:
113 status = nrf_wifi_sys_fmac_set_ps_wakeup_mode(
114 rpu_ctx_zep->rpu_ctx,
115 vif_ctx_zep->vif_idx,
116 params->wakeup_mode);
117 break;
118 case WIFI_PS_PARAM_EXIT_STRATEGY:
119 unsigned int exit_strategy;
120
121 if (params->exit_strategy == WIFI_PS_EXIT_EVERY_TIM) {
122 exit_strategy = EVERY_TIM;
123 } else if (params->exit_strategy == WIFI_PS_EXIT_CUSTOM_ALGO) {
124 exit_strategy = INT_PS;
125 } else {
126 params->fail_reason =
127 WIFI_PS_PARAM_FAIL_INVALID_EXIT_STRATEGY;
128 return -EINVAL;
129 }
130
131 status = nrf_wifi_sys_fmac_set_ps_exit_strategy(
132 rpu_ctx_zep->rpu_ctx,
133 vif_ctx_zep->vif_idx,
134 exit_strategy);
135 break;
136 default:
137 params->fail_reason =
138 WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
139 return -ENOTSUP;
140 }
141
142 if (status != NRF_WIFI_STATUS_SUCCESS) {
143 LOG_ERR("%s: Confiuring PS param %d failed",
144 __func__, params->type);
145 params->fail_reason =
146 WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
147 goto out;
148 }
149
150
151 ret = 0;
152 out:
153 k_mutex_unlock(&vif_ctx_zep->vif_lock);
154 return ret;
155 }
156
nrf_wifi_get_power_save_config(const struct device * dev,struct wifi_ps_config * ps_config)157 int nrf_wifi_get_power_save_config(const struct device *dev,
158 struct wifi_ps_config *ps_config)
159 {
160 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
161 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
162 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
163 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
164 int ret = -1;
165 int count = 0;
166
167 if (!dev || !ps_config) {
168 return ret;
169 }
170
171 vif_ctx_zep = dev->data;
172
173 if (!vif_ctx_zep) {
174 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
175 return ret;
176 }
177
178 if ((vif_ctx_zep->if_type != NRF_WIFI_IFTYPE_STATION)
179 #ifdef CONFIG_NRF70_RAW_DATA_TX
180 && (vif_ctx_zep->if_type != NRF_WIFI_STA_TX_INJECTOR)
181 #endif /* CONFIG_NRF70_RAW_DATA_TX */
182 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
183 && (vif_ctx_zep->if_type != NRF_WIFI_STA_PROMISC_TX_INJECTOR)
184 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
185 ) {
186 LOG_ERR("%s: Operation supported only in STA enabled mode",
187 __func__);
188 return ret;
189 }
190
191 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
192 if (!rpu_ctx_zep) {
193 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
194 return ret;
195 }
196
197 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
198 if (!rpu_ctx_zep->rpu_ctx) {
199 LOG_DBG("%s: RPU context not initialized", __func__);
200 goto out;
201 }
202
203 fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
204
205 if (!rpu_ctx_zep) {
206 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
207 goto out;
208 }
209
210 vif_ctx_zep->ps_info = ps_config;
211
212 vif_ctx_zep->ps_config_info_evnt = false;
213
214 status = nrf_wifi_sys_fmac_get_power_save_info(rpu_ctx_zep->rpu_ctx,
215 vif_ctx_zep->vif_idx);
216
217 if (status != NRF_WIFI_STATUS_SUCCESS) {
218 LOG_ERR("%s: nrf_wifi_sys_fmac_get_power_save_info failed",
219 __func__);
220 goto out;
221 }
222
223 do {
224 nrf_wifi_osal_sleep_ms(1);
225 count++;
226 } while ((vif_ctx_zep->ps_config_info_evnt == false) &&
227 (count < NRF_WIFI_FMAC_PS_CONF_EVNT_RECV_TIMEOUT));
228
229 if (count == NRF_WIFI_FMAC_PS_CONF_EVNT_RECV_TIMEOUT) {
230 nrf_wifi_osal_log_err("%s: Timed out",
231 __func__);
232 goto out;
233 }
234
235 ret = 0;
236 out:
237 k_mutex_unlock(&vif_ctx_zep->vif_lock);
238 return ret;
239 }
240
241 /* TWT interval conversion helpers: User <-> Protocol */
nrf_wifi_twt_us_to_float(uint32_t twt_interval)242 static struct twt_interval_float nrf_wifi_twt_us_to_float(uint32_t twt_interval)
243 {
244 double mantissa = 0.0;
245 int exponent = 0;
246 struct twt_interval_float twt_interval_fp;
247
248 double twt_interval_ms = twt_interval / 1000.0;
249
250 mantissa = frexp(twt_interval_ms, &exponent);
251 /* Ceiling and conversion to milli seconds */
252 twt_interval_fp.mantissa = ceil(mantissa * 1000);
253 twt_interval_fp.exponent = exponent;
254
255 return twt_interval_fp;
256 }
257
nrf_wifi_twt_float_to_us(struct twt_interval_float twt_interval_fp)258 static uint64_t nrf_wifi_twt_float_to_us(struct twt_interval_float twt_interval_fp)
259 {
260 /* Conversion to micro-seconds */
261 return floor(ldexp(twt_interval_fp.mantissa, twt_interval_fp.exponent) / (1000)) *
262 1000;
263 }
264
twt_wifi_mgmt_to_rpu_neg_type(enum wifi_twt_negotiation_type neg_type)265 static unsigned char twt_wifi_mgmt_to_rpu_neg_type(enum wifi_twt_negotiation_type neg_type)
266 {
267 unsigned char rpu_neg_type = 0;
268
269 switch (neg_type) {
270 case WIFI_TWT_INDIVIDUAL:
271 rpu_neg_type = NRF_WIFI_TWT_NEGOTIATION_TYPE_INDIVIDUAL;
272 break;
273 case WIFI_TWT_BROADCAST:
274 rpu_neg_type = NRF_WIFI_TWT_NEGOTIATION_TYPE_BROADCAST;
275 break;
276 default:
277 LOG_ERR("%s: Invalid negotiation type: %d",
278 __func__, neg_type);
279 break;
280 }
281
282 return rpu_neg_type;
283 }
284
twt_rpu_to_wifi_mgmt_neg_type(unsigned char neg_type)285 static enum wifi_twt_negotiation_type twt_rpu_to_wifi_mgmt_neg_type(unsigned char neg_type)
286 {
287 enum wifi_twt_negotiation_type wifi_neg_type = WIFI_TWT_INDIVIDUAL;
288
289 switch (neg_type) {
290 case NRF_WIFI_TWT_NEGOTIATION_TYPE_INDIVIDUAL:
291 wifi_neg_type = WIFI_TWT_INDIVIDUAL;
292 break;
293 case NRF_WIFI_TWT_NEGOTIATION_TYPE_BROADCAST:
294 wifi_neg_type = WIFI_TWT_BROADCAST;
295 break;
296 default:
297 LOG_ERR("%s: Invalid negotiation type: %d",
298 __func__, neg_type);
299 break;
300 }
301
302 return wifi_neg_type;
303 }
304
305 /* Though setup_cmd enums have 1-1 mapping but due to data type different need these */
twt_rpu_to_wifi_mgmt_setup_cmd(signed int setup_cmd)306 static enum wifi_twt_setup_cmd twt_rpu_to_wifi_mgmt_setup_cmd(signed int setup_cmd)
307 {
308 enum wifi_twt_setup_cmd wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
309
310 switch (setup_cmd) {
311 case NRF_WIFI_REQUEST_TWT:
312 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
313 break;
314 case NRF_WIFI_SUGGEST_TWT:
315 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_SUGGEST;
316 break;
317 case NRF_WIFI_DEMAND_TWT:
318 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_DEMAND;
319 break;
320 case NRF_WIFI_GROUPING_TWT:
321 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_GROUPING;
322 break;
323 case NRF_WIFI_ACCEPT_TWT:
324 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_ACCEPT;
325 break;
326 case NRF_WIFI_ALTERNATE_TWT:
327 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_ALTERNATE;
328 break;
329 case NRF_WIFI_DICTATE_TWT:
330 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_DICTATE;
331 break;
332 case NRF_WIFI_REJECT_TWT:
333 wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REJECT;
334 break;
335 default:
336 LOG_ERR("%s: Invalid setup command: %d",
337 __func__, setup_cmd);
338 break;
339 }
340
341 return wifi_setup_cmd;
342 }
343
twt_wifi_mgmt_to_rpu_setup_cmd(enum wifi_twt_setup_cmd setup_cmd)344 static signed int twt_wifi_mgmt_to_rpu_setup_cmd(enum wifi_twt_setup_cmd setup_cmd)
345 {
346 signed int rpu_setup_cmd = NRF_WIFI_REQUEST_TWT;
347
348 switch (setup_cmd) {
349 case WIFI_TWT_SETUP_CMD_REQUEST:
350 rpu_setup_cmd = NRF_WIFI_REQUEST_TWT;
351 break;
352 case WIFI_TWT_SETUP_CMD_SUGGEST:
353 rpu_setup_cmd = NRF_WIFI_SUGGEST_TWT;
354 break;
355 case WIFI_TWT_SETUP_CMD_DEMAND:
356 rpu_setup_cmd = NRF_WIFI_DEMAND_TWT;
357 break;
358 case WIFI_TWT_SETUP_CMD_GROUPING:
359 rpu_setup_cmd = NRF_WIFI_GROUPING_TWT;
360 break;
361 case WIFI_TWT_SETUP_CMD_ACCEPT:
362 rpu_setup_cmd = NRF_WIFI_ACCEPT_TWT;
363 break;
364 case WIFI_TWT_SETUP_CMD_ALTERNATE:
365 rpu_setup_cmd = NRF_WIFI_ALTERNATE_TWT;
366 break;
367 case WIFI_TWT_SETUP_CMD_DICTATE:
368 rpu_setup_cmd = NRF_WIFI_DICTATE_TWT;
369 break;
370 case WIFI_TWT_SETUP_CMD_REJECT:
371 rpu_setup_cmd = NRF_WIFI_REJECT_TWT;
372 break;
373 default:
374 LOG_ERR("%s: Invalid setup command: %d",
375 __func__, setup_cmd);
376 break;
377 }
378
379 return rpu_setup_cmd;
380 }
381
nrf_wifi_event_proc_get_power_save_info(void * vif_ctx,struct nrf_wifi_umac_event_power_save_info * ps_info,unsigned int event_len)382 void nrf_wifi_event_proc_get_power_save_info(void *vif_ctx,
383 struct nrf_wifi_umac_event_power_save_info *ps_info,
384 unsigned int event_len)
385 {
386 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
387
388 if (!vif_ctx || !ps_info) {
389 return;
390 }
391
392 vif_ctx_zep = vif_ctx;
393
394 vif_ctx_zep->ps_info->ps_params.mode = ps_info->ps_mode;
395 vif_ctx_zep->ps_info->ps_params.enabled = ps_info->enabled;
396 vif_ctx_zep->ps_info->num_twt_flows = ps_info->num_twt_flows;
397 vif_ctx_zep->ps_info->ps_params.timeout_ms = ps_info->ps_timeout;
398 vif_ctx_zep->ps_info->ps_params.listen_interval = ps_info->listen_interval;
399 vif_ctx_zep->ps_info->ps_params.wakeup_mode = ps_info->extended_ps;
400 if (ps_info->ps_exit_strategy == EVERY_TIM) {
401 vif_ctx_zep->ps_info->ps_params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM;
402 } else if (ps_info->ps_exit_strategy == INT_PS) {
403 vif_ctx_zep->ps_info->ps_params.exit_strategy = WIFI_PS_EXIT_CUSTOM_ALGO;
404 }
405
406 for (int i = 0; i < ps_info->num_twt_flows; i++) {
407 struct twt_interval_float twt_interval_fp;
408 struct wifi_twt_flow_info *twt_zep = &vif_ctx_zep->ps_info->twt_flows[i];
409 struct nrf_wifi_umac_config_twt_info *twt_rpu = &ps_info->twt_flow_info[i];
410
411 memset(twt_zep, 0, sizeof(struct wifi_twt_flow_info));
412
413 twt_zep->flow_id = twt_rpu->twt_flow_id;
414 twt_zep->implicit = twt_rpu->is_implicit ? 1 : 0;
415 twt_zep->trigger = twt_rpu->ap_trigger_frame ? 1 : 0;
416 twt_zep->announce = twt_rpu->twt_flow_type == NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED;
417 twt_zep->negotiation_type = twt_rpu_to_wifi_mgmt_neg_type(twt_rpu->neg_type);
418 twt_zep->dialog_token = twt_rpu->dialog_token;
419 twt_interval_fp.mantissa = twt_rpu->twt_target_wake_interval_mantissa;
420 twt_interval_fp.exponent = twt_rpu->twt_target_wake_interval_exponent;
421 twt_zep->twt_interval = nrf_wifi_twt_float_to_us(twt_interval_fp);
422 twt_zep->twt_wake_interval = twt_rpu->nominal_min_twt_wake_duration;
423 }
424
425 vif_ctx_zep->ps_config_info_evnt = true;
426 }
427
nrf_wifi_twt_update_internal_state(struct nrf_wifi_vif_ctx_zep * vif_ctx_zep,bool setup,unsigned char flow_id)428 static void nrf_wifi_twt_update_internal_state(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep,
429 bool setup, unsigned char flow_id)
430 {
431 if (setup) {
432 vif_ctx_zep->twt_flows_map |= BIT(flow_id);
433 vif_ctx_zep->twt_flow_in_progress_map &= ~BIT(flow_id);
434 } else {
435 vif_ctx_zep->twt_flows_map &= ~BIT(flow_id);
436 }
437 }
438
nrf_wifi_twt_teardown_flows(struct nrf_wifi_vif_ctx_zep * vif_ctx_zep,unsigned char start_flow_id,unsigned char end_flow_id)439 int nrf_wifi_twt_teardown_flows(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep,
440 unsigned char start_flow_id, unsigned char end_flow_id)
441 {
442 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
443 struct nrf_wifi_umac_config_twt_info twt_info = {0};
444 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
445 int ret = 0;
446 struct wifi_twt_params twt_params = {0};
447
448 if (!vif_ctx_zep) {
449 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
450 return ret;
451 }
452
453 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
454
455 if (!rpu_ctx_zep) {
456 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
457 return ret;
458 }
459
460 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
461 if (!rpu_ctx_zep->rpu_ctx) {
462 LOG_DBG("%s: RPU context not initialized", __func__);
463 goto out;
464 }
465
466 for (int flow_id = start_flow_id; flow_id < end_flow_id; flow_id++) {
467 if (!(vif_ctx_zep->twt_flows_map & BIT(flow_id))) {
468 continue;
469 }
470 twt_info.twt_flow_id = flow_id;
471 status = nrf_wifi_sys_fmac_twt_teardown(rpu_ctx_zep->rpu_ctx,
472 vif_ctx_zep->vif_idx,
473 &twt_info);
474 if (status != NRF_WIFI_STATUS_SUCCESS) {
475 LOG_ERR("%s: TWT teardown for flow id %d failed",
476 __func__, flow_id);
477 ret = -1;
478 continue;
479 }
480 /* UMAC doesn't send TWT teardown event for host initiated teardown */
481 nrf_wifi_twt_update_internal_state(vif_ctx_zep, false, flow_id);
482 /* TODO: Remove this once UMAC sends the status */
483 twt_params.operation = WIFI_TWT_TEARDOWN;
484 twt_params.flow_id = flow_id;
485 twt_params.teardown_status = WIFI_TWT_TEARDOWN_SUCCESS;
486 wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params);
487 }
488
489 out:
490 k_mutex_unlock(&vif_ctx_zep->vif_lock);
491 return ret;
492 }
493
nrf_wifi_set_twt(const struct device * dev,struct wifi_twt_params * twt_params)494 int nrf_wifi_set_twt(const struct device *dev,
495 struct wifi_twt_params *twt_params)
496 {
497 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
498 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
499 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
500 struct nrf_wifi_umac_config_twt_info twt_info = {0};
501 int ret = -1;
502
503 if (!dev || !twt_params) {
504 LOG_ERR("%s: dev or twt_params is NULL", __func__);
505 return ret;
506 }
507
508 vif_ctx_zep = dev->data;
509
510 if (!vif_ctx_zep) {
511 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
512 return ret;
513 }
514
515 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
516
517 if (!rpu_ctx_zep) {
518 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
519 return ret;
520 }
521
522 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
523 if (!rpu_ctx_zep->rpu_ctx) {
524 LOG_DBG("%s: RPU context not initialized", __func__);
525 goto out;
526 }
527
528 if (!(twt_params->operation == WIFI_TWT_TEARDOWN && twt_params->teardown.teardown_all) &&
529 twt_params->flow_id >= WIFI_MAX_TWT_FLOWS) {
530 LOG_ERR("%s: Invalid flow id: %d",
531 __func__, twt_params->flow_id);
532 twt_params->fail_reason = WIFI_TWT_FAIL_INVALID_FLOW_ID;
533 goto out;
534 }
535
536 switch (twt_params->operation) {
537 case WIFI_TWT_SETUP:
538 if (vif_ctx_zep->twt_flow_in_progress_map & BIT(twt_params->flow_id)) {
539 twt_params->fail_reason = WIFI_TWT_FAIL_OPERATION_IN_PROGRESS;
540 goto out;
541 }
542
543 if (twt_params->setup_cmd == WIFI_TWT_SETUP_CMD_REQUEST) {
544 if (vif_ctx_zep->twt_flows_map & BIT(twt_params->flow_id)) {
545 twt_params->fail_reason = WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS;
546 goto out;
547 }
548 }
549
550 struct twt_interval_float twt_interval_fp =
551 nrf_wifi_twt_us_to_float(twt_params->setup.twt_interval);
552
553 twt_info.twt_flow_id = twt_params->flow_id;
554 twt_info.neg_type = twt_wifi_mgmt_to_rpu_neg_type(twt_params->negotiation_type);
555 twt_info.setup_cmd = twt_wifi_mgmt_to_rpu_setup_cmd(twt_params->setup_cmd);
556 twt_info.ap_trigger_frame = twt_params->setup.trigger;
557 twt_info.is_implicit = twt_params->setup.implicit;
558 if (twt_params->setup.announce) {
559 twt_info.twt_flow_type = NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED;
560 } else {
561 twt_info.twt_flow_type = NRF_WIFI_TWT_FLOW_TYPE_UNANNOUNCED;
562 }
563
564 twt_info.nominal_min_twt_wake_duration =
565 twt_params->setup.twt_wake_interval;
566 twt_info.twt_target_wake_interval_mantissa = twt_interval_fp.mantissa;
567 twt_info.twt_target_wake_interval_exponent = twt_interval_fp.exponent;
568
569 twt_info.dialog_token = twt_params->dialog_token;
570 twt_info.twt_wake_ahead_duration = twt_params->setup.twt_wake_ahead_duration;
571
572 status = nrf_wifi_sys_fmac_twt_setup(rpu_ctx_zep->rpu_ctx,
573 vif_ctx_zep->vif_idx,
574 &twt_info);
575
576 break;
577 case WIFI_TWT_TEARDOWN:
578 unsigned char start_flow_id = 0;
579 unsigned char end_flow_id = WIFI_MAX_TWT_FLOWS;
580
581 if (!twt_params->teardown.teardown_all) {
582 if (!(vif_ctx_zep->twt_flows_map & BIT(twt_params->flow_id))) {
583 twt_params->fail_reason = WIFI_TWT_FAIL_INVALID_FLOW_ID;
584 goto out;
585 }
586 start_flow_id = twt_params->flow_id;
587 end_flow_id = twt_params->flow_id + 1;
588 twt_info.twt_flow_id = twt_params->flow_id;
589 }
590
591 status = nrf_wifi_twt_teardown_flows(vif_ctx_zep,
592 start_flow_id,
593 end_flow_id);
594 if (status != NRF_WIFI_STATUS_SUCCESS) {
595 LOG_ERR("%s: TWT teardown failed: start_flow_id: %d, end_flow_id: %d",
596 __func__, start_flow_id, end_flow_id);
597 goto out;
598 }
599 break;
600
601 default:
602 LOG_ERR("Unknown TWT operation");
603 status = NRF_WIFI_STATUS_FAIL;
604 break;
605 }
606
607 if (status != NRF_WIFI_STATUS_SUCCESS) {
608 LOG_ERR("%s: Failed", __func__);
609 goto out;
610 }
611
612 ret = 0;
613 out:
614 k_mutex_unlock(&vif_ctx_zep->vif_lock);
615 return ret;
616 }
617
nrf_wifi_event_proc_twt_setup_zep(void * vif_ctx,struct nrf_wifi_umac_cmd_config_twt * twt_setup_info,unsigned int event_len)618 void nrf_wifi_event_proc_twt_setup_zep(void *vif_ctx,
619 struct nrf_wifi_umac_cmd_config_twt *twt_setup_info,
620 unsigned int event_len)
621 {
622 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
623 struct wifi_twt_params twt_params = { 0 };
624 struct twt_interval_float twt_interval_fp = { 0 };
625
626 if (!vif_ctx || !twt_setup_info) {
627 return;
628 }
629
630 vif_ctx_zep = vif_ctx;
631
632 twt_params.operation = WIFI_TWT_SETUP;
633 twt_params.flow_id = twt_setup_info->info.twt_flow_id;
634 twt_params.negotiation_type = twt_rpu_to_wifi_mgmt_neg_type(twt_setup_info->info.neg_type);
635 twt_params.setup_cmd = twt_rpu_to_wifi_mgmt_setup_cmd(twt_setup_info->info.setup_cmd);
636 twt_params.setup.trigger = twt_setup_info->info.ap_trigger_frame ? 1 : 0;
637 twt_params.setup.implicit = twt_setup_info->info.is_implicit ? 1 : 0;
638 twt_params.setup.announce =
639 twt_setup_info->info.twt_flow_type == NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED;
640 twt_params.setup.twt_wake_interval =
641 twt_setup_info->info.nominal_min_twt_wake_duration;
642 twt_interval_fp.mantissa = twt_setup_info->info.twt_target_wake_interval_mantissa;
643 twt_interval_fp.exponent = twt_setup_info->info.twt_target_wake_interval_exponent;
644 twt_params.setup.twt_interval = nrf_wifi_twt_float_to_us(twt_interval_fp);
645 twt_params.dialog_token = twt_setup_info->info.dialog_token;
646 twt_params.resp_status = twt_setup_info->info.twt_resp_status;
647
648 if ((twt_setup_info->info.twt_resp_status == 0) ||
649 (twt_setup_info->info.neg_type == NRF_WIFI_ACCEPT_TWT)) {
650 nrf_wifi_twt_update_internal_state(vif_ctx_zep, true, twt_params.flow_id);
651 }
652
653 wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params);
654 }
655
656
nrf_wifi_event_proc_twt_teardown_zep(void * vif_ctx,struct nrf_wifi_umac_cmd_teardown_twt * twt_teardown_info,unsigned int event_len)657 void nrf_wifi_event_proc_twt_teardown_zep(void *vif_ctx,
658 struct nrf_wifi_umac_cmd_teardown_twt *twt_teardown_info,
659 unsigned int event_len)
660 {
661 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
662 struct wifi_twt_params twt_params = {0};
663
664 if (!vif_ctx || !twt_teardown_info) {
665 return;
666 }
667
668 vif_ctx_zep = vif_ctx;
669
670 twt_params.operation = WIFI_TWT_TEARDOWN;
671 twt_params.flow_id = twt_teardown_info->info.twt_flow_id;
672 /* TODO: ADD reason code in the twt_params structure */
673 nrf_wifi_twt_update_internal_state(vif_ctx_zep, false, twt_params.flow_id);
674
675 wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params);
676 }
677
nrf_wifi_event_proc_twt_sleep_zep(void * vif_ctx,struct nrf_wifi_umac_event_twt_sleep * sleep_evnt,unsigned int event_len)678 void nrf_wifi_event_proc_twt_sleep_zep(void *vif_ctx,
679 struct nrf_wifi_umac_event_twt_sleep *sleep_evnt,
680 unsigned int event_len)
681 {
682 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
683 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
684 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
685 struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
686 struct nrf_wifi_sys_fmac_priv *sys_fpriv = NULL;
687 #ifdef CONFIG_NRF70_DATA_TX
688 int desc = 0;
689 int ac = 0;
690 #endif
691 vif_ctx_zep = vif_ctx;
692
693 if (!vif_ctx_zep) {
694 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
695 return;
696 }
697
698 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
699 if (!rpu_ctx_zep) {
700 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
701 return;
702 }
703
704 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
705 if (!rpu_ctx_zep->rpu_ctx) {
706 LOG_DBG("%s: RPU context not initialized", __func__);
707 goto out;
708 }
709
710 fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
711 sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
712 sys_fpriv = wifi_fmac_priv(fmac_dev_ctx->fpriv);
713
714 if (!sleep_evnt) {
715 LOG_ERR("%s: sleep_evnt is NULL", __func__);
716 return;
717 }
718
719 switch (sleep_evnt->info.type) {
720 case TWT_BLOCK_TX:
721 nrf_wifi_osal_spinlock_take(sys_dev_ctx->tx_config.tx_lock);
722
723 sys_dev_ctx->twt_sleep_status = NRF_WIFI_FMAC_TWT_STATE_SLEEP;
724
725 wifi_mgmt_raise_twt_sleep_state(vif_ctx_zep->zep_net_if_ctx,
726 WIFI_TWT_STATE_SLEEP);
727 nrf_wifi_osal_spinlock_rel(sys_dev_ctx->tx_config.tx_lock);
728 break;
729 case TWT_UNBLOCK_TX:
730 nrf_wifi_osal_spinlock_take(sys_dev_ctx->tx_config.tx_lock);
731 sys_dev_ctx->twt_sleep_status = NRF_WIFI_FMAC_TWT_STATE_AWAKE;
732 wifi_mgmt_raise_twt_sleep_state(vif_ctx_zep->zep_net_if_ctx,
733 WIFI_TWT_STATE_AWAKE);
734 #ifdef CONFIG_NRF70_DATA_TX
735 for (ac = NRF_WIFI_FMAC_AC_BE;
736 ac <= NRF_WIFI_FMAC_AC_MAX; ++ac) {
737 desc = tx_desc_get(fmac_dev_ctx, ac);
738 if (desc < sys_fpriv->num_tx_tokens) {
739 tx_pending_process(fmac_dev_ctx, desc, ac);
740 }
741 }
742 #endif
743 nrf_wifi_osal_spinlock_rel(sys_dev_ctx->tx_config.tx_lock);
744 break;
745 default:
746 break;
747 }
748 out:
749 k_mutex_unlock(&vif_ctx_zep->vif_lock);
750 }
751
752 #ifdef CONFIG_NRF70_SYSTEM_WITH_RAW_MODES
nrf_wifi_mode(const struct device * dev,struct wifi_mode_info * mode)753 int nrf_wifi_mode(const struct device *dev,
754 struct wifi_mode_info *mode)
755 {
756 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
757 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
758 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
759 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
760 struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
761 int ret = -1;
762
763 if (!dev || !mode) {
764 LOG_ERR("%s: illegal input parameters", __func__);
765 return ret;
766 }
767
768 vif_ctx_zep = dev->data;
769 if (!vif_ctx_zep) {
770 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
771 return ret;
772 }
773
774 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
775 if (!rpu_ctx_zep) {
776 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
777 return ret;
778 }
779
780 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
781 if (!rpu_ctx_zep->rpu_ctx) {
782 LOG_DBG("%s: RPU context not initialized", __func__);
783 goto out;
784 }
785
786 fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
787 sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
788
789 if (!device_is_ready(dev)) {
790 LOG_ERR("%s: Device %s is not ready",
791 __func__, dev->name);
792 goto out;
793 }
794
795 if (mode->oper == WIFI_MGMT_SET) {
796 status = nrf_wifi_check_mode_validity(mode->mode);
797 if (status != NRF_WIFI_STATUS_SUCCESS) {
798 LOG_ERR("%s: mode setting is not valid", __func__);
799 goto out;
800 }
801
802 if (vif_ctx_zep->authorized && (mode->mode == NRF_WIFI_MONITOR_MODE)) {
803 LOG_ERR("%s: Cannot set monitor mode when station is connected",
804 __func__);
805 goto out;
806 }
807
808 /**
809 * Send the driver vif_idx instead of upper layer sent if_index.
810 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
811 * context maps the correct network interface index to current driver
812 * interface index.
813 */
814 status = nrf_wifi_sys_fmac_set_mode(rpu_ctx_zep->rpu_ctx,
815 vif_ctx_zep->vif_idx,
816 mode->mode);
817 if (status != NRF_WIFI_STATUS_SUCCESS) {
818 LOG_ERR("%s: mode set operation failed", __func__);
819 goto out;
820 }
821
822 } else {
823 mode->mode = sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode;
824 /**
825 * This is a work-around to handle current UMAC mode handling.
826 * This might be removed in future versions when UMAC has more space.
827 */
828 #ifdef CONFIG_NRF70_RAW_DATA_TX
829 if (sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->txinjection_mode == true) {
830 mode->mode ^= NRF_WIFI_TX_INJECTION_MODE;
831 }
832 #endif /* CONFIG_NRF70_RAW_DATA_TX */
833 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
834 if (sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->promisc_mode == true) {
835 mode->mode ^= NRF_WIFI_PROMISCUOUS_MODE;
836 }
837 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
838 }
839 ret = 0;
840 out:
841 k_mutex_unlock(&vif_ctx_zep->vif_lock);
842 return ret;
843 }
844 #endif /* CONFIG_NRF70_SYSTEM_WITH_RAW_MODES */
845
846 #if defined(CONFIG_NRF70_RAW_DATA_TX) || defined(CONFIG_NRF70_RAW_DATA_RX)
nrf_wifi_channel(const struct device * dev,struct wifi_channel_info * channel)847 int nrf_wifi_channel(const struct device *dev,
848 struct wifi_channel_info *channel)
849 {
850 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
851 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
852 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
853 struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
854 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
855 int ret = -1;
856
857 if (!dev || !channel) {
858 LOG_ERR("%s: illegal input parameters", __func__);
859 return ret;
860 }
861
862 vif_ctx_zep = dev->data;
863 if (!vif_ctx_zep) {
864 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
865 return ret;
866 }
867
868 if (vif_ctx_zep->authorized) {
869 LOG_ERR("%s: Cannot change channel when in station connected mode", __func__);
870 return ret;
871 }
872
873 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
874 if (!rpu_ctx_zep) {
875 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
876 return ret;
877 }
878
879 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
880 if (!rpu_ctx_zep->rpu_ctx) {
881 LOG_DBG("%s: RPU context not initialized", __func__);
882 goto out;
883 }
884
885 fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
886 sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
887
888 if (channel->oper == WIFI_MGMT_SET) {
889 /**
890 * Send the driver vif_idx instead of upper layer sent if_index.
891 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
892 * context maps the correct network interface index to current driver
893 * interface index.
894 */
895 status = nrf_wifi_sys_fmac_set_channel(rpu_ctx_zep->rpu_ctx,
896 vif_ctx_zep->vif_idx,
897 channel->channel);
898
899 if (status != NRF_WIFI_STATUS_SUCCESS) {
900 LOG_ERR("%s: set channel failed", __func__);
901 goto out;
902 }
903 } else {
904 channel->channel = sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->channel;
905 }
906 ret = 0;
907 out:
908 k_mutex_unlock(&vif_ctx_zep->vif_lock);
909 return ret;
910 }
911 #endif /* CONFIG_NRF70_RAW_DATA_TX || CONFIG_NRF70_RAW_DATA_RX */
912
913 #if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
nrf_wifi_filter(const struct device * dev,struct wifi_filter_info * filter)914 int nrf_wifi_filter(const struct device *dev,
915 struct wifi_filter_info *filter)
916 {
917 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
918 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
919 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
920 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
921 struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
922 int ret = -1;
923
924 if (!dev || !filter) {
925 LOG_ERR("%s: Illegal input parameters", __func__);
926 goto out;
927 }
928
929 vif_ctx_zep = dev->data;
930 if (!vif_ctx_zep) {
931 LOG_ERR("%s: vif_ctx_zep is NULL\n", __func__);
932 goto out;
933 }
934
935 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
936 fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
937 sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
938
939 if (filter->oper == WIFI_MGMT_SET) {
940 /**
941 * If promiscuous mode is enabled, filter settings
942 * cannot be plumbed to the lower layers as that might
943 * affect connectivity. Save the filter settings in the
944 * driver and filter packet type on packet receive by
945 * checking the 802.11 header in the packet
946 */
947 if (((sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) &
948 (NRF_WIFI_PROMISCUOUS_MODE)) == NRF_WIFI_PROMISCUOUS_MODE) {
949 sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter =
950 filter->filter;
951 ret = 0;
952 goto out;
953 }
954
955 /**
956 * In case a user sets data + management + ctrl bits
957 * or all the filter bits. Map it to bit 0 set to
958 * enable "all" packet filter bit setting.
959 * In case only filter packet size is configured and filter
960 * setting is sent as zero, set the filter value to
961 * previously configured value.
962 */
963 if (filter->filter == WIFI_MGMT_DATA_CTRL_FILTER_SETTING
964 || filter->filter == WIFI_ALL_FILTER_SETTING) {
965 filter->filter = 1;
966 } else if (filter->filter == 0) {
967 filter->filter =
968 sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter;
969 }
970
971 /**
972 * Send the driver vif_idx instead of upper layer sent if_index.
973 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
974 * context maps the correct network interface index to current driver
975 * interface index
976 */
977 status = nrf_wifi_sys_fmac_set_packet_filter(rpu_ctx_zep->rpu_ctx,
978 filter->filter,
979 vif_ctx_zep->vif_idx,
980 filter->buffer_size);
981 if (status != NRF_WIFI_STATUS_SUCCESS) {
982 LOG_ERR("%s: Set filter operation failed\n", __func__);
983 goto out;
984 }
985 } else {
986 filter->filter = sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter;
987 }
988 ret = 0;
989 out:
990 return ret;
991 }
992 #endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
993
nrf_wifi_set_rts_threshold(const struct device * dev,unsigned int rts_threshold)994 int nrf_wifi_set_rts_threshold(const struct device *dev,
995 unsigned int rts_threshold)
996 {
997 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
998 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
999 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
1000 struct nrf_wifi_umac_set_wiphy_info wiphy_info;
1001 int ret = -1;
1002
1003 if (!dev) {
1004 LOG_ERR("%s: dev is NULL", __func__);
1005 return ret;
1006 }
1007
1008 vif_ctx_zep = dev->data;
1009
1010 if (!vif_ctx_zep) {
1011 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
1012 return ret;
1013 }
1014
1015 rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
1016
1017 if (!rpu_ctx_zep) {
1018 LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
1019 return ret;
1020 }
1021
1022
1023 if (!rpu_ctx_zep->rpu_ctx) {
1024 LOG_ERR("%s: RPU context not initialized", __func__);
1025 return ret;
1026 }
1027
1028 if ((int)rts_threshold < -1) {
1029 /* 0 or any positive value is passed to f/w.
1030 * For RTS off, -1 is passed to f/w.
1031 * All other negative values considered as invalid.
1032 */
1033 LOG_ERR("%s: Invalid threshold value : %d", __func__, (int)rts_threshold);
1034 return ret;
1035 }
1036
1037 memset(&wiphy_info, 0, sizeof(struct nrf_wifi_umac_set_wiphy_info));
1038
1039 wiphy_info.rts_threshold = (int)rts_threshold;
1040
1041 k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
1042
1043 status = nrf_wifi_sys_fmac_set_wiphy_params(rpu_ctx_zep->rpu_ctx,
1044 vif_ctx_zep->vif_idx,
1045 &wiphy_info);
1046
1047 if (status != NRF_WIFI_STATUS_SUCCESS) {
1048 LOG_ERR("%s: Configuring rts threshold failed\n", __func__);
1049 goto out;
1050 }
1051
1052 vif_ctx_zep->rts_threshold_value = (int)rts_threshold;
1053
1054 ret = 0;
1055 out:
1056 k_mutex_unlock(&vif_ctx_zep->vif_lock);
1057
1058 return ret;
1059 }
1060
nrf_wifi_get_rts_threshold(const struct device * dev,unsigned int * rts_threshold)1061 int nrf_wifi_get_rts_threshold(const struct device *dev,
1062 unsigned int *rts_threshold)
1063 {
1064 struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
1065 int ret = -1;
1066
1067 if (!dev) {
1068 LOG_ERR("%s: dev is NULL", __func__);
1069 return ret;
1070 }
1071
1072 vif_ctx_zep = dev->data;
1073 if (!vif_ctx_zep) {
1074 LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
1075 return ret;
1076 }
1077
1078 *rts_threshold = vif_ctx_zep->rts_threshold_value;
1079 ret = 0;
1080
1081 return ret;
1082 }
1083