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 "sta_auto_connect_service.h"
16 #include "wifi_logger.h"
17 #include "wifi_sta_hal_interface.h"
18 #include "wifi_config_center.h"
19 #include "wifi_common_util.h"
20 #include "block_connect_service.h"
21 
22 DEFINE_WIFILOG_LABEL("StaAutoConnectService");
23 
24 namespace OHOS {
25 namespace Wifi {
StaAutoConnectService(StaStateMachine * staStateMachine,int instId)26 StaAutoConnectService::StaAutoConnectService(StaStateMachine *staStateMachine, int instId)
27     : pStaStateMachine(staStateMachine),
28       pSavedDeviceAppraisal(nullptr),
29       firmwareRoamFlag(true),
30       maxBlockedBssidNum(BLOCKLIST_INVALID_SIZE),
31       selectDeviceLastTime(0),
32       pAppraisals {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
33       m_instId(instId)
34 {}
35 
~StaAutoConnectService()36 StaAutoConnectService::~StaAutoConnectService()
37 {
38     WIFI_LOGI("Enter ~StaAutoConnectService.\n");
39     if (pSavedDeviceAppraisal != nullptr) {
40         delete pSavedDeviceAppraisal;
41         pSavedDeviceAppraisal = nullptr;
42     }
43 }
44 
InitAutoConnectService()45 ErrCode StaAutoConnectService::InitAutoConnectService()
46 {
47     WIFI_LOGI("Enter InitAutoConnectService.\n");
48 
49     if (ObtainRoamCapFromFirmware()) {
50         WIFI_LOGI("Succeeded in obtaining firmware roaming information.\n");
51     }
52     SyncBlockedSsidFirmware();
53 
54     pSavedDeviceAppraisal = new (std::nothrow) StaSavedDeviceAppraisal(firmwareRoamFlag);
55     if (pSavedDeviceAppraisal == nullptr) {
56         WIFI_LOGE("savedDeviceAppraisal is null\n");
57         return WIFI_OPT_FAILED;
58     }
59     pNetworkSelectionManager = std::make_unique<NetworkSelectionManager>();
60     int savedPriority = WifiSettings::GetInstance().GetSavedDeviceAppraisalPriority(m_instId);
61     if (RegisterDeviceAppraisal(pSavedDeviceAppraisal, savedPriority)) {
62         WIFI_LOGI("RegisterSavedDeviceAppraisal succeeded.\n");
63     }
64     return WIFI_OPT_SUCCESS;
65 }
66 
SetAutoConnectStateCallback(const std::vector<StaServiceCallback> & callbacks)67 void StaAutoConnectService::SetAutoConnectStateCallback(const std::vector<StaServiceCallback> &callbacks)
68 {
69     WIFI_LOGI("Enter SetAutoConnectStateCallback.\n");
70     mStaCallbacks = callbacks;
71 }
72 
OnScanInfosReadyHandler(const std::vector<InterScanInfo> & scanInfos)73 void StaAutoConnectService::OnScanInfosReadyHandler(const std::vector<InterScanInfo> &scanInfos)
74 {
75     WIFI_LOGI("Enter OnScanInfosReadyHandler.\n");
76     ClearOvertimeBlockedBssid(); /* Refreshing the BSSID Blocklist */
77 
78     WifiLinkedInfo info;
79     WifiConfigCenter::GetInstance().GetLinkedInfo(info, m_instId);
80     if (info.supplicantState == SupplicantState::ASSOCIATING ||
81         info.supplicantState == SupplicantState::ASSOCIATED ||
82         info.supplicantState == SupplicantState::AUTHENTICATING ||
83         info.supplicantState == SupplicantState::FOUR_WAY_HANDSHAKE ||
84         info.supplicantState == SupplicantState::GROUP_HANDSHAKE) {
85         WIFI_LOGE("Supplicant is under transient state.\n");
86         return;
87     }
88 
89     if (info.connState == ConnState::CONNECTED) {
90         ClearAllBlockedBssids();
91     }
92     std::vector<std::string> blockedBssids;
93     GetBlockedBssids(blockedBssids);
94     if (!AllowAutoSelectDevice(info) || !IsAllowAutoJoin()) {
95         return;
96     }
97     BlockConnectService::GetInstance().UpdateAllNetworkSelectStatus();
98     NetworkSelectionResult networkSelectionResult;
99     if (pNetworkSelectionManager->SelectNetwork(networkSelectionResult, NetworkSelectType::AUTO_CONNECT, scanInfos)) {
100         int networkId = networkSelectionResult.wifiDeviceConfig.networkId;
101         std::string &bssid = networkSelectionResult.interScanInfo.bssid;
102         std::string &ssid = networkSelectionResult.interScanInfo.ssid;
103         WIFI_LOGI("AutoSelectDevice networkId: %{public}d, ssid: %{public}s, bssid: %{public}s.", networkId,
104                   SsidAnonymize(ssid).c_str(), MacAnonymize(bssid).c_str());
105         auto message = pStaStateMachine->CreateMessage(WIFI_SVR_CMD_STA_CONNECT_SAVED_NETWORK);
106         message->SetParam1(networkId);
107         message->SetParam2(NETWORK_SELECTED_BY_AUTO);
108         message->AddStringMessageBody(bssid);
109         pStaStateMachine->SendMessage(message);
110     } else {
111         WIFI_LOGI("AutoSelectDevice return fail.");
112     }
113     for (const auto &callBackItem : mStaCallbacks) {
114         if (callBackItem.OnAutoSelectNetworkRes != nullptr) {
115             callBackItem.OnAutoSelectNetworkRes(networkSelectionResult.wifiDeviceConfig.networkId, m_instId);
116         }
117     }
118 }
119 
EnableOrDisableBssid(std::string bssid,bool enable,int reason)120 bool StaAutoConnectService::EnableOrDisableBssid(std::string bssid, bool enable, int reason)
121 {
122     WIFI_LOGI("Enter EnableOrDisableBssid.\n");
123     if (bssid.empty()) {
124         WIFI_LOGI("bssid is empty.\n");
125         return false;
126     }
127 
128     /* Updating the BSSID Blocklist */
129     if (!AddOrDelBlockedBssids(bssid, enable, reason)) {
130         WIFI_LOGI("The blocklist is not updated.\n");
131         return false;
132     }
133 
134     /* The blocklist has been updated, so update the firmware roaming */
135     /* configuration */
136     SyncBlockedSsidFirmware();
137     return true;
138 }
139 
AddOrDelBlockedBssids(std::string bssid,bool enable,int reason)140 bool StaAutoConnectService::AddOrDelBlockedBssids(std::string bssid, bool enable, int reason)
141 {
142     std::lock_guard<std::mutex> lock(m_blockBssidMapMutex);
143     WIFI_LOGI("Enter AddOrDelBlockedBssids.\n");
144     if (enable) {
145         if (blockedBssidMap.count(bssid) != 0) {
146             /* Removed the BSSID from the blocklist When the BSSID is enabled. */
147             blockedBssidMap.erase(bssid);
148             return true;
149         }
150         return false;
151     }
152 
153     BlockedBssidInfo status;
154     auto iter = blockedBssidMap.find(bssid);
155     if (iter == blockedBssidMap.end()) {
156         blockedBssidMap.emplace(bssid, status);
157     }
158     auto iterator = blockedBssidMap.find(bssid);
159     if (iterator == blockedBssidMap.end()) {
160         return false;
161     }
162     iterator->second.count++;
163     time_t now = time(nullptr);
164     if (now == static_cast<time_t>(-1)) {
165         return false;
166     }
167     iterator->second.blockedTime = static_cast<int>(now);
168     if (!iterator->second.blockedFlag) {
169         if (iterator->second.count >= MAX_BSSID_BLOCKLIST_COUNT ||
170             reason == AP_CANNOT_HANDLE_NEW_STA) {
171             iterator->second.blockedFlag = true;
172             return true;
173         }
174     }
175     return false;
176 }
177 
GetBlockedBssids(std::vector<std::string> & blockedBssids)178 void StaAutoConnectService::GetBlockedBssids(std::vector<std::string> &blockedBssids)
179 {
180     std::lock_guard<std::mutex> lock(m_blockBssidMapMutex);
181     for (auto iter = blockedBssidMap.begin(); iter != blockedBssidMap.end(); ++iter) {
182         blockedBssids.push_back(iter->first);
183     }
184     WIFI_LOGD("GetBlockedBssids, blockedBssids count: %{public}d.", (int)blockedBssids.size());
185     return;
186 }
187 
ClearAllBlockedBssids()188 void StaAutoConnectService::ClearAllBlockedBssids()
189 {
190     std::lock_guard<std::mutex> lock(m_blockBssidMapMutex);
191     WIFI_LOGI("Enter ClearAllBlockedBssids.\n");
192     blockedBssidMap.clear();
193     return;
194 }
195 
ClearOvertimeBlockedBssid()196 void StaAutoConnectService::ClearOvertimeBlockedBssid()
197 {
198     std::lock_guard<std::mutex> lock(m_blockBssidMapMutex);
199     WIFI_LOGI("Enter ClearOvertimeBlockedBssid.\n");
200     if (blockedBssidMap.empty()) {
201         WIFI_LOGI("blockedBssidMap is empty !\n");
202         return;
203     }
204     bool updated = false;
205     auto iter = blockedBssidMap.begin();
206     while (iter != blockedBssidMap.end()) {
207         BlockedBssidInfo status = iter->second;
208         time_t now = time(nullptr);
209         int currentTimeStap = static_cast<int>(now);
210         WIFI_LOGI("blockedFlag:%{public}d, currentTimeStap:%{public}d, blockedTime:%{public}d.\n",
211             status.blockedFlag, currentTimeStap, status.blockedTime);
212         if (status.blockedFlag && ((currentTimeStap - status.blockedTime) >= MAX_BSSID_BLOCKLIST_TIME)) {
213             blockedBssidMap.erase(iter++);
214             updated = true;
215         } else {
216             ++iter;
217         }
218     }
219     if (updated) {
220         SyncBlockedSsidFirmware();
221     }
222     return;
223 }
224 
ConnectElectedDevice(WifiDeviceConfig & electedDevice)225 void StaAutoConnectService::ConnectElectedDevice(WifiDeviceConfig &electedDevice)
226 {
227     WIFI_LOGI("Enter ConnectElectedDevice.\n");
228     if (electedDevice.bssid.empty()) {
229         WIFI_LOGE("electedDevice bssid is empty.");
230         return;
231     }
232 
233     WifiLinkedInfo currentConnectedNetwork;
234     WifiConfigCenter::GetInstance().GetLinkedInfo(currentConnectedNetwork, m_instId);
235     if (currentConnectedNetwork.connState == ConnState::CONNECTED && electedDevice.networkId == INVALID_NETWORK_ID &&
236         currentConnectedNetwork.ssid == electedDevice.ssid && currentConnectedNetwork.bssid != electedDevice.bssid) {
237         /* Frameworks start roaming only when firmware is not supported */
238         if (!firmwareRoamFlag) {
239             WIFI_LOGI("Roaming connectTo, networkId: %{public}d.\n", electedDevice.networkId);
240             pStaStateMachine->StartRoamToNetwork(electedDevice.bssid);
241         }
242     } else if (currentConnectedNetwork.detailedState == DetailedState::DISCONNECTED ||
243         currentConnectedNetwork.detailedState == DetailedState::CONNECTION_TIMEOUT ||
244         currentConnectedNetwork.detailedState == DetailedState::FAILED ||
245         currentConnectedNetwork.detailedState == DetailedState::PASSWORD_ERROR ||
246         currentConnectedNetwork.detailedState == DetailedState::CONNECTION_FULL ||
247         currentConnectedNetwork.detailedState == DetailedState::CONNECTION_REJECT) {
248         pStaStateMachine->SendMessage(WIFI_SVR_CMD_STA_CONNECT_SAVED_NETWORK,
249             electedDevice.networkId,
250             NETWORK_SELECTED_BY_AUTO);
251         WIFI_LOGI("connectTo save networkId: %{public}d, preShareKey len: %{public}d.\n",
252             electedDevice.networkId, (int)electedDevice.preSharedKey.length());
253     } else {
254         WIFI_LOGE("The current connection status is %{public}d.\n", currentConnectedNetwork.detailedState);
255     }
256     return;
257 }
258 
SyncBlockedSsidFirmware()259 void StaAutoConnectService::SyncBlockedSsidFirmware()
260 {
261     WIFI_LOGI("Enter SyncBlockedSsidFirmware.\n");
262     if (!firmwareRoamFlag) {
263         return;
264     }
265     if (maxBlockedBssidNum <= 0) {
266         return;
267     }
268     std::vector<std::string> blockedBssids;
269     GetBlockedBssids(blockedBssids);
270 
271     if (static_cast<int>(blockedBssids.size()) > maxBlockedBssidNum) {
272         blockedBssids.resize(maxBlockedBssidNum);
273     }
274 
275     if (SetRoamBlockedBssidFirmware(blockedBssids)) {
276         WIFI_LOGE("Set firmware roaming configuration succeeded.\n");
277     } else {
278         WIFI_LOGI("Set firmware roaming configuration failed.\n");
279     }
280     return;
281 }
282 
ObtainRoamCapFromFirmware()283 bool StaAutoConnectService::ObtainRoamCapFromFirmware()
284 {
285     WIFI_LOGI("Enter ObtainRoamCapFromFirmware.\n");
286 
287     unsigned int capabilities;
288     if (WifiStaHalInterface::GetInstance().GetStaCapabilities(capabilities) == WIFI_HAL_OPT_OK) {
289         if ((capabilities & STA_CAP_ROAMING) == 0) {
290             WIFI_LOGE("Firmware roaming is not supported.\n");
291             return false;
292         }
293     }
294 
295     WifiHalRoamCapability capability;
296     if (WifiStaHalInterface::GetInstance().GetRoamingCapabilities(capability) == WIFI_HAL_OPT_OK) {
297         if (capability.maxBlocklistSize > 0) {
298             firmwareRoamFlag = true;
299             maxBlockedBssidNum = capability.maxBlocklistSize;
300             WIFI_LOGI("Get firmware roaming capabilities succeeded.\n");
301             return true;
302         }
303         WIFI_LOGE("Invalid firmware roaming capabilities.\n");
304     }
305 
306     WIFI_LOGE("Get firmware roaming capabilities failed.\n");
307     return false;
308 }
309 
SetRoamBlockedBssidFirmware(const std::vector<std::string> & blocklistBssids) const310 bool StaAutoConnectService::SetRoamBlockedBssidFirmware(const std::vector<std::string> &blocklistBssids) const
311 {
312     WIFI_LOGI("Enter SetRoamBlockedBssidFirmware.\n");
313     if (!firmwareRoamFlag) {
314         return false;
315     }
316 
317     if (blocklistBssids.empty()) {
318         return false;
319     }
320 
321     if (static_cast<int>(blocklistBssids.size()) > maxBlockedBssidNum) {
322         return false;
323     }
324 
325     WifiHalRoamConfig capability;
326     capability.blocklistBssids = blocklistBssids;
327     if (WifiStaHalInterface::GetInstance().SetRoamConfig(capability) == WIFI_HAL_OPT_OK) {
328         return true;
329     }
330     return false;
331 }
332 
RegisterDeviceAppraisal(StaDeviceAppraisal * appraisal,int priority)333 bool StaAutoConnectService::RegisterDeviceAppraisal(StaDeviceAppraisal *appraisal, int priority)
334 {
335     WIFI_LOGI("Enter RegisterDeviceAppraisal.\n");
336     if (priority < 0 || priority >= MIN_APPRAISAL_PRIORITY) {
337         WIFI_LOGE("Out of array range.\n");
338         return false;
339     }
340     if (pAppraisals[priority] != nullptr) {
341         WIFI_LOGE("Appraisals is not empty.\n");
342         return false;
343     }
344     pAppraisals[priority] = appraisal;
345     return true;
346 }
347 
AutoSelectDevice(WifiDeviceConfig & electedDevice,const std::vector<InterScanInfo> & scanInfos,std::vector<std::string> & blockedBssids,WifiLinkedInfo & info)348 ErrCode StaAutoConnectService::AutoSelectDevice(WifiDeviceConfig &electedDevice,
349     const std::vector<InterScanInfo> &scanInfos, std::vector<std::string> &blockedBssids, WifiLinkedInfo &info)
350 {
351     WIFI_LOGI("Enter SelectNetwork.\n");
352     if (scanInfos.empty()) {
353         WIFI_LOGE("scanInfo is empty.");
354         return WIFI_OPT_FAILED;
355     }
356 
357     /* Whether network selection handover is required */
358     if (!AllowAutoSelectDevice(scanInfos, info)) {
359         WIFI_LOGE("Network switching is not required.\n");
360         return WIFI_OPT_FAILED;
361     }
362 
363     std::vector<InterScanInfo> availableScanInfos;
364     /* Filter out unnecessary networks. */
365     GetAvailableScanInfos(availableScanInfos, scanInfos, blockedBssids, info);
366     if (availableScanInfos.empty()) {
367         WIFI_LOGE("No scanInfo available.\n");
368         return WIFI_OPT_FAILED;
369     }
370     /*
371      * Check the registered network appraisal from highest priority to lowest
372      * priority until the selected network
373      */
374     for (auto registeredAppraisal : pAppraisals) {
375         if (registeredAppraisal != nullptr) {
376             ErrCode code = registeredAppraisal->DeviceAppraisals(electedDevice, availableScanInfos, info);
377             if (code == WIFI_OPT_SUCCESS) {
378                 time_t now = time(nullptr);
379                 selectDeviceLastTime = static_cast<int>(now);
380                 WIFI_LOGI("electedDevice generation.\n");
381                 return WIFI_OPT_SUCCESS;
382             }
383         }
384     }
385 
386     if (RoamingSelection(electedDevice, availableScanInfos, info)) {
387         WIFI_LOGI("Roaming network generation.\n");
388         return WIFI_OPT_SUCCESS;
389     }
390     WIFI_LOGE("No electedDevice.\n");
391     return WIFI_OPT_FAILED;
392 }
393 
RoamingSelection(WifiDeviceConfig & electedDevice,std::vector<InterScanInfo> & availableScanInfos,WifiLinkedInfo & info)394 bool StaAutoConnectService::RoamingSelection(
395     WifiDeviceConfig &electedDevice, std::vector<InterScanInfo> &availableScanInfos, WifiLinkedInfo &info)
396 {
397     for (auto scanInfo : availableScanInfos) {
398         if (info.connState == ConnState::CONNECTED && scanInfo.ssid == info.ssid && scanInfo.bssid != info.bssid) {
399             WIFI_LOGD("Discover roaming networks.\n");
400             if (RoamingEncryptionModeCheck(electedDevice, scanInfo, info)) {
401                 return true;
402             }
403         }
404     }
405     return false;
406 }
407 
RoamingEncryptionModeCheck(WifiDeviceConfig & electedDevice,InterScanInfo scanInfo,WifiLinkedInfo & info)408 bool StaAutoConnectService::RoamingEncryptionModeCheck(
409     WifiDeviceConfig &electedDevice, InterScanInfo scanInfo, WifiLinkedInfo &info)
410 {
411     WifiDeviceConfig network;
412     if (WifiSettings::GetInstance().GetDeviceConfig(scanInfo.ssid, DEVICE_CONFIG_INDEX_SSID, network) == 0) {
413         std::string mgmt = scanInfo.capabilities;
414         if (mgmt.find("WPA-PSK") != std::string::npos || mgmt.find("WPA2-PSK") != std::string::npos) {
415             mgmt = "WPA-PSK";
416         } else if (mgmt.find("EAP") != std::string::npos) {
417             mgmt = "WPA-EAP";
418         } else if (mgmt.find("SAE") != std::string::npos) {
419             mgmt = "SAE";
420         } else {
421             if (mgmt.find("WEP") != std::string::npos && network.wepTxKeyIndex == 0) {
422                 WIFI_LOGE("The roaming network is a WEP network, but the connected network is not a WEP network.\n");
423                 return false;
424             } else if (mgmt.find("WEP") == std::string::npos && network.wepTxKeyIndex != 0) {
425                 WIFI_LOGE("The connected network is a WEP network, but the roaming network is not a WEP network.\n");
426                 return false;
427             }
428             mgmt = "NONE";
429         }
430         if (mgmt == network.keyMgmt) {
431             WIFI_LOGD("The Current network bssid %{public}s signal strength is %{public}d",
432                 MacAnonymize(info.bssid).c_str(), info.rssi);
433             WIFI_LOGD("The Roaming network bssid %{public}s signal strength is %{public}d",
434                 MacAnonymize(scanInfo.bssid).c_str(), scanInfo.rssi);
435             int rssi = scanInfo.rssi - info.rssi;
436             if (rssi > MIN_ROAM_RSSI_DIFF) {
437                 WIFI_LOGD("Roming network rssi - Current network rssi > 6.");
438                 electedDevice.ssid = scanInfo.ssid;
439                 electedDevice.bssid = scanInfo.bssid;
440                 return true;
441             } else {
442                 WIFI_LOGD("Roming network rssi - Current network rssi < 6.");
443             }
444         } else {
445             WIFI_LOGE("The encryption mode does not match.\n");
446         }
447     }
448     return false;
449 }
450 
AllowAutoSelectDevice(OHOS::Wifi::WifiLinkedInfo & info)451 bool StaAutoConnectService::AllowAutoSelectDevice(OHOS::Wifi::WifiLinkedInfo &info)
452 {
453     if (info.connState == DISCONNECTED || info.connState == UNKNOWN) {
454         return true;
455     }
456     WIFI_LOGI("Current linkInfo state:[%{public}d %{public}s] is not in DISCONNECTED state, skip network selection.",
457         info.connState, magic_enum::Enum2Name(info.connState).c_str());
458     return false;
459 }
460 
AllowAutoSelectDevice(const std::vector<InterScanInfo> & scanInfos,WifiLinkedInfo & info)461 bool StaAutoConnectService::AllowAutoSelectDevice(const std::vector<InterScanInfo> &scanInfos, WifiLinkedInfo &info)
462 {
463     WIFI_LOGI("Allow auto select device, connState=%{public}d %{public}s, detailedState=%{public}d %{public}s\n",
464         info.connState, magic_enum::Enum2Name(info.connState).c_str(), info.detailedState,
465         magic_enum::Enum2Name(info.detailedState).c_str());
466     if (scanInfos.empty()) {
467         WIFI_LOGE("No network,skip network selection.\n");
468         return false;
469     }
470 
471     switch (info.detailedState) {
472         case DetailedState::WORKING:
473             /* Configure whether to automatically switch the network. */
474             if (!WifiSettings::GetInstance().GetWhetherToAllowNetworkSwitchover(m_instId)) {
475                 WIFI_LOGE("Automatic network switching is not allowed in user configuration.\n");
476                 return false;
477             }
478             /* Indicates whether the minimum interval is the minimum interval since the last network selection. */
479             if (selectDeviceLastTime != 0) {
480                 int gap = static_cast<int>(time(nullptr)) - selectDeviceLastTime;
481                 if (gap < MIN_SELECT_NETWORK_TIME) {
482                     WIFI_LOGE("%ds time before we selected the network(30s).\n", gap);
483                     return false;
484                 }
485             }
486 
487             if (!CurrentDeviceGoodEnough(scanInfos, info)) {
488                 WIFI_LOGI("The current network is insuffice.\n");
489                 return true;
490             }
491             return false;
492 
493         case DetailedState::DISCONNECTED:
494         case DetailedState::CONNECTION_TIMEOUT:
495         case DetailedState::FAILED:
496         case DetailedState::CONNECTION_REJECT:
497         case DetailedState::CONNECTION_FULL:
498             WIFI_LOGI("Auto Select is allowed, detailedState: %{public}d\n", info.detailedState);
499             return true;
500         case DetailedState::PASSWORD_ERROR:
501             WIFI_LOGI("Password error, clear blocked bssids, auto connect to ap quickly.\n");
502             ClearAllBlockedBssids();
503             return true;
504 
505         case DetailedState::NOTWORKING:
506             WIFI_LOGI("The current network cannot access the Internet.\n");
507             /* Configure whether to automatically switch the network. */
508             if (!WifiSettings::GetInstance().GetWhetherToAllowNetworkSwitchover(m_instId)) {
509                 WIFI_LOGE("Automatic network switching is not allowed in user configuration.\n");
510                 return false;
511             }
512             return true;
513 
514         default:
515             WIFI_LOGE("not allowed auto select!\n");
516             return false;
517     }
518     return false;
519 }
520 
CurrentDeviceGoodEnough(const std::vector<InterScanInfo> & scanInfos,WifiLinkedInfo & info)521 bool StaAutoConnectService::CurrentDeviceGoodEnough(const std::vector<InterScanInfo> &scanInfos, WifiLinkedInfo &info)
522 {
523     WIFI_LOGI("Enter CurrentDeviceGoodEnough.\n");
524 
525     WifiDeviceConfig network;
526 
527     /* The network is deleted */
528     if (WifiSettings::GetInstance().GetDeviceConfig(info.networkId, network) == -1) {
529         WIFI_LOGE("The network is deleted.\n");
530         return false;
531     }
532 
533     int userLastSelectedNetworkId = WifiConfigCenter::GetInstance().GetUserLastSelectedNetworkId(m_instId);
534     if (userLastSelectedNetworkId != INVALID_NETWORK_ID && userLastSelectedNetworkId == network.networkId) {
535         time_t userLastSelectedNetworkTimeVal = WifiConfigCenter::GetInstance().GetUserLastSelectedNetworkTimeVal(
536             m_instId);
537         time_t now = time(nullptr);
538         int interval = static_cast<int>(now - userLastSelectedNetworkTimeVal);
539         if (interval <= TIME_FROM_LAST_SELECTION) {
540             WIFI_LOGI("(60s)Current user recent selections time is %ds.\n", interval);
541             return true;
542         }
543     }
544 
545     /* Temporary network unqualified */
546     if (network.isEphemeral) {
547         WIFI_LOGE("The network is isEphemeral.\n");
548         return false;
549     }
550 
551     if (network.keyMgmt == "NONE" || network.keyMgmt.size() == 0) {
552         WIFI_LOGE("This network No keyMgmt.\n");
553         return false;
554     }
555 
556     /* The signal strength on the live network does not meet requirements. */
557     if (info.rssi < RSSI_DELIMITING_VALUE) {
558         WIFI_LOGE("Signal strength insuffice %{public}d < -65.\n", info.rssi);
559         return false;
560     }
561     /*
562      * The network is a 2.4 GHz network and is not qualified when the 5G network
563      * is available.
564      */
565     if (Whether24GDevice(info.frequency)) {
566         if (WhetherDevice5GAvailable(scanInfos)) {
567             WIFI_LOGE("5 GHz is available when the current frequency band is 2.4 GHz.\n");
568             return false;
569         }
570     }
571     return true;
572 }
573 
WhetherDevice5GAvailable(const std::vector<InterScanInfo> & scanInfos)574 bool StaAutoConnectService::WhetherDevice5GAvailable(const std::vector<InterScanInfo> &scanInfos)
575 {
576     WIFI_LOGI("Enter WhetherDevice5GAvailable.\n");
577     for (auto scaninfo : scanInfos) {
578         if (Whether5GDevice(scaninfo.frequency)) {
579             return true;
580         }
581     }
582     return false;
583 }
584 
Whether24GDevice(int frequency)585 bool StaAutoConnectService::Whether24GDevice(int frequency)
586 {
587     if (frequency > MIN_24_FREQUENCY && frequency < MAX_24_FREQUENCY) {
588         return true;
589     } else {
590         return false;
591     }
592 }
593 
Whether5GDevice(int frequency)594 bool StaAutoConnectService::Whether5GDevice(int frequency)
595 {
596     if (frequency > MIN_5_FREQUENCY && frequency < MAX_5_FREQUENCY) {
597         return true;
598     } else {
599         return false;
600     }
601 }
602 
GetAvailableScanInfos(std::vector<InterScanInfo> & availableScanInfos,const std::vector<InterScanInfo> & scanInfos,std::vector<std::string> & blockedBssids,WifiLinkedInfo & info)603 void StaAutoConnectService::GetAvailableScanInfos(std::vector<InterScanInfo> &availableScanInfos,
604     const std::vector<InterScanInfo> &scanInfos, std::vector<std::string> &blockedBssids, WifiLinkedInfo &info)
605 {
606     WIFI_LOGI("Enter GetAvailableScanInfos.\n");
607     if (scanInfos.empty()) {
608         return;
609     }
610     bool scanInfosContainCurrentBssid = false;
611 
612     for (auto scanInfo : scanInfos) {
613         if (scanInfo.ssid.size() == 0) {
614             continue;
615         }
616 
617         /* Check whether the scanning result contains the current BSSID. */
618         if (info.connState == ConnState::CONNECTED && scanInfo.bssid == info.bssid) {
619             scanInfosContainCurrentBssid = true;
620         }
621 
622         auto itr = find(blockedBssids.begin(), blockedBssids.end(), scanInfo.bssid);
623         if (itr != blockedBssids.end()) { /* Skip Blocklist Network */
624             WIFI_LOGD("Skip blocklistedBssid network, ssid: %{public}s.\n", SsidAnonymize(scanInfo.ssid).c_str());
625             continue;
626         }
627 
628         /* Skipping networks with weak signals */
629         if (scanInfo.frequency < MIN_5GHZ_BAND_FREQUENCY) {
630             if (scanInfo.rssi <= MIN_RSSI_VALUE_24G) {
631                 WIFI_LOGD("Skip network %{public}s with low 2.4G signals %{public}d.\n",
632                     SsidAnonymize(scanInfo.ssid).c_str(), scanInfo.rssi);
633                 continue;
634             }
635         } else {
636             if (scanInfo.rssi <= MIN_RSSI_VALUE_5G) {
637                 WIFI_LOGD("Skip network %{public}s with low 5G signals %{public}d.\n",
638                     SsidAnonymize(scanInfo.ssid).c_str(), scanInfo.rssi);
639                 continue;
640             }
641         }
642         availableScanInfos.push_back(scanInfo);
643     }
644     /*
645      * Some scan requests may not include channels for the currently connected
646      * network, so the currently connected network will not appear in the scan
647      * results. We will not act on these scans to avoid network switching that may
648      * trigger disconnections.
649      */
650     if (info.connState == ConnState::CONNECTED && !scanInfosContainCurrentBssid) {
651         WIFI_LOGI("scanInfo is be cleared.\n");
652         availableScanInfos.clear();
653     }
654     return;
655 }
656 
DisableAutoJoin(const std::string & conditionName)657 void StaAutoConnectService::DisableAutoJoin(const std::string &conditionName)
658 {
659     std::lock_guard<std::mutex> lock(autoJoinMutex);
660     WIFI_LOGI("Auto Join is disabled by %{public}s.", conditionName.c_str());
661     autoJoinConditionsMap.insert_or_assign(conditionName, []() { return false; });
662 }
663 
EnableAutoJoin(const std::string & conditionName)664 void StaAutoConnectService::EnableAutoJoin(const std::string &conditionName)
665 {
666     std::lock_guard<std::mutex> lock(autoJoinMutex);
667     WIFI_LOGI("Auto Join disabled by %{public}s is released.", conditionName.c_str());
668     autoJoinConditionsMap.erase(conditionName);
669 }
670 
RegisterAutoJoinCondition(const std::string & conditionName,const std::function<bool ()> & autoJoinCondition)671 void StaAutoConnectService::RegisterAutoJoinCondition(const std::string &conditionName,
672                                                       const std::function<bool()> &autoJoinCondition)
673 {
674     if (!autoJoinCondition) {
675         WIFI_LOGE("the condition of %{public}s is empty.", conditionName.c_str());
676         return;
677     }
678     std::lock_guard<std::mutex> lock(autoJoinMutex);
679     WIFI_LOGI("Auto Join condition of %{public}s is registered.", conditionName.c_str());
680     autoJoinConditionsMap.insert_or_assign(conditionName, autoJoinCondition);
681 }
682 
DeregisterAutoJoinCondition(const std::string & conditionName)683 void StaAutoConnectService::DeregisterAutoJoinCondition(const std::string &conditionName)
684 {
685     std::lock_guard<std::mutex> lock(autoJoinMutex);
686     WIFI_LOGI("Auto Join condition of %{public}s is deregistered.", conditionName.c_str());
687     autoJoinConditionsMap.erase(conditionName);
688 }
689 
IsAllowAutoJoin()690 bool StaAutoConnectService::IsAllowAutoJoin()
691 {
692     std::lock_guard<std::mutex> lock(autoJoinMutex);
693     for (auto condition = autoJoinConditionsMap.rbegin(); condition != autoJoinConditionsMap.rend(); ++condition) {
694         if (!condition->second.operator()()) {
695             WIFI_LOGI("Auto Join is not allowed because of %{public}s.", condition->first.c_str());
696             return false;
697         }
698     }
699     return true;
700 }
701 }  // namespace Wifi
702 }  // namespace OHOS
703