1 /*
2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: wlan_hdd_nan_datapath.c
22 *
23 * WLAN Host Device Driver nan datapath API implementation
24 */
25 #include <wlan_hdd_includes.h>
26 #include <linux/if.h>
27 #include <linux/netdevice.h>
28 #include <linux/skbuff.h>
29 #include <linux/etherdevice.h>
30 #include "wlan_hdd_includes.h"
31 #include "wlan_hdd_p2p.h"
32 #include "osif_sync.h"
33 #include "wma_api.h"
34 #include "wlan_hdd_assoc.h"
35 #include "sme_nan_datapath.h"
36 #include "wlan_hdd_object_manager.h"
37 #include <qca_vendor.h>
38 #include "os_if_nan.h"
39 #include "wlan_nan_api.h"
40 #include "nan_public_structs.h"
41 #include "cfg_nan_api.h"
42 #include "wlan_mlme_ucfg_api.h"
43 #include "qdf_util.h"
44 #include "qdf_net_if.h"
45 #include <cdp_txrx_misc.h>
46 #include "wlan_fwol_ucfg_api.h"
47 #include "wlan_dp_ucfg_api.h"
48 #include "wlan_hdd_sysfs.h"
49 #include "wlan_hdd_stats.h"
50
51 /**
52 * hdd_nan_datapath_target_config() - Configure NAN datapath features
53 * @hdd_ctx: Pointer to HDD context
54 * @tgt_cfg: Pointer to target device capability information
55 *
56 * NAN datapath functionality is enabled if it is enabled in
57 * .ini file and also supported on target device.
58 *
59 * Return: None
60 */
hdd_nan_datapath_target_config(struct hdd_context * hdd_ctx,struct wma_tgt_cfg * tgt_cfg)61 void hdd_nan_datapath_target_config(struct hdd_context *hdd_ctx,
62 struct wma_tgt_cfg *tgt_cfg)
63 {
64 hdd_ctx->nan_datapath_enabled =
65 cfg_nan_get_datapath_enable(hdd_ctx->psoc) &&
66 tgt_cfg->nan_datapath_enabled;
67 hdd_debug("NAN Datapath Enable: %d (Host: %d FW: %d)",
68 hdd_ctx->nan_datapath_enabled,
69 cfg_nan_get_datapath_enable(hdd_ctx->psoc),
70 tgt_cfg->nan_datapath_enabled);
71 }
72
73 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
74 /**
75 * hdd_close_ndi_adapter() - close the adapter
76 * @hdd_ctx: pointer to HDD context
77 * @adapter: adapter context
78 * @value: true or false
79 *
80 * Returns: void
81 */
hdd_close_ndi_adapter(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,bool value)82 static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx,
83 struct hdd_adapter *adapter, bool value)
84 {
85 }
86 #else
hdd_close_ndi_adapter(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,bool value)87 static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx,
88 struct hdd_adapter *adapter, bool value)
89 {
90 hdd_close_adapter(hdd_ctx, adapter, value);
91 }
92 #endif
93
94 /**
95 * hdd_close_ndi() - close NAN Data interface
96 * @adapter: adapter context
97 *
98 * Close the adapter if start BSS fails
99 *
100 * Returns: 0 on success, negative error code otherwise
101 */
hdd_close_ndi(struct hdd_adapter * adapter)102 static int hdd_close_ndi(struct hdd_adapter *adapter)
103 {
104 int errno;
105 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
106
107 hdd_enter();
108
109 /* check if the adapter is in NAN Data mode */
110 if (QDF_NDI_MODE != adapter->device_mode) {
111 hdd_err("Interface is not in NDI mode");
112 return -EINVAL;
113 }
114 wlan_hdd_netif_queue_control(adapter,
115 WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
116 WLAN_CONTROL_PATH);
117
118 hdd_cancel_ip_notifier_work(adapter);
119 hdd_adapter_deregister_fc(adapter);
120
121 errno = hdd_vdev_destroy(adapter->deflink);
122 if (errno)
123 hdd_err("failed to destroy vdev: %d", errno);
124
125 adapter->is_virtual_iface = true;
126 /* We are good to close the adapter */
127 hdd_close_ndi_adapter(hdd_ctx, adapter, true);
128
129 hdd_exit();
130 return 0;
131 }
132
133 /**
134 * hdd_is_ndp_allowed() - Indicates if NDP is allowed
135 * @hdd_ctx: hdd context
136 *
137 * NDP is not allowed with any other role active except STA.
138 *
139 * Return: true if allowed, false otherwise
140 */
141 #ifdef NDP_SAP_CONCURRENCY_ENABLE
hdd_is_ndp_allowed(struct hdd_context * hdd_ctx)142 static bool hdd_is_ndp_allowed(struct hdd_context *hdd_ctx)
143 {
144 struct hdd_adapter *adapter, *next_adapter = NULL;
145 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_NDP_ALLOWED;
146 struct wlan_hdd_link_info *link_info;
147
148 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
149 dbgid) {
150 hdd_adapter_for_each_active_link_info(adapter, link_info) {
151 switch (adapter->device_mode) {
152 case QDF_P2P_GO_MODE:
153 if (test_bit(SOFTAP_BSS_STARTED,
154 &link_info->link_flags)) {
155 hdd_adapter_dev_put_debug(adapter,
156 dbgid);
157 if (next_adapter)
158 hdd_adapter_dev_put_debug(
159 next_adapter,
160 dbgid);
161 return false;
162 }
163 break;
164 case QDF_P2P_CLIENT_MODE:
165 if (hdd_cm_is_vdev_associated(link_info) ||
166 hdd_cm_is_connecting(link_info)) {
167 hdd_adapter_dev_put_debug(adapter,
168 dbgid);
169 if (next_adapter)
170 hdd_adapter_dev_put_debug(
171 next_adapter,
172 dbgid);
173 return false;
174 }
175 break;
176 default:
177 break;
178 }
179 }
180 hdd_adapter_dev_put_debug(adapter, dbgid);
181 }
182
183 return true;
184 }
185 #else
hdd_is_ndp_allowed(struct hdd_context * hdd_ctx)186 static bool hdd_is_ndp_allowed(struct hdd_context *hdd_ctx)
187 {
188 struct hdd_adapter *adapter, *next_adapter = NULL;
189 wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_NDP_ALLOWED;
190 struct wlan_hdd_link_info *link_info;
191
192 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
193 dbgid) {
194 hdd_adapter_for_each_active_link_info(adapter, link_info) {
195 switch (adapter->device_mode) {
196 case QDF_P2P_GO_MODE:
197 case QDF_SAP_MODE:
198 if (test_bit(SOFTAP_BSS_STARTED,
199 &link_info->link_flags)) {
200 hdd_adapter_dev_put_debug(adapter,
201 dbgid);
202 if (next_adapter)
203 hdd_adapter_dev_put_debug(
204 next_adapter,
205 dbgid);
206 return false;
207 }
208 break;
209 case QDF_P2P_CLIENT_MODE:
210 if (hdd_cm_is_vdev_associated(link_info) ||
211 hdd_cm_is_connecting(link_info)) {
212 hdd_adapter_dev_put_debug(adapter,
213 dbgid);
214 if (next_adapter)
215 hdd_adapter_dev_put_debug(
216 next_adapter,
217 dbgid);
218 return false;
219 }
220 break;
221 default:
222 break;
223 }
224 }
225 hdd_adapter_dev_put_debug(adapter, dbgid);
226 }
227
228 return true;
229 }
230 #endif /* NDP_SAP_CONCURRENCY_ENABLE */
231
232 /**
233 * hdd_ndi_select_valid_freq() - Find the valid freq for NDI start
234 * @hdd_ctx: hdd context
235 * @freq: pointer to freq, give preference to 5745, 5220 and 2437 to keep the
236 * legacy behavior intact
237 *
238 * Unlike traditional device modes, where the higher application
239 * layer initiates connect / join / start, the NAN data
240 * interface does not have any such formal requests. The NDI
241 * create request is responsible for starting the BSS as well.
242 * Use the 5GHz Band NAN Social channel for BSS start if target
243 * supports it, since a 2.4GHz channel will require a DBS HW mode change
244 * first on a DBS 2x2 MAC target. Use a 2.4 GHz Band NAN Social channel
245 * if the target is not 5GHz capable. If both of these channels are
246 * not available, pick the next available channel. This would be used just to
247 * start the NDI. Actual channel for NDP data transfer would be negotiated with
248 * peer later.
249 *
250 * Return: SUCCESS if valid channel is obtained
251 */
hdd_ndi_select_valid_freq(struct hdd_context * hdd_ctx,uint32_t * freq)252 static QDF_STATUS hdd_ndi_select_valid_freq(struct hdd_context *hdd_ctx,
253 uint32_t *freq)
254 {
255 static const qdf_freq_t valid_freq[] = {NAN_SOCIAL_FREQ_5GHZ_UPPER_BAND,
256 NAN_SOCIAL_FREQ_5GHZ_LOWER_BAND,
257 NAN_SOCIAL_FREQ_2_4GHZ};
258 uint8_t i;
259 struct regulatory_channel *cur_chan_list;
260 QDF_STATUS status;
261
262 for (i = 0; i < ARRAY_SIZE(valid_freq); i++) {
263 if (wlan_reg_is_freq_enabled(hdd_ctx->pdev, valid_freq[i],
264 REG_CURRENT_PWR_MODE)) {
265 *freq = valid_freq[i];
266 return QDF_STATUS_SUCCESS;
267 }
268 }
269
270 cur_chan_list = qdf_mem_malloc(sizeof(*cur_chan_list) *
271 (NUM_CHANNELS + 2));
272 if (!cur_chan_list)
273 return QDF_STATUS_E_NOMEM;
274
275 status = ucfg_reg_get_current_chan_list(hdd_ctx->pdev, cur_chan_list);
276 if (QDF_IS_STATUS_ERROR(status)) {
277 hdd_err_rl("Failed to get the current channel list");
278 qdf_mem_free(cur_chan_list);
279 return QDF_STATUS_E_IO;
280 }
281
282 for (i = 0; i < NUM_CHANNELS; i++) {
283 /*
284 * current channel list includes all channels. Exclude
285 * disabled channels
286 */
287 if (cur_chan_list[i].chan_flags & REGULATORY_CHAN_DISABLED ||
288 cur_chan_list[i].chan_flags & REGULATORY_CHAN_RADAR)
289 continue;
290 /*
291 * do not include 6 GHz channels for now as NAN would need
292 * 2.4 GHz and 5 GHz channels for discovery.
293 * <TODO> Need to consider the 6GHz channels when there is a
294 * case where all 2GHz and 5GHz channels are disabled and
295 * only 6GHz channels are enabled
296 */
297 if (wlan_reg_is_6ghz_chan_freq(cur_chan_list[i].center_freq))
298 continue;
299
300 /* extracting first valid channel from regulatory list */
301 if (wlan_reg_is_freq_enabled(hdd_ctx->pdev,
302 cur_chan_list[i].center_freq,
303 REG_CURRENT_PWR_MODE)) {
304 *freq = cur_chan_list[i].center_freq;
305 qdf_mem_free(cur_chan_list);
306 return QDF_STATUS_SUCCESS;
307 }
308 }
309
310 qdf_mem_free(cur_chan_list);
311
312 return QDF_STATUS_E_FAILURE;
313 }
314
315 /**
316 * hdd_ndi_start_bss() - Start BSS on NAN data interface
317 * @adapter: adapter context
318 *
319 * Return: 0 on success, error value on failure
320 */
hdd_ndi_start_bss(struct hdd_adapter * adapter)321 static int hdd_ndi_start_bss(struct hdd_adapter *adapter)
322 {
323 QDF_STATUS status;
324 struct bss_dot11_config dot11_cfg = {0};
325 struct start_bss_config ndi_bss_cfg = {0};
326 qdf_freq_t valid_freq = 0;
327 mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
328 struct mac_context *mac = MAC_CONTEXT(mac_handle);
329 struct hdd_context *hdd_ctx;
330
331 hdd_enter();
332 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
333
334 if (!mac) {
335 hdd_debug("mac ctx NULL");
336 return -EINVAL;
337 }
338
339 status = hdd_ndi_select_valid_freq(hdd_ctx, &valid_freq);
340 if (!QDF_IS_STATUS_SUCCESS(status)) {
341 hdd_err("Unable to retrieve channel list for NAN");
342 return -EINVAL;
343 }
344
345 dot11_cfg.vdev_id = adapter->deflink->vdev_id;
346 dot11_cfg.bss_op_ch_freq = valid_freq;
347 dot11_cfg.phy_mode = eCSR_DOT11_MODE_AUTO;
348 if (!wlan_vdev_id_is_open_cipher(mac->pdev, adapter->deflink->vdev_id))
349 dot11_cfg.privacy = 1;
350
351 sme_get_network_params(mac, &dot11_cfg);
352 ndi_bss_cfg.vdev_id = adapter->deflink->vdev_id;
353 ndi_bss_cfg.oper_ch_freq = dot11_cfg.bss_op_ch_freq;
354 ndi_bss_cfg.nwType = dot11_cfg.nw_type;
355 ndi_bss_cfg.dot11mode = dot11_cfg.dot11_mode;
356
357 if (dot11_cfg.opr_rates.numRates) {
358 qdf_mem_copy(ndi_bss_cfg.operationalRateSet.rate,
359 dot11_cfg.opr_rates.rate,
360 dot11_cfg.opr_rates.numRates);
361 ndi_bss_cfg.operationalRateSet.numRates =
362 dot11_cfg.opr_rates.numRates;
363 }
364
365 if (dot11_cfg.ext_rates.numRates) {
366 qdf_mem_copy(ndi_bss_cfg.extendedRateSet.rate,
367 dot11_cfg.ext_rates.rate,
368 dot11_cfg.ext_rates.numRates);
369 ndi_bss_cfg.extendedRateSet.numRates =
370 dot11_cfg.ext_rates.numRates;
371 }
372
373 status = sme_start_bss(mac_handle, adapter->deflink->vdev_id,
374 &ndi_bss_cfg);
375
376 if (QDF_IS_STATUS_ERROR(status)) {
377 hdd_err("NDI sme_RoamConnect session %d failed with status %d -> NotConnected",
378 adapter->deflink->vdev_id, status);
379 /* change back to NotConnected */
380 hdd_conn_set_connection_state(adapter,
381 eConnectionState_NotConnected);
382 }
383
384 hdd_exit();
385
386 return 0;
387 }
388
389 /**
390 * hdd_get_random_nan_mac_addr() - generate random non pre-existent mac address
391 * @hdd_ctx: hdd context pointer
392 * @mac_addr: mac address buffer to populate
393 *
394 * Return: status of operation
395 */
hdd_get_random_nan_mac_addr(struct hdd_context * hdd_ctx,struct qdf_mac_addr * mac_addr)396 static int hdd_get_random_nan_mac_addr(struct hdd_context *hdd_ctx,
397 struct qdf_mac_addr *mac_addr)
398 {
399 struct hdd_adapter *adapter;
400 uint8_t pos, bit_pos, byte_pos, mask;
401 uint8_t i, attempts, max_attempt = 16;
402 bool found;
403
404 for (attempts = 0; attempts < max_attempt; attempts++) {
405 found = false;
406 /* if NDI is present next addr is required to be 1 bit apart */
407 adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE);
408 if (adapter) {
409 hdd_debug("NDI already exists, deriving next mac");
410 qdf_mem_copy(mac_addr, &adapter->mac_addr,
411 sizeof(*mac_addr));
412 qdf_get_random_bytes(&pos, sizeof(pos));
413 /* skipping byte 0, 5 leaves 8*4=32 positions */
414 pos = pos % 32;
415 bit_pos = pos % 8;
416 byte_pos = pos / 8;
417 mask = 1 << bit_pos;
418 /* flip the required bit */
419 mac_addr->bytes[byte_pos + 1] ^= mask;
420 } else {
421 qdf_get_random_bytes(mac_addr, sizeof(*mac_addr));
422 /*
423 * Reset multicast bit (bit-0) and set
424 * locally-administered bit
425 */
426 mac_addr->bytes[0] = 0x2;
427
428 /*
429 * to avoid potential conflict with FW's generated NMI
430 * mac addr, host sets LSB if 6th byte to 0
431 */
432 mac_addr->bytes[5] &= 0xFE;
433 }
434 for (i = 0; i < hdd_ctx->num_provisioned_addr; i++) {
435 if ((!qdf_mem_cmp(hdd_ctx->
436 provisioned_mac_addr[i].bytes,
437 mac_addr, sizeof(*mac_addr)))) {
438 found = true;
439 break;
440 }
441 }
442
443 if (found)
444 continue;
445
446 for (i = 0; i < hdd_ctx->num_derived_addr; i++) {
447 if ((!qdf_mem_cmp(hdd_ctx->
448 derived_mac_addr[i].bytes,
449 mac_addr, sizeof(*mac_addr)))) {
450 found = true;
451 break;
452 }
453 }
454 if (found)
455 continue;
456
457 adapter = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr->bytes);
458 if (!adapter)
459 return 0;
460 }
461
462 hdd_err("unable to get non-pre-existing mac address in %d attempts",
463 max_attempt);
464
465 return -EINVAL;
466 }
467
hdd_ndp_event_handler(struct wlan_hdd_link_info * link_info,struct csr_roam_info * roam_info,eRoamCmdStatus roam_status,eCsrRoamResult roam_result)468 void hdd_ndp_event_handler(struct wlan_hdd_link_info *link_info,
469 struct csr_roam_info *roam_info,
470 eRoamCmdStatus roam_status,
471 eCsrRoamResult roam_result)
472 {
473 bool success;
474 struct wlan_objmgr_psoc *psoc;
475 struct wlan_objmgr_vdev *vdev;
476
477 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_NAN_ID);
478 if (!vdev) {
479 hdd_err("vdev is NULL");
480 return;
481 }
482 psoc = wlan_vdev_get_psoc(vdev);
483 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
484
485 if (roam_status == eCSR_ROAM_NDP_STATUS_UPDATE) {
486 switch (roam_result) {
487 case eCSR_ROAM_RESULT_NDI_CREATE_RSP:
488 success = (roam_info->ndp.ndi_create_params.status ==
489 NAN_DATAPATH_RSP_STATUS_SUCCESS);
490 hdd_debug("posting ndi create status: %d (%s) to umac",
491 success, success ? "Success" : "Failure");
492 os_if_nan_post_ndi_create_rsp(psoc, link_info->vdev_id,
493 success);
494 return;
495 case eCSR_ROAM_RESULT_NDI_DELETE_RSP:
496 success = (roam_info->ndp.ndi_create_params.status ==
497 NAN_DATAPATH_RSP_STATUS_SUCCESS);
498 hdd_debug("posting ndi delete status: %d (%s) to umac",
499 success, success ? "Success" : "Failure");
500 os_if_nan_post_ndi_delete_rsp(psoc, link_info->vdev_id,
501 success);
502 return;
503 default:
504 hdd_err("in correct roam_result: %d", roam_result);
505 return;
506 }
507 } else {
508 hdd_err("in correct roam_status: %d", roam_status);
509 return;
510 }
511 }
512
513 /**
514 * __wlan_hdd_cfg80211_process_ndp_cmd() - handle NDP request
515 * @wiphy: pointer to wireless wiphy structure.
516 * @wdev: pointer to wireless_dev structure.
517 * @data: Pointer to the data to be passed via vendor interface
518 * @data_len:Length of the data to be passed
519 *
520 * This function is invoked to handle vendor command
521 *
522 * Return: 0 on success, negative errno on failure
523 */
__wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)524 static int __wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy,
525 struct wireless_dev *wdev, const void *data, int data_len)
526 {
527 int ret_val;
528 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
529
530 ret_val = wlan_hdd_validate_context(hdd_ctx);
531 if (ret_val)
532 return ret_val;
533
534 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
535 hdd_err_rl("Command not allowed in FTM mode");
536 return -EPERM;
537 }
538
539 if (!WLAN_HDD_IS_NDP_ENABLED(hdd_ctx)) {
540 hdd_debug_rl("NAN datapath is not enabled");
541 return -EPERM;
542 }
543
544 return os_if_nan_process_ndp_cmd(hdd_ctx->psoc, data, data_len,
545 hdd_is_ndp_allowed(hdd_ctx), wdev);
546 }
547
548 /**
549 * wlan_hdd_cfg80211_process_ndp_cmd() - handle NDP request
550 * @wiphy: pointer to wireless wiphy structure.
551 * @wdev: pointer to wireless_dev structure.
552 * @data: Pointer to the data to be passed via vendor interface
553 * @data_len:Length of the data to be passed
554 *
555 * This function is called to send a NAN request to
556 * firmware. This is an SSR-protected wrapper function.
557 *
558 * Return: 0 on success, negative errno on failure
559 */
wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)560 int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy,
561 struct wireless_dev *wdev,
562 const void *data, int data_len)
563 {
564 /* This call is intentionally not protected by op_start/op_stop, due to
565 * the various protection needs of the callbacks dispatched within.
566 */
567 return __wlan_hdd_cfg80211_process_ndp_cmd(wiphy, wdev,
568 data, data_len);
569 }
570
update_ndi_state(struct hdd_adapter * adapter,uint32_t state)571 static int update_ndi_state(struct hdd_adapter *adapter, uint32_t state)
572 {
573 struct wlan_objmgr_vdev *vdev;
574 QDF_STATUS status;
575
576 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_NAN_ID);
577 if (!vdev) {
578 hdd_err("vdev is NULL");
579 return QDF_STATUS_E_NULL_VALUE;
580 }
581 status = os_if_nan_set_ndi_state(vdev, state);
582
583 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
584 return status;
585 }
586
587 /**
588 * hdd_init_nan_data_mode() - initialize nan data mode
589 * @adapter: adapter context
590 *
591 * Returns: 0 on success negative error code on error
592 */
hdd_init_nan_data_mode(struct hdd_adapter * adapter)593 int hdd_init_nan_data_mode(struct hdd_adapter *adapter)
594 {
595 struct net_device *wlan_dev = adapter->dev;
596 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
597 QDF_STATUS status;
598 int32_t ret_val;
599 mac_handle_t mac_handle;
600 bool bval = false;
601 uint8_t enable_sifs_burst = 0;
602 struct wlan_objmgr_vdev *vdev;
603 uint16_t rts_profile = 0;
604
605 status = hdd_adapter_fill_link_address(adapter);
606 if (QDF_IS_STATUS_ERROR(status)) {
607 hdd_debug("Link address derive failed");
608 return qdf_status_to_os_return(status);
609 }
610
611 status = hdd_adapter_check_duplicate_session(adapter);
612 if (QDF_IS_STATUS_ERROR(status)) {
613 hdd_err("Duplicate session is existing with same mac address");
614 return qdf_status_to_os_return(status);
615 }
616
617 ret_val = hdd_vdev_create(adapter->deflink);
618 if (ret_val) {
619 hdd_err("failed to create vdev: %d", ret_val);
620 return ret_val;
621 }
622
623 mac_handle = hdd_ctx->mac_handle;
624
625 /* Configure self HT/VHT capabilities */
626 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
627 if (!QDF_IS_STATUS_SUCCESS(status))
628 hdd_err("unable to get vht_enable2x2");
629
630 sme_set_pdev_ht_vht_ies(mac_handle, bval);
631 sme_set_vdev_ies_per_band(mac_handle, adapter->deflink->vdev_id,
632 adapter->device_mode);
633
634 hdd_roam_profile_init(adapter->deflink);
635 hdd_register_wext(wlan_dev);
636
637 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID);
638 if (!vdev) {
639 ret_val = -EAGAIN;
640 goto wext_unregister;
641 }
642
643 status = hdd_wmm_adapter_init(adapter);
644 if (QDF_STATUS_SUCCESS != status) {
645 hdd_err("hdd_wmm_adapter_init() failed, status %d", status);
646 ret_val = -EAGAIN;
647 goto error_wmm_init;
648 }
649
650 set_bit(WMM_INIT_DONE, &adapter->event_flags);
651
652 /* ENABLE SIFS BURST */
653 status = ucfg_get_enable_sifs_burst(hdd_ctx->psoc, &enable_sifs_burst);
654 if (!QDF_IS_STATUS_SUCCESS(status))
655 hdd_err("Failed to get sifs burst value, use default");
656
657 ret_val = wma_cli_set_command((int)adapter->deflink->vdev_id,
658 (int)wmi_pdev_param_burst_enable,
659 enable_sifs_burst,
660 PDEV_CMD);
661 if (0 != ret_val)
662 hdd_err("wmi_pdev_param_burst_enable set failed %d", ret_val);
663
664 /* RTS CTS PARAM */
665 status = ucfg_fwol_get_rts_profile(hdd_ctx->psoc, &rts_profile);
666 if (QDF_IS_STATUS_ERROR(status))
667 hdd_err("FAILED TO GET RTSCTS Profile status:%d", status);
668
669 ret_val = sme_cli_set_command(adapter->deflink->vdev_id,
670 wmi_vdev_param_enable_rtscts, rts_profile,
671 VDEV_CMD);
672 if (ret_val)
673 hdd_err("FAILED TO SET RTSCTS Profile ret:%d", ret_val);
674
675 hdd_set_netdev_flags(adapter);
676
677 hdd_tsf_auto_report_init(adapter);
678 update_ndi_state(adapter, NAN_DATA_NDI_CREATING_STATE);
679 hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
680 return ret_val;
681
682 error_wmm_init:
683 hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
684
685 wext_unregister:
686 hdd_wext_unregister(wlan_dev, true);
687 QDF_BUG(!hdd_vdev_destroy(adapter->deflink));
688
689 return ret_val;
690 }
691
692 /**
693 * hdd_is_max_ndi_count_reached() - Check the NDI max limit
694 * @hdd_ctx: Pointer to HDD context
695 *
696 * This function does not allow to create more than ndi_max_support
697 *
698 * Return: false if max value not reached otherwise true
699 */
hdd_is_max_ndi_count_reached(struct hdd_context * hdd_ctx)700 static bool hdd_is_max_ndi_count_reached(struct hdd_context *hdd_ctx)
701 {
702 struct hdd_adapter *adapter, *next_adapter = NULL;
703 uint8_t ndi_adapter_count = 0;
704 QDF_STATUS status;
705 uint32_t max_ndi;
706
707 if (!hdd_ctx)
708 return true;
709
710 hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
711 NET_DEV_HOLD_NDI_OPEN) {
712 if (WLAN_HDD_IS_NDI(adapter))
713 ndi_adapter_count++;
714 hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_NDI_OPEN);
715 }
716
717 status = cfg_nan_get_max_ndi(hdd_ctx->psoc, &max_ndi);
718 if (QDF_IS_STATUS_ERROR(status)) {
719 hdd_err(" Unable to fetch Max NDI");
720 return true;
721 }
722
723 if (ndi_adapter_count >= max_ndi) {
724 hdd_err("Can't allow more than %d NDI adapters",
725 max_ndi);
726 return true;
727 }
728
729 return false;
730 }
731
hdd_ndi_open(const char * iface_name,bool is_add_virtual_iface)732 int hdd_ndi_open(const char *iface_name, bool is_add_virtual_iface)
733 {
734 struct hdd_adapter *adapter;
735 struct qdf_mac_addr random_ndi_mac;
736 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
737 uint8_t *ndi_mac_addr;
738 struct hdd_adapter_create_param params = {0};
739
740 hdd_enter();
741
742 if (hdd_is_max_ndi_count_reached(hdd_ctx))
743 return -EINVAL;
744
745 params.is_add_virtual_iface = is_add_virtual_iface;
746
747 hdd_debug("is_add_virtual_iface %d", is_add_virtual_iface);
748
749 if (cfg_nan_get_ndi_mac_randomize(hdd_ctx->psoc)) {
750 if (hdd_get_random_nan_mac_addr(hdd_ctx, &random_ndi_mac)) {
751 hdd_err("get random mac address failed");
752 return -EFAULT;
753 }
754 ndi_mac_addr = &random_ndi_mac.bytes[0];
755 } else {
756 ndi_mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_NDI_MODE);
757 if (!ndi_mac_addr) {
758 hdd_err("get intf address failed");
759 return -EFAULT;
760 }
761 }
762
763 params.is_add_virtual_iface = 1;
764 adapter = hdd_open_adapter(hdd_ctx, QDF_NDI_MODE, iface_name,
765 ndi_mac_addr, NET_NAME_UNKNOWN, true,
766 ¶ms);
767 if (!adapter) {
768 if (!cfg_nan_get_ndi_mac_randomize(hdd_ctx->psoc))
769 wlan_hdd_release_intf_addr(hdd_ctx, ndi_mac_addr);
770 hdd_err("hdd_open_adapter failed");
771 return -EINVAL;
772 }
773
774 hdd_exit();
775 return 0;
776 }
777
778 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
hdd_ndi_set_mode(const char * iface_name)779 int hdd_ndi_set_mode(const char *iface_name)
780 {
781 struct hdd_adapter *adapter;
782 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
783 struct qdf_mac_addr random_ndi_mac;
784 uint8_t *ndi_mac_addr = NULL;
785
786 hdd_enter();
787 if (hdd_is_max_ndi_count_reached(hdd_ctx))
788 return -EINVAL;
789
790 adapter = hdd_get_adapter_by_iface_name(hdd_ctx, iface_name);
791 if (!adapter) {
792 hdd_err("adapter is null");
793 return -EINVAL;
794 }
795
796 if (cfg_nan_get_ndi_mac_randomize(hdd_ctx->psoc)) {
797 if (hdd_get_random_nan_mac_addr(hdd_ctx, &random_ndi_mac)) {
798 hdd_err("get random mac address failed");
799 return -EFAULT;
800 }
801 ndi_mac_addr = &random_ndi_mac.bytes[0];
802 ucfg_dp_update_intf_mac(hdd_ctx->psoc, &adapter->mac_addr,
803 (struct qdf_mac_addr *)ndi_mac_addr,
804 adapter->deflink->vdev);
805 hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr,
806 (struct qdf_mac_addr *)ndi_mac_addr);
807 qdf_mem_copy(&adapter->mac_addr, ndi_mac_addr, ETH_ALEN);
808 qdf_net_update_net_device_dev_addr(adapter->dev,
809 ndi_mac_addr, ETH_ALEN);
810 }
811
812 adapter->device_mode = QDF_NDI_MODE;
813 hdd_debug("Created NDI with device mode:%d and iface_name:%s",
814 adapter->device_mode, iface_name);
815
816 return 0;
817 }
818 #endif
819
hdd_ndi_start(const char * iface_name,uint16_t transaction_id)820 int hdd_ndi_start(const char *iface_name, uint16_t transaction_id)
821 {
822 int ret;
823 QDF_STATUS status;
824 struct hdd_adapter *adapter;
825 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
826 struct wlan_objmgr_vdev *vdev;
827
828 hdd_enter();
829 if (!hdd_ctx)
830 return -EINVAL;
831
832 adapter = hdd_get_adapter_by_iface_name(hdd_ctx, iface_name);
833 if (!adapter) {
834 hdd_err("adapter is null");
835 return -EINVAL;
836 }
837
838 /* create nan vdev */
839 status = hdd_init_nan_data_mode(adapter);
840 if (QDF_STATUS_SUCCESS != status) {
841 hdd_err("failed to init nan data intf, status :%d", status);
842 ret = -EFAULT;
843 goto err_handler;
844 }
845
846 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_NAN_ID);
847 if (!vdev) {
848 hdd_err("vdev is NULL");
849 ret = -EINVAL;
850 goto err_handler;
851 }
852
853 hdd_cstats_log_ndi_create_req_evt(vdev, transaction_id);
854 /*
855 * Create transaction id is required to be saved since the firmware
856 * does not honor the transaction id for create request
857 */
858 ucfg_nan_set_ndp_create_transaction_id(vdev, transaction_id);
859 ucfg_nan_set_ndi_state(vdev, NAN_DATA_NDI_CREATING_STATE);
860 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
861
862 if (hdd_ndi_start_bss(adapter)) {
863 hdd_err("NDI start bss failed");
864 ret = -EFAULT;
865 goto err_handler;
866 }
867
868 hdd_create_adapter_sysfs_files(adapter);
869 hdd_exit();
870 return 0;
871
872 err_handler:
873
874 /* Start BSS failed, delete the interface */
875 hdd_close_ndi(adapter);
876 return ret;
877 }
878
879 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
hdd_delete_ndi_intf(struct wiphy * wiphy,struct wireless_dev * wdev)880 static int hdd_delete_ndi_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
881 {
882 struct net_device *dev = wdev->netdev;
883 struct hdd_context *hdd_ctx = (struct hdd_context *)wiphy_priv(wiphy);
884 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
885
886 hdd_enter_dev(dev);
887
888 wlan_hdd_release_intf_addr(hdd_ctx,
889 adapter->mac_addr.bytes);
890 hdd_stop_adapter(hdd_ctx, adapter);
891 hdd_deinit_adapter(hdd_ctx, adapter, true);
892
893 hdd_exit();
894
895 return 0;
896 }
897 #else
hdd_delete_ndi_intf(struct wiphy * wiphy,struct wireless_dev * wdev)898 static int hdd_delete_ndi_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
899 {
900 int ret;
901
902 ret = __wlan_hdd_del_virtual_intf(wiphy, wdev);
903
904 if (ret)
905 hdd_err("NDI delete request failed");
906 else
907 hdd_err("NDI delete request successfully issued");
908
909 return ret;
910 }
911 #endif
912
hdd_ndi_delete(uint8_t vdev_id,const char * iface_name,uint16_t transaction_id)913 int hdd_ndi_delete(uint8_t vdev_id, const char *iface_name,
914 uint16_t transaction_id)
915 {
916 int ret;
917 struct hdd_adapter *adapter;
918 struct wlan_hdd_link_info *link_info;
919 struct hdd_station_ctx *sta_ctx;
920 struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
921 struct wlan_objmgr_vdev *vdev;
922
923 if (!hdd_ctx)
924 return -EINVAL;
925
926 /* check if adapter by vdev_id is valid NDI */
927 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
928 if (!link_info || !WLAN_HDD_IS_NDI(link_info->adapter)) {
929 hdd_err("NAN data interface %s is not available", iface_name);
930 return -EINVAL;
931 }
932
933 adapter = link_info->adapter;
934 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
935
936 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_NAN_ID);
937 if (!vdev) {
938 hdd_err("vdev is NULL");
939 return -EINVAL;
940 }
941
942 os_if_nan_set_ndp_delete_transaction_id(vdev, transaction_id);
943 os_if_nan_set_ndi_state(vdev, NAN_DATA_NDI_DELETING_STATE);
944 hdd_cstats_log_ndi_delete_req_evt(vdev, transaction_id);
945 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
946
947 /* Delete the interface */
948 adapter->is_virtual_iface = true;
949 ret = hdd_delete_ndi_intf(hdd_ctx->wiphy, &adapter->wdev);
950
951 return ret;
952 }
953
954 #define MAX_VDEV_NDP_PARAMS 2
955 /* params being sent:
956 * wmi_vdev_param_ndp_inactivity_timeout
957 * wmi_vdev_param_ndp_keepalive_timeout
958 */
959
960 void
hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id,struct nan_datapath_inf_create_rsp * ndi_rsp)961 hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id,
962 struct nan_datapath_inf_create_rsp *ndi_rsp)
963 {
964 struct hdd_context *hdd_ctx;
965 struct hdd_adapter *adapter;
966 struct wlan_hdd_link_info *link_info;
967 struct hdd_station_ctx *sta_ctx;
968 struct csr_roam_info *roam_info;
969 uint16_t ndp_inactivity_timeout = 0;
970 uint16_t ndp_keep_alive_period;
971 struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BCAST_INIT;
972 struct wlan_objmgr_vdev *vdev;
973 struct dev_set_param setparam[MAX_VDEV_NDP_PARAMS] = {};
974 uint8_t index = 0;
975 QDF_STATUS status;
976
977 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
978 if (!hdd_ctx)
979 return;
980
981 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
982 if (!link_info) {
983 hdd_err("Invalid vdev");
984 return;
985 }
986
987 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
988 adapter = link_info->adapter;
989
990 roam_info = qdf_mem_malloc(sizeof(*roam_info));
991 if (!roam_info)
992 return;
993
994 if (ndi_rsp->status == QDF_STATUS_SUCCESS) {
995 hdd_alert("NDI interface successfully created");
996 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_NAN_ID);
997 if (!vdev) {
998 qdf_mem_free(roam_info);
999 hdd_err("vdev is NULL");
1000 return;
1001 }
1002
1003 os_if_nan_set_ndp_create_transaction_id(vdev, 0);
1004 os_if_nan_set_ndi_state(vdev, NAN_DATA_NDI_CREATED_STATE);
1005 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
1006
1007 wlan_hdd_netif_queue_control(adapter,
1008 WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
1009 WLAN_CONTROL_PATH);
1010
1011 if (QDF_IS_STATUS_ERROR(cfg_nan_get_ndp_inactivity_timeout(
1012 hdd_ctx->psoc, &ndp_inactivity_timeout)))
1013 hdd_err("Failed to fetch inactivity timeout value");
1014 status = mlme_check_index_setparam(
1015 setparam,
1016 wmi_vdev_param_ndp_inactivity_timeout,
1017 ndp_inactivity_timeout, index++,
1018 MAX_VDEV_NDP_PARAMS);
1019 if (QDF_IS_STATUS_ERROR(status)) {
1020 hdd_err("failed at wmi_vdev_param_ndp_inactivity_timeout");
1021 goto error;
1022 }
1023
1024 if (QDF_IS_STATUS_SUCCESS(cfg_nan_get_ndp_keepalive_period(
1025 hdd_ctx->psoc,
1026 &ndp_keep_alive_period))) {
1027 status = mlme_check_index_setparam(
1028 setparam,
1029 wmi_vdev_param_ndp_keepalive_timeout,
1030 ndp_keep_alive_period, index++,
1031 MAX_VDEV_NDP_PARAMS);
1032 if (QDF_IS_STATUS_ERROR(status)) {
1033 hdd_err("failed at wmi_vdev_param_ndp_keepalive_timeout");
1034 goto error;
1035 }
1036 }
1037 status = sme_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM,
1038 link_info->vdev_id,
1039 setparam, index);
1040 if (QDF_IS_STATUS_ERROR(status))
1041 hdd_err("failed to send vdev set params");
1042 } else {
1043 hdd_alert("NDI interface creation failed with reason %d",
1044 ndi_rsp->reason /* create_reason */);
1045 }
1046
1047 hdd_cstats_log_ndi_create_resp_evt(link_info, ndi_rsp);
1048
1049 hdd_save_peer(sta_ctx, &bc_mac_addr);
1050 qdf_copy_macaddr(&roam_info->bssid, &bc_mac_addr);
1051 hdd_roam_register_sta(link_info,
1052 &roam_info->bssid,
1053 roam_info->fAuthRequired);
1054
1055 error:
1056 qdf_mem_free(roam_info);
1057 }
1058
hdd_ndi_close(uint8_t vdev_id)1059 void hdd_ndi_close(uint8_t vdev_id)
1060 {
1061 struct hdd_context *hdd_ctx;
1062 struct wlan_hdd_link_info *link_info;
1063
1064 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1065 if (!hdd_ctx)
1066 return;
1067
1068 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
1069 if (!link_info) {
1070 hdd_err("Invalid vdev");
1071 return;
1072 }
1073
1074 link_info->adapter->is_virtual_iface = true;
1075 hdd_close_ndi(link_info->adapter);
1076 }
1077
hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id)1078 void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id)
1079 {
1080 struct hdd_context *hdd_ctx;
1081 struct hdd_adapter *adapter;
1082 struct wlan_hdd_link_info *link_info;
1083 struct hdd_station_ctx *sta_ctx;
1084 struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BCAST_INIT;
1085
1086 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1087 if (!hdd_ctx)
1088 return;
1089
1090 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
1091 if (!link_info) {
1092 hdd_err("Invalid vdev");
1093 return;
1094 }
1095
1096 adapter = link_info->adapter;
1097 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1098
1099 hdd_delete_peer(sta_ctx, &bc_mac_addr);
1100
1101 wlan_hdd_netif_queue_control(adapter,
1102 WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
1103 WLAN_CONTROL_PATH);
1104
1105 /*
1106 * For NAN Data interface, the close session results in the final
1107 * indication to the userspace
1108 */
1109 if (adapter->device_mode == QDF_NDI_MODE)
1110 hdd_ndp_session_end_handler(adapter);
1111
1112 complete(&adapter->disconnect_comp_var);
1113 }
1114
hdd_ndp_session_end_handler(struct hdd_adapter * adapter)1115 void hdd_ndp_session_end_handler(struct hdd_adapter *adapter)
1116 {
1117 struct wlan_objmgr_vdev *vdev;
1118
1119 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_NAN_ID);
1120 if (!vdev) {
1121 hdd_err("vdev is NULL");
1122 return;
1123 }
1124
1125 os_if_nan_ndi_session_end(vdev);
1126 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
1127 }
1128
1129 /**
1130 * hdd_send_obss_scan_req() - send OBSS scan request to SME layer.
1131 * @hdd_ctx: hdd context pointer
1132 * @val: true if new NDP peer is added and false when last peer NDP is deleted.
1133 *
1134 * Return: void
1135 */
hdd_send_obss_scan_req(struct hdd_context * hdd_ctx,bool val)1136 static void hdd_send_obss_scan_req(struct hdd_context *hdd_ctx, bool val)
1137 {
1138 QDF_STATUS status;
1139 uint32_t sta_vdev_id = 0;
1140
1141 status = hdd_get_first_connected_sta_vdev_id(hdd_ctx, &sta_vdev_id);
1142
1143 if (QDF_IS_STATUS_SUCCESS(status)) {
1144 hdd_debug("reconfig OBSS scan param: %d", val);
1145 sme_reconfig_obss_scan_param(hdd_ctx->mac_handle, sta_vdev_id,
1146 val);
1147 } else {
1148 hdd_debug("Connected STA not found");
1149 }
1150 }
1151
hdd_ndp_new_peer_handler(uint8_t vdev_id,uint16_t sta_id,struct qdf_mac_addr * peer_mac_addr,bool first_peer)1152 int hdd_ndp_new_peer_handler(uint8_t vdev_id, uint16_t sta_id,
1153 struct qdf_mac_addr *peer_mac_addr,
1154 bool first_peer)
1155 {
1156 struct hdd_context *hdd_ctx;
1157 struct hdd_adapter *adapter;
1158 struct wlan_hdd_link_info *link_info;
1159 struct hdd_station_ctx *sta_ctx;
1160 struct csr_roam_info *roam_info;
1161 struct wlan_objmgr_vdev *vdev;
1162
1163 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1164 if (!hdd_ctx)
1165 return -EINVAL;
1166
1167 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
1168 if (!link_info) {
1169 hdd_err("Invalid vdev");
1170 return -EINVAL;
1171 }
1172
1173 adapter = link_info->adapter;
1174 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1175
1176 /* save peer in ndp ctx */
1177 if (!hdd_save_peer(sta_ctx, peer_mac_addr)) {
1178 hdd_err("Ndp peer table full. cannot save new peer");
1179 return -EPERM;
1180 }
1181
1182 roam_info = qdf_mem_malloc(sizeof(*roam_info));
1183 if (!roam_info)
1184 return -ENOMEM;
1185 qdf_copy_macaddr(&roam_info->bssid, peer_mac_addr);
1186
1187 /* this function is called for each new peer */
1188 hdd_roam_register_sta(link_info, &roam_info->bssid,
1189 roam_info->fAuthRequired);
1190
1191 if (!first_peer)
1192 goto mem_free;
1193
1194 hdd_debug("Set ctx connection state to connected");
1195 /* Disable LRO/GRO for NDI Mode */
1196 if (ucfg_dp_is_ol_enabled(hdd_ctx->psoc) &&
1197 !NAN_CONCURRENCY_SUPPORTED(hdd_ctx->psoc)) {
1198 hdd_debug("Disable LRO/GRO in NDI Mode");
1199 hdd_disable_rx_ol_in_concurrency(true);
1200 }
1201
1202 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID);
1203 if (vdev) {
1204 ucfg_dp_bus_bw_compute_prev_txrx_stats(vdev);
1205 hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
1206 }
1207
1208 ucfg_dp_bus_bw_compute_timer_start(hdd_ctx->psoc);
1209 sta_ctx->conn_info.conn_state = eConnectionState_NdiConnected;
1210 hdd_wmm_connect(adapter, roam_info, eCSR_BSS_TYPE_NDI);
1211 wlan_hdd_netif_queue_control(adapter,
1212 WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
1213 WLAN_CONTROL_PATH);
1214 /*
1215 * This is called only for first peer. So, no.of NDP sessions
1216 * are always 1
1217 */
1218 if (!NDI_CONCURRENCY_SUPPORTED(hdd_ctx->psoc))
1219 hdd_indicate_active_ndp_cnt(hdd_ctx->psoc, vdev_id, 1);
1220 hdd_send_obss_scan_req(hdd_ctx, true);
1221
1222 mem_free:
1223 qdf_mem_free(roam_info);
1224 return 0;
1225 }
1226
hdd_cleanup_ndi(struct wlan_hdd_link_info * link_info)1227 void hdd_cleanup_ndi(struct wlan_hdd_link_info *link_info)
1228 {
1229 struct hdd_station_ctx *sta_ctx;
1230 struct wlan_objmgr_vdev *vdev;
1231 struct hdd_adapter *adapter = link_info->adapter;
1232 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1233
1234 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1235 if (sta_ctx->conn_info.conn_state != eConnectionState_NdiConnected) {
1236 hdd_debug("NDI has no NDPs");
1237 return;
1238 }
1239 sta_ctx->conn_info.conn_state = eConnectionState_NdiDisconnected;
1240 hdd_conn_set_connection_state(adapter,
1241 eConnectionState_NdiDisconnected);
1242 hdd_debug("Stop netif tx queues.");
1243 wlan_hdd_netif_queue_control(adapter,
1244 WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
1245 WLAN_CONTROL_PATH);
1246 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID);
1247 if (vdev) {
1248 ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(vdev);
1249 hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
1250 }
1251 ucfg_dp_bus_bw_compute_timer_try_stop(hdd_ctx->psoc);
1252 if ((ucfg_dp_is_ol_enabled(hdd_ctx->psoc) &&
1253 !NAN_CONCURRENCY_SUPPORTED(hdd_ctx->psoc)) &&
1254 ((policy_mgr_get_connection_count(hdd_ctx->psoc) == 0) ||
1255 ((policy_mgr_get_connection_count(hdd_ctx->psoc) == 1) &&
1256 (policy_mgr_mode_specific_connection_count(
1257 hdd_ctx->psoc,
1258 PM_STA_MODE,
1259 NULL) == 1)))) {
1260 hdd_debug("Enable LRO/GRO");
1261 ucfg_dp_rx_handle_concurrency(hdd_ctx->psoc, false);
1262 }
1263 }
1264
hdd_ndp_peer_departed_handler(uint8_t vdev_id,uint16_t sta_id,struct qdf_mac_addr * peer_mac_addr,bool last_peer)1265 void hdd_ndp_peer_departed_handler(uint8_t vdev_id, uint16_t sta_id,
1266 struct qdf_mac_addr *peer_mac_addr, bool last_peer)
1267 {
1268 struct hdd_context *hdd_ctx;
1269 struct hdd_adapter *adapter;
1270 struct wlan_hdd_link_info *link_info;
1271 struct hdd_station_ctx *sta_ctx;
1272
1273 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1274 if (!hdd_ctx)
1275 return;
1276
1277 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
1278 if (!link_info) {
1279 hdd_err("Invalid vdev");
1280 return;
1281 }
1282
1283 adapter = link_info->adapter;
1284 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
1285
1286 hdd_delete_peer(sta_ctx, peer_mac_addr);
1287
1288 ucfg_nan_clear_peer_mc_list(hdd_ctx->psoc, link_info->vdev,
1289 peer_mac_addr);
1290
1291 if (last_peer) {
1292 hdd_debug("No more ndp peers.");
1293 hdd_cleanup_ndi(link_info);
1294 qdf_event_set(&adapter->peer_cleanup_done);
1295 /*
1296 * This is called only for last peer. So, no.of NDP sessions
1297 * are always 0
1298 */
1299 if (!NDI_CONCURRENCY_SUPPORTED(hdd_ctx->psoc))
1300 hdd_indicate_active_ndp_cnt(hdd_ctx->psoc, vdev_id, 0);
1301 hdd_send_obss_scan_req(hdd_ctx, false);
1302 }
1303 }
1304