xref: /wlan-dirver/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c (revision f6f31628469944673446302b6aa45d021e83dd22)
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  */
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  */
82 static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx,
83 				  struct hdd_adapter *adapter, bool value)
84 {
85 }
86 #else
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  */
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
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
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  */
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  */
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  */
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 
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  */
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  */
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 
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  */
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  */
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 
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 				   &params);
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))
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 
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))
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
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 
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
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 
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 
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 
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  */
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 
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 
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 
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