1 /*
2  * Copyright (C) 2021-2022 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 
16 #include "wifi_country_code_policy.h"
17 #include <memory>
18 #ifdef TELEPHONE_CORE_SERVICE_ENABLE
19 #include "core_service_client.h"
20 #endif
21 #ifdef I18N_INTL_UTIL_ENABLE
22 #include "locale_config.h"
23 #endif
24 #include "uri.h"
25 #include "wifi_country_code_manager.h"
26 #include "wifi_global_func.h"
27 #include "wifi_logger.h"
28 #include "wifi_msg.h"
29 #include "wifi_config_center.h"
30 
31 namespace OHOS {
32 namespace Wifi {
33 DEFINE_WIFILOG_LABEL("WifiCountryCodePolicy");
34 
WifiCountryCodePolicy(std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN> wifiCountryCodePolicyConf)35 WifiCountryCodePolicy::WifiCountryCodePolicy(std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN> wifiCountryCodePolicyConf)
36 {
37     CreatePolicy(wifiCountryCodePolicyConf);
38 }
39 
CreatePolicy(std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN> wifiCountryCodePolicyConf)40 void WifiCountryCodePolicy::CreatePolicy(std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN> wifiCountryCodePolicyConf)
41 {
42     WIFI_LOGI("create wifi country code policy");
43     m_policyList.emplace_back(
44         std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByFactory, this, std::placeholders::_1));
45     if (wifiCountryCodePolicyConf[FEATURE_MCC]) {
46         m_policyList.emplace_back(
47             std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByMcc, this, std::placeholders::_1));
48     }
49     if (wifiCountryCodePolicyConf[FEATURE_RCV_AP_CONNECTED]) {
50         m_policyList.emplace_back(
51             std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByAP, this, std::placeholders::_1));
52     }
53     if (wifiCountryCodePolicyConf[FEATURE_RCV_SCAN_RESLUT]) {
54         m_policyList.emplace_back(
55             std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByScanResult, this, std::placeholders::_1));
56     }
57     if (wifiCountryCodePolicyConf[FEATURE_USE_REGION]) {
58         m_policyList.emplace_back(
59             std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByRegion, this, std::placeholders::_1));
60     }
61     if (wifiCountryCodePolicyConf[FEATURE_USE_ZZ]) {
62         m_policyList.emplace_back(
63             std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByDefaultZZ, this, std::placeholders::_1));
64     }
65     m_policyList.emplace_back(
66         std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByCache, this, std::placeholders::_1));
67     m_policyList.emplace_back(
68         std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByDefaultRegion, this, std::placeholders::_1));
69     m_policyList.emplace_back(
70         std::bind(&WifiCountryCodePolicy::GetWifiCountryCodeByDefault, this, std::placeholders::_1));
71 }
72 
CalculateWifiCountryCode(std::string & wifiCountryCode)73 ErrCode WifiCountryCodePolicy::CalculateWifiCountryCode(std::string &wifiCountryCode)
74 {
75     for (const auto &policy : m_policyList) {
76         if (policy(wifiCountryCode) == WIFI_OPT_SUCCESS) {
77             return WIFI_OPT_SUCCESS;
78         }
79     }
80     return WIFI_OPT_FAILED;
81 }
82 
GetWifiCountryCodeByFactory(std::string & wifiCountryCode)83 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByFactory(std::string &wifiCountryCode)
84 {
85     char roRunModeValue[WIFI_COUNTRY_CODE_RUN_MODE_SIZE] = {0};
86     int errorCode = GetParamValue(WIFI_COUNTRY_CODE_RUN_MODE, DEFAULT_RO_RUN_MODE, roRunModeValue,
87         WIFI_COUNTRY_CODE_RUN_MODE_SIZE);
88     if (errorCode <= SYSTEM_PARAMETER_ERROR_CODE || strcasecmp(FACTORY_RO_RUN_MODE, roRunModeValue) != 0) {
89         WIFI_LOGI("wifi country code factory mode does not take effect or fail, ret=%{public}d, "
90             "runMode=%{public}s", errorCode, roRunModeValue);
91         return WIFI_OPT_FAILED;
92     }
93     char factoryWifiCountryCodeValue[FACTORY_WIFI_COUNTRY_CODE_SIZE] = {0};
94     errorCode = GetParamValue(FACTORY_WIFI_COUNTRY_CODE, DEFAULT_WIFI_COUNTRY_CODE,
95         factoryWifiCountryCodeValue, FACTORY_WIFI_COUNTRY_CODE_SIZE);
96     if (errorCode <= SYSTEM_PARAMETER_ERROR_CODE) {
97         WIFI_LOGI("get wifi country code by factory fail, errorCode=%{public}d", errorCode);
98         return WIFI_OPT_FAILED;
99     }
100     if (!IsValidCountryCode(factoryWifiCountryCodeValue)) {
101         WIFI_LOGI("get wifi country code by factory fail, code invalid, code=%{public}s",
102             factoryWifiCountryCodeValue);
103         return WIFI_OPT_FAILED;
104     }
105     wifiCountryCode = factoryWifiCountryCodeValue;
106     WIFI_LOGI("get wifi country code by factory success, code=%{public}s", wifiCountryCode.c_str());
107     return WIFI_OPT_SUCCESS;
108 }
109 
GetWifiCountryCodeByMcc(std::string & wifiCountryCode)110 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByMcc(std::string &wifiCountryCode)
111 {
112     // get cached plmn
113     char cachedPlmn[OPERATOR_NUMERIC_SIZE] = {0};
114     int errorCode = GetParamValue(OPERATOR_NUMERIC_KEY, DEFAULT_OPERATOR_NUMERIC, cachedPlmn, OPERATOR_NUMERIC_SIZE);
115     if (errorCode <= SYSTEM_PARAMETER_ERROR_CODE || strcasecmp(DEFAULT_OPERATOR_NUMERIC, cachedPlmn) == 0) {
116         WIFI_LOGE("get wifi country code by cached mcc fail, ret=%{public}d, cachedPlmn=%{public}s",
117             errorCode, cachedPlmn);
118         return WIFI_OPT_FAILED;
119     }
120     std::string cachedPlmnStr(cachedPlmn);
121     int integerCachedMcc = ConvertStringToInt(cachedPlmnStr.substr(PLMN_SUBSTR_LEFT, PLMN_SUBSTR_RIGHT));
122     if (ConvertMncToIso(integerCachedMcc, wifiCountryCode) != true) {
123         WIFI_LOGE("get wifi country code by cached mcc fail, cached plmn invalid, mcc=%{public}d", integerCachedMcc);
124         return WIFI_OPT_FAILED;
125     }
126 
127     // get dynamic plmn
128     std::string dynamicPlmn;
129 #ifdef TELEPHONE_CORE_SERVICE_ENABLE
130     dynamicPlmn = Str16ToStr8(Telephony::CoreServiceClient::GetInstance().GetOperatorNumeric(SLOT_ID));
131 #endif
132     if (dynamicPlmn.empty() || dynamicPlmn.length() < PLMN_LEN) {
133         WIFI_LOGI("get wifi country code by dynamic mcc fail, plmn invalid, plmn=%{public}s, use cached plmn, "
134             "cache code=%{public}s", dynamicPlmn.c_str(), wifiCountryCode.c_str());
135         return WIFI_OPT_SUCCESS;
136     }
137     int integerMcc = ConvertStringToInt(dynamicPlmn.substr(PLMN_SUBSTR_LEFT, PLMN_SUBSTR_RIGHT));
138     if (ConvertMncToIso(integerMcc, wifiCountryCode) != true) {
139         WIFI_LOGI("get wifi country code by dynamic mcc fail, convert fail, mcc=%{public}d, use cached plmn, "
140             "cache code=%{public}s", integerMcc, wifiCountryCode.c_str());
141         return WIFI_OPT_SUCCESS;
142     }
143     WIFI_LOGI("get wifi country code by dynamic mcc success, mcc=%{public}d, code=%{public}s",
144         integerMcc, wifiCountryCode.c_str());
145     return WIFI_OPT_SUCCESS;
146 }
147 
HandleScanResultAction()148 void WifiCountryCodePolicy::HandleScanResultAction()
149 {
150     std::string tempWifiCountryCode;
151     if (StatisticCountryCodeFromScanResult(tempWifiCountryCode) != WIFI_OPT_SUCCESS) {
152         m_wifiCountryCodeFromScanResults = "";
153         return;
154     }
155     if (!IsValidCountryCode(tempWifiCountryCode)) {
156         WIFI_LOGE("the country code obtained from the scann result is invalid, code=%{public}s",
157             tempWifiCountryCode.c_str());
158         m_wifiCountryCodeFromScanResults = "";
159         return;
160     }
161     m_wifiCountryCodeFromScanResults = tempWifiCountryCode;
162 }
163 
IsContainBssid(const std::vector<std::string> & bssidList,const std::string & bssid)164 bool WifiCountryCodePolicy::IsContainBssid(const std::vector<std::string> &bssidList, const std::string &bssid)
165 {
166     if (bssidList.size() == 0 || bssid.empty()) {
167         return false;
168     }
169     return std::find(bssidList.begin(), bssidList.end(), bssid) != bssidList.end();
170 }
171 
StatisticCountryCodeFromScanResult(std::string & wifiCountryCode)172 ErrCode WifiCountryCodePolicy::StatisticCountryCodeFromScanResult(std::string &wifiCountryCode)
173 {
174     std::vector<WifiScanInfo> results;
175     WifiConfigCenter::GetInstance().GetWifiScanConfig()->GetScanInfoList(results);
176     if (results.size() == 0) {
177         WIFI_LOGI("get scanResult size is 0");
178         return WIFI_OPT_FAILED;
179     }
180     std::vector<std::string> bssidVector;
181     for (auto &scanInfo : results) {
182         std::string tempWifiCountryCode;
183         ErrCode errorCode = ParseCountryCodeElement(scanInfo.infoElems, tempWifiCountryCode);
184         if (errorCode == WIFI_OPT_FAILED || scanInfo.bssid.empty() || tempWifiCountryCode.empty()) {
185             continue;
186         }
187         StrToUpper(tempWifiCountryCode);
188         m_bssidAndCountryCodeMap.insert_or_assign(scanInfo.bssid, tempWifiCountryCode);
189         bssidVector.push_back(scanInfo.bssid);
190     }
191     m_allBssidVector.push_back(bssidVector);
192     if (m_allBssidVector.size() > MAX_SCAN_SAVED_SIZE) {
193         for (const std::string &bssid : m_allBssidVector[BSSID_VECTOR_INDEX_ZERO]) {
194             if (!IsContainBssid(m_allBssidVector[BSSID_VECTOR_INDEX_ONE], bssid) &&
195                 !IsContainBssid(m_allBssidVector[BSSID_VECTOR_INDEX_TWO], bssid) &&
196                 !IsContainBssid(m_allBssidVector[BSSID_VECTOR_INDEX_THREE], bssid)) {
197                 m_bssidAndCountryCodeMap.erase(bssid);  // remove the ap that have not been scanned recently
198             }
199         }
200         m_allBssidVector.erase(m_allBssidVector.begin());
201     }
202     return FindLargestCountCountryCode(wifiCountryCode);
203 }
204 
FindLargestCountCountryCode(std::string & wifiCountryCode)205 ErrCode WifiCountryCodePolicy::FindLargestCountCountryCode(std::string &wifiCountryCode)
206 {
207     std::map<std::string, int> codeCount;  // counting the number of different country codes
208     for (const auto &info : m_bssidAndCountryCodeMap) {
209         codeCount.insert_or_assign(info.second, codeCount[info.second] + 1);
210     }
211     std::vector<std::pair<std::string, int>> sortCode(codeCount.begin(), codeCount.end());
212     sort(sortCode.begin(), sortCode.end(), [](const std::pair<std::string, int> &a,
213         const std::pair<std::string, int> &b) {
214         return a.second > b.second;
215     });
216     if (sortCode.size() == 0) {
217         WIFI_LOGI("country code count is zero");
218         return WIFI_OPT_FAILED;
219     }
220     if (sortCode.size() == 1) {
221         std::pair<std::string, int> oneCode = sortCode[0];
222         wifiCountryCode = oneCode.first;
223         WIFI_LOGI("only one country, code=%{public}s", wifiCountryCode.c_str());
224         return WIFI_OPT_SUCCESS;
225     }
226     std::pair<std::string, int> firstCode = sortCode[0];
227     std::pair<std::string, int> secondCode = sortCode[1];
228     if (firstCode.second == secondCode.second) {
229         WIFI_LOGI("contains two country codes with the same count and the largest count, unable to make decisions,"
230             " code=%{public}s|%{public}s, count=%{public}d",
231             firstCode.first.c_str(), secondCode.first.c_str(), firstCode.second);
232         return WIFI_OPT_FAILED;
233     }
234     wifiCountryCode = firstCode.first;
235     WIFI_LOGI("largest num of country code=%{public}s", wifiCountryCode.c_str());
236     return WIFI_OPT_SUCCESS;
237 }
238 
ParseCountryCodeElement(const std::vector<WifiInfoElem> & infoElems,std::string & wifiCountryCode)239 ErrCode WifiCountryCodePolicy::ParseCountryCodeElement(
240     const std::vector<WifiInfoElem> &infoElems, std::string &wifiCountryCode)
241 {
242     if (infoElems.empty()) {
243         return WIFI_OPT_FAILED;
244     }
245     for (const auto &ie : infoElems) {
246         if (ie.id != COUNTRY_CODE_EID || ie.content.size() < WIFI_COUNTRY_CODE_LEN) {
247             continue;
248         }
249         std::string tempWifiCountryCode;
250         for (int i = 0 ; i < WIFI_COUNTRY_CODE_LEN; i++) {
251             tempWifiCountryCode.push_back(ie.content[i]);
252         }
253         if (!IsValidCountryCode(tempWifiCountryCode)) {
254             continue;
255         }
256         wifiCountryCode = tempWifiCountryCode;
257         return WIFI_OPT_SUCCESS;
258     }
259     return WIFI_OPT_FAILED;
260 }
261 
GetWifiCountryCodeByAP(std::string & wifiCountryCode)262 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByAP(std::string &wifiCountryCode)
263 {
264     WifiLinkedInfo result;
265     WifiConfigCenter::GetInstance().GetLinkedInfo(result);
266     if (static_cast<int>(OHOS::Wifi::ConnState::CONNECTED) != result.connState) {
267         return WIFI_OPT_FAILED;
268     }
269     std::vector<WifiScanInfo> scanResults;
270     WifiConfigCenter::GetInstance().GetWifiScanConfig()->GetScanInfoList(scanResults);
271     if (scanResults.empty()) {
272         return WIFI_OPT_FAILED;
273     }
274     for (auto &info : scanResults) {
275         if (strcasecmp(info.bssid.c_str(), result.bssid.c_str()) == 0 &&
276             ParseCountryCodeElement(info.infoElems, wifiCountryCode) == WIFI_OPT_SUCCESS) {
277             WIFI_LOGI("get wifi country code by ap success, code=%{public}s", wifiCountryCode.c_str());
278             return WIFI_OPT_SUCCESS;
279         }
280     }
281     WIFI_LOGI("get wifi country code by ap fail, the country code of the AP is incorrect or empty");
282     return WIFI_OPT_FAILED;
283 }
284 
GetWifiCountryCodeByScanResult(std::string & wifiCountryCode)285 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByScanResult(std::string &wifiCountryCode)
286 {
287     // if wifi state is not ENABLED, do not obtain the country code from the scan results
288     if (WifiConfigCenter::GetInstance().GetWifiState(SLOT_ID) != static_cast<int>(WifiState::ENABLED) ||
289         m_wifiCountryCodeFromScanResults.empty()) {
290         WIFI_LOGI("get wifi country code by scan result fail, result empty");
291         return WIFI_OPT_FAILED;
292     }
293     wifiCountryCode = m_wifiCountryCodeFromScanResults;
294     WIFI_LOGI("get wifi country code by scan result success, code=%{public}s", wifiCountryCode.c_str());
295     return WIFI_OPT_SUCCESS;
296 }
297 
GetWifiCountryCodeByRegion(std::string & wifiCountryCode)298 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByRegion(std::string &wifiCountryCode)
299 {
300     // the user selects an area in settings
301     std::string tempWifiCountryCode;
302 #ifdef I18N_INTL_UTIL_ENABLE
303     tempWifiCountryCode = Global::I18n::LocaleConfig::GetSystemRegion();
304 #endif
305     if (tempWifiCountryCode.empty() || !IsValidCountryCode(tempWifiCountryCode)) {
306         WIFI_LOGE("get wifi country code by region fail, code=%{public}s", tempWifiCountryCode.c_str());
307         return WIFI_OPT_FAILED;
308     }
309     wifiCountryCode = tempWifiCountryCode;
310     WIFI_LOGI("get wifi country code by region success, code=%{public}s", wifiCountryCode.c_str());
311     return WIFI_OPT_SUCCESS;
312 }
313 
GetWifiCountryCodeByDefaultZZ(std::string & wifiCountryCode)314 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByDefaultZZ(std::string &wifiCountryCode)
315 {
316     wifiCountryCode = DEFAULT_WIFI_COUNTRY_CODE_ZZ;
317     WIFI_LOGI("get wifi country code by default ZZ success, code=%{public}s",
318         DEFAULT_WIFI_COUNTRY_CODE_ZZ);
319     return WIFI_OPT_SUCCESS;
320 }
321 
GetWifiCountryCodeByCache(std::string & wifiCountryCode)322 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByCache(std::string &wifiCountryCode)
323 {
324     char tempWifiCountryCode[WIFI_COUNTRY_CODE_DYNAMIC_UPDATE_SIZE] = {0};
325     int ret = GetParamValue(WIFI_COUNTRY_CODE_DYNAMIC_UPDATE_KEY, DEFAULT_WIFI_COUNTRY_CODE,
326         tempWifiCountryCode, WIFI_COUNTRY_CODE_DYNAMIC_UPDATE_SIZE);
327     if (ret <= SYSTEM_PARAMETER_ERROR_CODE) {
328         WIFI_LOGE("get wifi country code by cache fail, ret=%{public}d", ret);
329         return WIFI_OPT_FAILED;
330     }
331     if (!IsValidCountryCode(tempWifiCountryCode)) {
332         WIFI_LOGE("get wifi country code by cache fail, code invalid, code=%{public}s", tempWifiCountryCode);
333         return WIFI_OPT_FAILED;
334     }
335     wifiCountryCode = tempWifiCountryCode;
336     WIFI_LOGI("get wifi country code by cache success, code=%{public}s", wifiCountryCode.c_str());
337     return WIFI_OPT_SUCCESS;
338 }
339 
GetWifiCountryCodeByDefaultRegion(std::string & wifiCountryCode)340 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByDefaultRegion(std::string &wifiCountryCode)
341 {
342     char defaultRegion[DEFAULT_REGION_SIZE] = {0};
343     int errorCode = GetParamValue(DEFAULT_REGION_KEY,
344         DEFAULT_REGION, defaultRegion, DEFAULT_REGION_SIZE);
345     if (errorCode <= SYSTEM_PARAMETER_ERROR_CODE) {
346         WIFI_LOGI("get wifi country code by default region fail, errorCode=%{public}d", errorCode);
347         return WIFI_OPT_FAILED;
348     }
349     if (!IsValidCountryCode(defaultRegion)) {
350         WIFI_LOGI("get wifi country code by default region fail, code invalid, code=%{public}s", defaultRegion);
351         return WIFI_OPT_FAILED;
352     }
353     wifiCountryCode = defaultRegion;
354     WIFI_LOGI("get wifi country code by default region success, code=%{public}s", wifiCountryCode.c_str());
355     return WIFI_OPT_SUCCESS;
356 }
357 
GetWifiCountryCodeByDefault(std::string & wifiCountryCode)358 ErrCode WifiCountryCodePolicy::GetWifiCountryCodeByDefault(std::string &wifiCountryCode)
359 {
360     wifiCountryCode = DEFAULT_WIFI_COUNTRY_CODE;
361     WIFI_LOGI("get wifi country code by default success, use default code=%{public}s",
362         DEFAULT_WIFI_COUNTRY_CODE);
363     return WIFI_OPT_SUCCESS;
364 }
365 }
366 }