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