1 /*
2  * Copyright (C) 2021-2023 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_manager.h"
17 #include <cstdint>
18 #include <sstream>
19 #include "i_ap_service.h"
20 #include "wifi_ap_hal_interface.h"
21 #include "wifi_common_event_helper.h"
22 #include "wifi_datashare_utils.h"
23 #include "wifi_errcode.h"
24 #include "wifi_global_func.h"
25 #include "wifi_logger.h"
26 #include "wifi_msg.h"
27 #include "wifi_config_center.h"
28 
29 namespace OHOS {
30 namespace Wifi {
31 DEFINE_WIFILOG_LABEL("WifiCountryCodeManager");
32 const std::string CLASS_NAME = "WifiCountryCodeManager";
33 
~WifiCountryCodeManager()34 WifiCountryCodeManager::~WifiCountryCodeManager()
35 {
36     std::lock_guard<std::mutex> lock(m_countryCodeMutex);
37     m_codeChangeListeners.clear();
38 }
39 
GetInstance()40 WifiCountryCodeManager &WifiCountryCodeManager::GetInstance()
41 {
42     static WifiCountryCodeManager instance;
43     return instance;
44 }
45 
Init()46 ErrCode WifiCountryCodeManager::Init()
47 {
48     WIFI_LOGI("init");
49     wifiCountryCodePolicyConf_ = GetWifiCountryCodePolicy();
50     m_wifiCountryCodePolicy = std::make_shared<WifiCountryCodePolicy>(wifiCountryCodePolicyConf_);
51 #ifdef FEATURE_STA_SUPPORT
52     m_staCallback.callbackModuleName = CLASS_NAME;
53     m_staCallback.OnStaConnChanged = DealStaConnChanged;
54 #endif
55 
56 #ifdef FEATURE_AP_SUPPORT
57     m_apCallback.callbackModuleName = CLASS_NAME;
58     m_apCallback.OnApStateChangedEvent = DealApStateChanged;
59 #endif
60     return WIFI_OPT_SUCCESS;
61 }
62 
63 #ifdef FEATURE_STA_SUPPORT
GetStaCallback() const64 StaServiceCallback WifiCountryCodeManager::GetStaCallback() const
65 {
66     return m_staCallback;
67 }
68 #endif
69 
70 #ifdef FEATURE_AP_SUPPORT
GetApCallback() const71 IApServiceCallbacks WifiCountryCodeManager::GetApCallback() const
72 {
73     return m_apCallback;
74 }
75 #endif
76 
GetWifiCountryCode(std::string & wifiCountryCode) const77 void WifiCountryCodeManager::GetWifiCountryCode(std::string &wifiCountryCode) const
78 {
79     wifiCountryCode = m_wifiCountryCode;
80 }
81 
SetWifiCountryCodeFromExternal(const std::string & wifiCountryCode)82 ErrCode WifiCountryCodeManager::SetWifiCountryCodeFromExternal(const std::string &wifiCountryCode)
83 {
84     WIFI_LOGI("set wifi country code from external, externalCode=%{public}s", wifiCountryCode.c_str());
85     return UpdateWifiCountryCode(wifiCountryCode);
86 }
87 
TriggerUpdateWifiCountryCode(int triggerReason)88 void WifiCountryCodeManager::TriggerUpdateWifiCountryCode(int triggerReason)
89 {
90     if (triggerReason == TRIGGER_UPDATE_REASON_TEL_NET_CHANGE && wifiCountryCodePolicyConf_[FEATURE_MCC]) {
91         WIFI_LOGI("TEL_NET_CHANGE trigger update country code change");
92         UpdateWifiCountryCode();
93     } else if (triggerReason == TRIGGER_UPDATE_REASON_SCAN_CHANGE &&
94         wifiCountryCodePolicyConf_[FEATURE_RCV_SCAN_RESLUT] && m_wifiCountryCodePolicy != nullptr) {
95         m_wifiCountryCodePolicy->HandleScanResultAction();
96         UpdateWifiCountryCode();
97     }
98 }
99 
IsAllowUpdateWifiCountryCode()100 bool WifiCountryCodeManager::IsAllowUpdateWifiCountryCode()
101 {
102     bool ret = true;
103 
104     // The Wi-Fi connection has just succeeded. Updating the country code is allowed.
105     if (m_isFirstConnected) {
106         WIFI_LOGI("wifi first connected, allow update wifi country code");
107         m_isFirstConnected = false;
108         return ret;
109     }
110 
111     std::map <int, WifiLinkedInfo> allLinkedInfo = WifiConfigCenter::GetInstance().GetAllWifiLinkedInfo();
112     for (auto item : allLinkedInfo) {
113         if (item.second.connState == ConnState::CONNECTED) {
114             WIFI_LOGI("wifi connected, not allow update wifi country code, instId=%{public}d", item.first);
115             ret = false;
116             break;
117         }
118     }
119     return ret;
120 }
121 
122 /*
123  * Scenarios that trigger country code update, with configuration files controlling the effectiveness of the scenario:
124  * 1 Received a telephone network search state change notify;
125  * 2 Wifi open success;
126  * 3 Softap started;
127  * 4 Update the country code by calling the SetWifiCountryCode interface externally;
128  * 5 Report the scanning result.
129  */
UpdateWifiCountryCode(const std::string & externalCode)130 ErrCode WifiCountryCodeManager::UpdateWifiCountryCode(const std::string &externalCode)
131 {
132     if (!IsAllowUpdateWifiCountryCode()) {
133         return WIFI_OPT_FAILED;
134     }
135     std::string wifiCountryCode;
136     if (!externalCode.empty() && !IsValidCountryCode(externalCode)) {
137         WIFI_LOGI("external set wifi country code, code=%{public}s", externalCode.c_str());
138         wifiCountryCode = externalCode;
139     } else if (m_wifiCountryCodePolicy == nullptr ||
140         m_wifiCountryCodePolicy->CalculateWifiCountryCode(wifiCountryCode) == WIFI_OPT_FAILED) {
141         WIFI_LOGE("calculate wifi country code failed");
142         return WIFI_OPT_FAILED;
143     }
144     StrToUpper(wifiCountryCode);
145     WIFI_LOGI("calculate wifi country code result:%{public}s", wifiCountryCode.c_str());
146     UpdateWifiCountryCodeCache(wifiCountryCode);
147     m_wifiCountryCode = wifiCountryCode;
148     NotifyWifiCountryCodeChangeListeners(wifiCountryCode);
149     return WIFI_OPT_SUCCESS;
150 }
151 
NotifyWifiCountryCodeChangeListeners(const std::string & wifiCountryCode)152 void WifiCountryCodeManager::NotifyWifiCountryCodeChangeListeners(const std::string &wifiCountryCode)
153 {
154     std::lock_guard<std::mutex> lock(m_countryCodeMutex);
155     for (auto &callBackItem : m_codeChangeListeners) {
156         WIFI_LOGI("notify wifi country code change, module name=%{public}s", callBackItem.first.c_str());
157         callBackItem.second->OnWifiCountryCodeChanged(wifiCountryCode);
158     }
159 }
160 
RegisterWifiCountryCodeChangeListener(const std::shared_ptr<IWifiCountryCodeChangeListener> & listener)161 ErrCode WifiCountryCodeManager::RegisterWifiCountryCodeChangeListener(
162     const std::shared_ptr<IWifiCountryCodeChangeListener> &listener)
163 {
164     std::lock_guard<std::mutex> lock(m_countryCodeMutex);
165     if (listener->GetListenerModuleName().empty()) {
166         WIFI_LOGE("register fail, listener module name is null");
167         return WIFI_OPT_FAILED;
168     }
169     m_codeChangeListeners.insert_or_assign(listener->GetListenerModuleName(), listener);
170     WIFI_LOGI("register success, listener module name: %{public}s", listener->GetListenerModuleName().c_str());
171     return WIFI_OPT_SUCCESS;
172 }
173 
UnregisterWifiCountryCodeChangeListener(const std::shared_ptr<IWifiCountryCodeChangeListener> & listener)174 ErrCode WifiCountryCodeManager::UnregisterWifiCountryCodeChangeListener(
175     const std::shared_ptr<IWifiCountryCodeChangeListener> &listener)
176 {
177     return UnregisterWifiCountryCodeChangeListener(listener->GetListenerModuleName());
178 }
179 
UnregisterWifiCountryCodeChangeListener(const std::string & moduleName)180 ErrCode WifiCountryCodeManager::UnregisterWifiCountryCodeChangeListener(const std::string &moduleName)
181 {
182     std::lock_guard<std::mutex> lock(m_countryCodeMutex);
183     if (moduleName.empty()) {
184         WIFI_LOGE("unregister fail, listener module name is null");
185         return WIFI_OPT_FAILED;
186     }
187     int ret = static_cast<int>(m_codeChangeListeners.erase(moduleName));
188     WIFI_LOGI("unregister ret=%{public}d, listener module name: %{public}s", ret, moduleName.c_str());
189     return ret > 0 ? WIFI_OPT_SUCCESS : WIFI_OPT_FAILED;
190 }
191 
192 #ifdef FEATURE_STA_SUPPORT
DealStaOpened(int instId)193 void WifiCountryCodeManager::DealStaOpened(int instId)
194 {
195     WIFI_LOGI("wifi opened, id=%{public}d", instId);
196     WifiCountryCodeManager::GetInstance().UpdateWifiCountryCode();
197 }
198 
DealStaStopped(int instId)199 void WifiCountryCodeManager::DealStaStopped(int instId)
200 {
201     WIFI_LOGI("wifi close, id=%{public}d", instId);
202     std::string moduleName = "StaService_" + std::to_string(instId);
203     WifiCountryCodeManager::GetInstance().UnregisterWifiCountryCodeChangeListener(moduleName);
204 }
205 #endif
206 
207 #ifdef FEATURE_STA_SUPPORT
DealStaConnChanged(OperateResState state,const WifiLinkedInfo & info,int instId)208 void WifiCountryCodeManager::DealStaConnChanged(OperateResState state, const WifiLinkedInfo &info, int instId)
209 {
210     WIFI_LOGD("wifi connection state change, state=%{public}d, id=%{public}d", state, instId);
211     if (state == OperateResState::CONNECT_AP_CONNECTED) {
212         WifiCountryCodeManager::GetInstance().m_isFirstConnected = true;
213         WifiCountryCodeManager::GetInstance().UpdateWifiCountryCode();
214     }
215 }
216 #endif
217 
218 #ifdef FEATURE_AP_SUPPORT
DealApStateChanged(ApState state,int id)219 void WifiCountryCodeManager::DealApStateChanged(ApState state, int id)
220 {
221     WIFI_LOGI("ap state change, state=%{public}d, id=%{public}d", state, id);
222     if (state == ApState::AP_STATE_STARTED) {
223         WifiCountryCodeManager::GetInstance().UpdateWifiCountryCode();
224     } else if (state != ApState::AP_STATE_STARTING && state != ApState::AP_STATE_STARTED) {
225         std::string moduleName = "ApService_" + std::to_string(id);
226         WifiCountryCodeManager::GetInstance().UnregisterWifiCountryCodeChangeListener(moduleName);
227     }
228 }
229 #endif
230 
UpdateWifiCountryCodeCache(const std::string & wifiCountryCode)231 ErrCode WifiCountryCodeManager::UpdateWifiCountryCodeCache(const std::string &wifiCountryCode)
232 {
233     if (wifiCountryCode.empty() || !IsValidCountryCode(wifiCountryCode)) {
234         WIFI_LOGE("wifi country code is empty or invalid");
235         return WIFI_OPT_FAILED;
236     }
237     int ret = SetParamValue(WIFI_COUNTRY_CODE_DYNAMIC_UPDATE_KEY, wifiCountryCode.c_str());
238     std::string retStr = ret == 0 ? "success" : "fail, ret=" + std::to_string(ret);
239     WIFI_LOGI("update wifi country code cache %{public}s", retStr.c_str());
240     return ret == 0 ? WIFI_OPT_SUCCESS : WIFI_OPT_FAILED;
241 }
242 
GetWifiCountryCodePolicy()243 std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN> WifiCountryCodeManager::GetWifiCountryCodePolicy()
244 {
245     char preValue[WIFI_COUNTRY_CODE_SIZE] = {0};
246     int errorCode = GetParamValue(WIFI_COUNTRY_CODE_CONFIG,
247         WIFI_COUNTRY_CODE_CONFIG_DEFAULT, preValue, WIFI_COUNTRY_CODE_SIZE);
248     int policyConf = 0;
249     if (errorCode <= SYSTEM_PARAMETER_ERROR_CODE) {
250         WIFI_LOGI("get wifi country code policy config fail, use policyConf=0");
251         return std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN>(policyConf);
252     }
253     policyConf = ConvertStringToInt(preValue);
254     WIFI_LOGI("get wifi country code policy config is %{public}d", policyConf);
255     return std::bitset<WIFI_COUNTRY_CODE_POLICE_DEF_LEN>(policyConf);
256 }
257 }
258 }