1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "block_connect_service.h"
16 
17 namespace OHOS {
18 namespace Wifi {
19 DEFINE_WIFILOG_LABEL("BlockConnectService");
20 constexpr int FREQUENT_DISCONNECT_COUNT = 5;
21 constexpr int64_t FREQUENT_DISCONNECT_TIME_INTERVAL_MAX = 10 * 60 * 1000 * 1000;
22 constexpr int64_t FREQUENT_DISCONNECT_TIME_INTERVAL_MID = 1 * 60 * 1000 * 1000;
23 constexpr int64_t FREQUENT_DISCONNECT_TIME_INTERVAL_MIN = 0.5 * 60 * 1000 * 1000;
24 
GetInstance()25 BlockConnectService &BlockConnectService::GetInstance()
26 {
27     static BlockConnectService gStaBlockConnectService;
28     return gStaBlockConnectService;
29 }
30 
BlockConnectService()31 BlockConnectService::BlockConnectService()
32 {
33     // Initialize any necessary variables or data structures
34     blockConnectPolicies = {
35         {DisabledReason::DISABLED_ASSOCIATION_REJECTION,
36          DisablePolicy(5 * 60 * 1000 * 1000, 3, WifiDeviceConfigStatus::DISABLED)},
37         {DisabledReason::DISABLED_AUTHENTICATION_FAILURE,
38          DisablePolicy(5 * 60 * 1000 * 1000, 3, WifiDeviceConfigStatus::DISABLED)},
39         {DisabledReason::DISABLED_DHCP_FAILURE,
40          DisablePolicy(5 * 60 * 1000 * 1000, 2, WifiDeviceConfigStatus::DISABLED)},
41         {DisabledReason::DISABLED_NO_INTERNET_TEMPORARY,
42          DisablePolicy(5 * 60 * 1000 * 1000, 1, WifiDeviceConfigStatus::DISABLED)},
43         {DisabledReason::DISABLED_AUTHENTICATION_NO_CREDENTIALS,
44          DisablePolicy(-1, 3, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
45         {DisabledReason::DISABLED_NO_INTERNET_PERMANENT,
46          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
47         {DisabledReason::DISABLED_BY_WIFI_MANAGER,
48          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
49         {DisabledReason::DISABLED_BY_WRONG_PASSWORD,
50          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
51         {DisabledReason::DISABLED_AUTHENTICATION_NO_SUBSCRIPTION,
52          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
53         {DisabledReason::DISABLED_AUTHENTICATION_PRIVATE_EAP_ERROR,
54          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
55         {DisabledReason::DISABLED_NETWORK_NOT_FOUND,
56          DisablePolicy(5 * 60 * 1000 * 1000, 2, WifiDeviceConfigStatus::DISABLED)},
57         {DisabledReason::DISABLED_CONSECUTIVE_FAILURES,
58          DisablePolicy(5 * 60 * 1000 * 1000, 1, WifiDeviceConfigStatus::DISABLED)},
59         {DisabledReason::DISABLED_BY_SYSTEM,
60          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
61         {DisabledReason::DISABLED_EAP_AKA_FAILURE,
62          DisablePolicy(-1, 1, WifiDeviceConfigStatus::PERMEMANTLY_DISABLED)},
63         {DisabledReason::DISABLED_DISASSOC_REASON,
64          DisablePolicy(5 * 60 * 1000 * 1000, 5, WifiDeviceConfigStatus::DISABLED)},
65     };
66 
67     validReasons = {
68         static_cast<int>(DisconnectDetailReason::UNSPECIFIED),
69         static_cast<int>(DisconnectDetailReason::PREV_AUTH_NOT_VALID),
70         static_cast<int>(DisconnectDetailReason::DISASSOC_DUE_TO_INACTIVITY),
71         static_cast<int>(DisconnectDetailReason::DISASSOC_AP_BUSY),
72         static_cast<int>(DisconnectDetailReason::DISASSOC_STA_HAS_LEFT),
73         static_cast<int>(DisconnectDetailReason::DISASSOC_IEEE_802_1X_AUTH_FAILED),
74         static_cast<int>(DisconnectDetailReason::DISASSOC_LOW_ACK)
75     };
76 
77     mLastConnectedApInfo = {"", -1, 0};
78 }
79 
80 // Destructor
~BlockConnectService()81 BlockConnectService::~BlockConnectService()
82 {
83     // Clean up any resources
84     blockConnectPolicies.clear();
85 }
86 
Exit()87 void BlockConnectService::Exit()
88 {
89     // Implement the logic to exit the service
90     // Clean up any resources
91     blockConnectPolicies.clear();
92     mLastConnectedApInfo = {"", -1, 0};
93 }
94 
95 // Method to check if auto connect is enabled for a given WifiDeviceConfig
ShouldAutoConnect(const WifiDeviceConfig & config)96 bool BlockConnectService::ShouldAutoConnect(const WifiDeviceConfig &config)
97 {
98     // Return true if auto connect is enabled, false otherwise
99     WIFI_LOGD("ENTER shouldAutoConnect %{public}d",
100               config.networkSelectionStatus.status == WifiDeviceConfigStatus::ENABLED);
101     return config.networkSelectionStatus.status == WifiDeviceConfigStatus::ENABLED;
102 }
103 
104 // Update the selection status of all saved networks and check if disabled networks have expired
UpdateAllNetworkSelectStatus()105 bool BlockConnectService::UpdateAllNetworkSelectStatus()
106 {
107     WIFI_LOGD("ENTER updateAllNetworkSelectStatus");
108     // Implement the logic to update the selection status of all saved networks
109     // and check if disabled networks have expired
110     // Return true if successful, false otherwise
111     int64_t timestamp = GetElapsedMicrosecondsSinceBoot();
112     std::vector<WifiDeviceConfig> results;
113     if (WifiSettings::GetInstance().GetDeviceConfig(results) != 0) {
114         WIFI_LOGE("Failed to get device config");
115         return false;
116     }
117     for (auto &config : results) {
118         if (config.networkSelectionStatus.status == WifiDeviceConfigStatus::ENABLED) {
119             continue;
120         }
121         DisablePolicy policy = CalculateDisablePolicy(config.networkSelectionStatus.networkSelectionDisableReason);
122         if (policy.disableStatus == WifiDeviceConfigStatus::PERMEMANTLY_DISABLED) {
123             LogDisabledConfig(config);
124             continue;
125         }
126         if (policy.disableStatus == WifiDeviceConfigStatus::ENABLED ||
127             timestamp - config.networkSelectionStatus.networkDisableTimeStamp >= policy.disableTime) {
128             config.networkSelectionStatus.status = WifiDeviceConfigStatus::ENABLED;
129             config.networkSelectionStatus.networkSelectionDisableReason = DisabledReason::DISABLED_NONE;
130             config.networkSelectionStatus.networkDisableTimeStamp = -1;
131             config.networkSelectionStatus.networkDisableCount = 0;
132             WifiSettings::GetInstance().AddDeviceConfig(config);
133         }
134         LogDisabledConfig(config);
135     }
136     return true;
137 }
138 
139 // Enable the selection status of a target network
EnableNetworkSelectStatus(int targetNetworkId)140 bool BlockConnectService::EnableNetworkSelectStatus(int targetNetworkId)
141 {
142     WIFI_LOGD("ENTER EnableNetworkSelectStatus");
143     // Implement the logic to enable the selection status of a target network
144     // Return true if successful, false otherwise
145     WifiDeviceConfig targetNetwork;
146     if (WifiSettings::GetInstance().GetDeviceConfig(targetNetworkId, targetNetwork)) {
147         WIFI_LOGE("Failed to get device config %{public}d", targetNetworkId);
148         return false;
149     }
150     targetNetwork.networkSelectionStatus.status = WifiDeviceConfigStatus::ENABLED;
151     targetNetwork.networkSelectionStatus.networkSelectionDisableReason = DisabledReason::DISABLED_NONE;
152     targetNetwork.networkSelectionStatus.networkDisableTimeStamp = -1;
153     targetNetwork.networkSelectionStatus.networkDisableCount = 0;
154     WifiSettings::GetInstance().AddDeviceConfig(targetNetwork);
155     WIFI_LOGI("EnableNetworkSelectStatus %{public}d %{public}s enabled",
156         targetNetworkId, SsidAnonymize(targetNetwork.ssid).c_str());
157     return true;
158 }
159 
CalculateDisablePolicy(DisabledReason disableReason)160 DisablePolicy BlockConnectService::CalculateDisablePolicy(DisabledReason disableReason)
161 {
162     // Implement the logic to calculate the disable reason based on the disconnect reason
163     // Return the disable reason
164     std::map<DisabledReason, DisablePolicy>::iterator it = blockConnectPolicies.find(disableReason);
165     if (it == blockConnectPolicies.end()) {
166         return DisablePolicy(-1, 0, WifiDeviceConfigStatus::ENABLED);
167     }
168     return it->second;
169 }
170 
171 // Clear the blocklist information of a target network with reason for wpa_supplicant disconnection
UpdateNetworkSelectStatus(int targetNetworkId,DisabledReason disableReason,int wpaReason)172 bool BlockConnectService::UpdateNetworkSelectStatus(int targetNetworkId, DisabledReason disableReason, int wpaReason)
173 {
174     // Implement the logic to clear the blocklist information of a target network
175     // Return true if successful, false otherwise
176     WIFI_LOGD("ENTER updateNetworkSelectStatus");
177     if (disableReason == DisabledReason::DISABLED_DISASSOC_REASON) {
178         if (std::find(validReasons.begin(), validReasons.end(), wpaReason) == validReasons.end()) {
179             return false;
180         }
181     }
182     return UpdateNetworkSelectStatus(targetNetworkId, disableReason);
183 }
184 
185 // Clear the blocklist information of a target network
UpdateNetworkSelectStatus(int targetNetworkId,DisabledReason disableReason)186 bool BlockConnectService::UpdateNetworkSelectStatus(int targetNetworkId, DisabledReason disableReason)
187 {
188     // Implement the logic to clear the blocklist information of a target network
189     // Return true if successful, false otherwise
190     WIFI_LOGD("ENTER updateNetworkSelectStatus");
191     WifiDeviceConfig targetNetwork;
192     int64_t timestamp = GetElapsedMicrosecondsSinceBoot();
193     if (WifiSettings::GetInstance().GetDeviceConfig(targetNetworkId, targetNetwork)) {
194         WIFI_LOGE("Failed to get device config %{public}d", targetNetworkId);
195         return false;
196     }
197     DisablePolicy disablePolicy = CalculateDisablePolicy(disableReason);
198     if (disablePolicy.disableStatus == WifiDeviceConfigStatus::ENABLED) {
199         targetNetwork.networkSelectionStatus.status = WifiDeviceConfigStatus::ENABLED;
200         targetNetwork.networkSelectionStatus.networkSelectionDisableReason = disableReason;
201         targetNetwork.networkSelectionStatus.networkDisableTimeStamp = -1;
202         targetNetwork.networkSelectionStatus.networkDisableCount = 0;
203         return true;
204     }
205     if (targetNetwork.networkSelectionStatus.networkSelectionDisableReason == disableReason) {
206         targetNetwork.networkSelectionStatus.networkDisableCount++;
207     } else {
208         targetNetwork.networkSelectionStatus.networkDisableCount = 1;
209         targetNetwork.networkSelectionStatus.networkSelectionDisableReason = disableReason;
210     }
211 
212     if (targetNetwork.networkSelectionStatus.networkDisableCount >= disablePolicy.disableCount) {
213         targetNetwork.networkSelectionStatus.status = disablePolicy.disableStatus;
214         targetNetwork.networkSelectionStatus.networkSelectionDisableReason = disableReason;
215         targetNetwork.networkSelectionStatus.networkDisableTimeStamp = timestamp;
216     }
217     WifiSettings::GetInstance().AddDeviceConfig(targetNetwork);
218     WIFI_LOGI("updateNetworkSelectStatus networkId %{public}d %{public}s %{public}d",
219         targetNetworkId, SsidAnonymize(targetNetwork.ssid).c_str(), disableReason);
220     return true;
221 }
222 
223 // Check if the given BSSID has frequent disconnects with the last connected network
IsFrequentDisconnect(std::string bssid,int wpaReason)224 bool BlockConnectService::IsFrequentDisconnect(std::string bssid, int wpaReason)
225 {
226     // Implement the logic to check if the given BSSID has frequent disconnects
227     // with the last connected network
228     // Return true if frequent disconnects, false otherwise
229     int64_t timestamp = GetElapsedMicrosecondsSinceBoot();
230     int64_t time_duration = timestamp - mLastConnectedApInfo.lastDisconnectTimestamp;
231     WIFI_LOGD("ENTER isFrequentDisconnect %{public}" PRId64"  %{public}s", time_duration, MacAnonymize(bssid).c_str());
232     WIFI_LOGD("mLastConnectedApInfo alreadyConnectedCount %{public}d", mLastConnectedApInfo.alreadyConnectedCount);
233     mLastConnectedApInfo.lastDisconnectTimestamp = timestamp;
234     if (mLastConnectedApInfo.bssid != bssid) {
235         mLastConnectedApInfo.bssid = bssid;
236         mLastConnectedApInfo.alreadyConnectedCount = 1;
237         return false;
238     }
239 
240     if (time_duration > FREQUENT_DISCONNECT_TIME_INTERVAL_MAX) {
241         mLastConnectedApInfo.bssid = bssid;
242         mLastConnectedApInfo.alreadyConnectedCount = 1;
243         return false;
244     }
245     if (wpaReason == static_cast<int>(DisconnectDetailReason::DEAUTH_STA_IS_LEFING) ||
246         wpaReason == static_cast<int>(DisconnectDetailReason::DISASSOC_STA_HAS_LEFT)) {
247         if (time_duration < FREQUENT_DISCONNECT_TIME_INTERVAL_MIN) {
248             WIFI_LOGD("isFrequentDisconnect case min %{public}s %{public}d  duration %{public}" PRId64,
249                 MacAnonymize(bssid).c_str(), wpaReason, time_duration);
250             mLastConnectedApInfo.alreadyConnectedCount++;
251         }
252     } else if (time_duration < FREQUENT_DISCONNECT_TIME_INTERVAL_MID) {
253         WIFI_LOGD("isFrequentDisconnect case mid %{public}s %{public}d duration %{public}" PRId64,
254             MacAnonymize(bssid).c_str(), wpaReason, time_duration);
255         mLastConnectedApInfo.alreadyConnectedCount++;
256     }
257     if (mLastConnectedApInfo.alreadyConnectedCount >= FREQUENT_DISCONNECT_COUNT) {
258         WIFI_LOGI("isFrequentDisconnect %{public}s %{public}d count %{public}d",
259             MacAnonymize(bssid).c_str(), wpaReason, mLastConnectedApInfo.alreadyConnectedCount);
260         return true;
261     }
262     return false;
263 }
264 
265 // Check if the given targetNetworkId is blocked due to wrong password
IsWrongPassword(int targetNetworkId)266 bool BlockConnectService::IsWrongPassword(int targetNetworkId)
267 {
268     // Implement the logic to check if the given targetNetworkId is blocked due to wrong password
269     // Return true if blocked due to wrong password, false otherwise
270     WifiDeviceConfig targetNetwork;
271     if (WifiSettings::GetInstance().GetDeviceConfig(targetNetworkId, targetNetwork)) {
272         WIFI_LOGE("Failed to get device config %{public}d", targetNetworkId);
273         return false;
274     }
275 
276     if (targetNetwork.numAssociation == 0) {
277         return true;
278     }
279     return false;
280 }
281 
EnableAllNetworksByEnteringSettings(std::vector<DisabledReason> enableReasons)282 void BlockConnectService::EnableAllNetworksByEnteringSettings(std::vector<DisabledReason> enableReasons)
283 {
284     WIFI_LOGI("ENTER EnableAllNetworksByEnteringSettings");
285     std::vector<WifiDeviceConfig> results;
286     if (WifiSettings::GetInstance().GetDeviceConfig(results) != 0) {
287         WIFI_LOGE("Failed to get device config");
288         return;
289     }
290     for (auto &config : results) {
291         if (config.networkSelectionStatus.status == WifiDeviceConfigStatus::ENABLED) {
292             continue;
293         }
294         if (std::find(enableReasons.begin(), enableReasons.end(),
295             config.networkSelectionStatus.networkSelectionDisableReason) != enableReasons.end()) {
296             config.networkSelectionStatus.status = WifiDeviceConfigStatus::ENABLED;
297             config.networkSelectionStatus.networkSelectionDisableReason = DisabledReason::DISABLED_NONE;
298             config.networkSelectionStatus.networkDisableTimeStamp = -1;
299             config.networkSelectionStatus.networkDisableCount = 0;
300             WifiSettings::GetInstance().AddDeviceConfig(config);
301         }
302     }
303 }
304 
OnReceiveSettingsEnterEvent(bool isEnter)305 void BlockConnectService::OnReceiveSettingsEnterEvent(bool isEnter)
306 {
307     WIFI_LOGI("ENTER OnReceiveSettingsEnterEvent %{public}d", static_cast<int>(isEnter));
308     if (isEnter) {
309         std::vector<DisabledReason> enableReasons = {
310             DisabledReason::DISABLED_AUTHENTICATION_FAILURE,
311             DisabledReason::DISABLED_ASSOCIATION_REJECTION,
312             DisabledReason::DISABLED_DHCP_FAILURE,
313             DisabledReason::DISABLED_CONSECUTIVE_FAILURES,
314         };
315         EnableAllNetworksByEnteringSettings(enableReasons);
316     }
317 }
318 
LogDisabledConfig(const WifiDeviceConfig & config)319 void BlockConnectService::LogDisabledConfig(const WifiDeviceConfig &config)
320 {
321     if (config.networkSelectionStatus.status == WifiDeviceConfigStatus::ENABLED) {
322         WIFI_LOGD("%{public}s config is ENABLED", SsidAnonymize(config.ssid).c_str());
323         return;
324     }
325     if (config.networkSelectionStatus.status == WifiDeviceConfigStatus::DISABLED) {
326         WIFI_LOGI("%{public}s config is DISABLED due to reason: %{public}d",
327             SsidAnonymize(config.ssid).c_str(), config.networkSelectionStatus.networkSelectionDisableReason);
328         return;
329     }
330     if (config.networkSelectionStatus.status == WifiDeviceConfigStatus::PERMEMANTLY_DISABLED) {
331         WIFI_LOGI("%{public}s  networkId :%{public}d config is PERMEMANTLY DISABLED due to reason: %{public}d",
332             SsidAnonymize(config.ssid).c_str(), config.networkId,
333             config.networkSelectionStatus.networkSelectionDisableReason);
334         return;
335     }
336 }
337 }
338 }