1 /*
2  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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: contains nud event tracking main function definitions
22  */
23 
24 #include "osif_sync.h"
25 #include "wlan_hdd_main.h"
26 #include "wlan_dp_ucfg_api.h"
27 #include "wlan_dlm_ucfg_api.h"
28 #include "hdd_dp_cfg.h"
29 #include <cdp_txrx_misc.h>
30 #include "wlan_cm_roam_ucfg_api.h"
31 #include "wlan_hdd_nud_tracking.h"
32 
33 static void
hdd_handle_nud_fail_sta(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)34 hdd_handle_nud_fail_sta(struct hdd_context *hdd_ctx,
35 			struct hdd_adapter *adapter)
36 {
37 	struct reject_ap_info ap_info;
38 	struct hdd_station_ctx *sta_ctx;
39 	struct qdf_mac_addr bssid;
40 
41 	if (hdd_is_roaming_in_progress(hdd_ctx)) {
42 		hdd_debug("Roaming already in progress, cannot trigger roam.");
43 		return;
44 	}
45 
46 	hdd_debug("nud fail detected, try roaming to better BSSID, vdev id: %d",
47 		  adapter->deflink->vdev_id);
48 
49 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
50 
51 	qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info));
52 	ap_info.bssid = sta_ctx->conn_info.bssid;
53 	ap_info.reject_ap_type = DRIVER_AVOID_TYPE;
54 	ap_info.reject_reason = REASON_NUD_FAILURE;
55 	ap_info.source = ADDED_BY_DRIVER;
56 	ucfg_dlm_add_bssid_to_reject_list(hdd_ctx->pdev, &ap_info);
57 
58 	if (roaming_offload_enabled(hdd_ctx)) {
59 		qdf_zero_macaddr(&bssid);
60 		ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev,
61 					 adapter->deflink->vdev_id,
62 					 &bssid, 0, CM_ROAMING_NUD_FAILURE);
63 	}
64 }
65 
66 static void
hdd_handle_nud_fail_non_sta(struct wlan_hdd_link_info * link_info)67 hdd_handle_nud_fail_non_sta(struct wlan_hdd_link_info *link_info)
68 {
69 	wlan_hdd_cm_issue_disconnect(link_info,
70 				     REASON_GATEWAY_REACHABILITY_FAILURE,
71 				     false);
72 }
73 
74 /**
75  * __hdd_nud_failure_work() - work for nud event
76  * @adapter: HDD adapter
77  *
78  * Return: None
79  */
80 static void
__hdd_nud_failure_work(struct hdd_adapter * adapter)81 __hdd_nud_failure_work(struct hdd_adapter *adapter)
82 {
83 	struct hdd_context *hdd_ctx;
84 	int status;
85 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
86 
87 	hdd_enter();
88 
89 	status = hdd_validate_adapter(adapter);
90 	if (status)
91 		return;
92 
93 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
94 	status = wlan_hdd_validate_context(hdd_ctx);
95 	if (0 != status)
96 		return;
97 
98 	if (!hdd_cm_is_vdev_associated(adapter->deflink)) {
99 		hdd_debug("Not in Connected State");
100 		return;
101 	}
102 
103 	if (hdd_ctx->hdd_wlan_suspended) {
104 		hdd_debug("wlan is suspended, ignore NUD failure event");
105 		return;
106 	}
107 
108 	if (soc && ucfg_dp_nud_fail_data_stall_evt_enabled()) {
109 		hdd_dp_err("Data stall due to NUD failure");
110 		cdp_post_data_stall_event
111 			(soc,
112 			 DATA_STALL_LOG_INDICATOR_HOST_DRIVER,
113 			 DATA_STALL_LOG_NUD_FAILURE,
114 			 OL_TXRX_PDEV_ID, 0XFF,
115 			 DATA_STALL_LOG_RECOVERY_TRIGGER_PDR);
116 	}
117 
118 	if (adapter->device_mode == QDF_STA_MODE &&
119 	    ucfg_dp_is_roam_after_nud_enabled(hdd_ctx->psoc)) {
120 		hdd_handle_nud_fail_sta(hdd_ctx, adapter);
121 		return;
122 	}
123 	hdd_handle_nud_fail_non_sta(adapter->deflink);
124 
125 	hdd_exit();
126 }
127 
hdd_nud_failure_work(hdd_cb_handle context,qdf_netdev_t netdev)128 void hdd_nud_failure_work(hdd_cb_handle context, qdf_netdev_t netdev)
129 {
130 	struct hdd_adapter *adapter;
131 	struct osif_vdev_sync *vdev_sync;
132 
133 	adapter = WLAN_HDD_GET_PRIV_PTR(netdev);
134 	if (!adapter) {
135 		hdd_err("adapter is null");
136 		return;
137 	}
138 
139 	if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync))
140 		return;
141 
142 	__hdd_nud_failure_work(adapter);
143 
144 	osif_vdev_sync_op_stop(vdev_sync);
145 }
146