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
16 #include "ap_config_use.h"
17 #include <algorithm>
18 #include <cstdlib>
19 #include <ctime>
20 #include <iostream>
21 #include <sstream>
22 #include "log_helper.h"
23 #include "wifi_ap_hal_interface.h"
24 #include "wifi_common_util.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_p2p_msg.h"
30 #include "wifi_config_center.h"
31
32 namespace OHOS {
33 namespace Wifi {
34 DEFINE_WIFILOG_HOTSPOT_LABEL("WifiApConfigUse");
35
ApConfigUse(int id)36 ApConfigUse::ApConfigUse(int id) : m_id(id)
37 {
38 m_softapChannelPolicyPtr = std::make_unique<SoftapChannelPolicyParser>();
39 CHECK_NULL_AND_RETURN_NULL(m_softapChannelPolicyPtr);
40 m_softapIndoorChannels = m_softapChannelPolicyPtr->GetAllIndoorChannels();
41 m_softapPreferredChannels = m_softapChannelPolicyPtr->GetAllPreferredChannels();
42 m_softapChannelPolicyPtr = nullptr; // xml loading completed, release pointer
43 }
44
UpdateApChannelConfig(HotspotConfig & apConfig) const45 void ApConfigUse::UpdateApChannelConfig(HotspotConfig &apConfig) const
46 {
47 int bestChannel = AP_CHANNEL_INVALID;
48 switch (apConfig.GetBand()) {
49 case BandType::BAND_2GHZ:
50 bestChannel = GetBestChannelFor2G();
51 break;
52 case BandType::BAND_5GHZ:
53 bestChannel = GetBestChannelFor5G(apConfig);
54 break;
55 default:
56 // BAND_6GHZ, BAND_60GHZ do nothing
57 break;
58 }
59
60 if (bestChannel == AP_CHANNEL_INVALID) {
61 // if there is no suitable channel, use the default band=2.4GHZ, channel=6
62 apConfig.SetBand(BandType::BAND_2GHZ);
63 apConfig.SetChannel(AP_CHANNEL_DEFAULT);
64 } else {
65 apConfig.SetChannel(bestChannel);
66 }
67 JudgeDbacWithP2p(apConfig);
68 WIFI_LOGI("ap config: ssid=%{public}s, preSharedKey=%{public}s, inst_id=%{public}d, band=%{public}d,\
69 channel=%{public}d", SsidAnonymize(apConfig.GetSsid()).c_str(),
70 PassWordAnonymize(apConfig.GetPreSharedKey()).c_str(), m_id, static_cast<int>(apConfig.GetBand()),
71 apConfig.GetChannel());
72 }
73
GetBestChannelFor2G() const74 int ApConfigUse::GetBestChannelFor2G() const
75 {
76 std::vector<int> channels = GetChannelFromDrvOrXmlByBand(BandType::BAND_2GHZ);
77 if (channels.empty()) {
78 WIFI_LOGI("GetBestChannelFor2G is empty");
79 return AP_CHANNEL_INVALID;
80 }
81
82 // randomly select a channel as the best channel
83 return channels[GetRandomInt(0, channels.size() - 1)];
84 }
85
GetBestChannelFor5G(HotspotConfig & apConfig) const86 int ApConfigUse::GetBestChannelFor5G(HotspotConfig &apConfig) const
87 {
88 std::vector<int> channels = GetChannelFromDrvOrXmlByBand(BandType::BAND_5GHZ);
89 FilterIndoorChannel(channels);
90 Filter165Channel(channels);
91 WIFI_LOGD("Instance %{public}d %{public}s band:%{public}d, channel:%{public}d, bandwidth:%{public}d",
92 m_id, __func__, static_cast<int>(apConfig.GetBand()), apConfig.GetChannel(), apConfig.GetBandWidth());
93 if (apConfig.GetBandWidth() == AP_BANDWIDTH_160) {
94 WIFI_LOGI("GetBestChannelFor5G BandWidth is 160M");
95 return AP_CHANNEL_5G_160M_DEFAULT;
96 }
97
98 if (channels.empty()) {
99 WIFI_LOGI("GetBestChannelFor5G is empty");
100 return AP_CHANNEL_INVALID;
101 }
102 for (auto item : channels) {
103 if (AP_CHANNEL_5G_DEFAULT == item) {
104 return AP_CHANNEL_5G_DEFAULT; // channel 149 is preferred for 5G
105 }
106 }
107
108 // randomly select a channel as the best channel
109 return channels[GetRandomInt(0, channels.size() - 1)];
110 }
111
GetChannelFromDrvOrXmlByBand(const BandType & bandType) const112 std::vector<int> ApConfigUse::GetChannelFromDrvOrXmlByBand(const BandType &bandType) const
113 {
114 std::vector<int> preferredChannels = GetPreferredChannelByBand(bandType);
115 if (!preferredChannels.empty()) {
116 WIFI_LOGI("get freqs from xml success, bandType=%{public}d, channel size=%{public}d",
117 static_cast<int>(bandType), static_cast<int>(preferredChannels.size()));
118 return preferredChannels;
119 }
120 std::vector<int> freqs;
121 WifiErrorNo ret = WifiApHalInterface::GetInstance().GetFrequenciesByBand(
122 WifiConfigCenter::GetInstance().GetApIfaceName(), static_cast<int>(bandType), freqs);
123 if (ret != WifiErrorNo::WIFI_HAL_OPT_OK) {
124 WifiSettings::GetInstance().SetDefaultFrequenciesByCountryBand(bandType, freqs);
125 WIFI_LOGI("get freqs from drv fail, use default, bandType=%{public}d, size=%{public}d",
126 static_cast<int>(bandType), static_cast<int>(freqs.size()));
127 } else {
128 WIFI_LOGI("get freqs from drv success, bandType=%{public}d, size=%{public}d",
129 static_cast<int>(bandType), static_cast<int>(freqs.size()));
130 }
131 std::vector<int> channels;
132 TransformFrequencyIntoChannel(freqs, channels);
133 return channels;
134 }
135
FilterIndoorChannel(std::vector<int> & channels) const136 void ApConfigUse::FilterIndoorChannel(std::vector<int> &channels) const
137 {
138 if (channels.empty()) {
139 return;
140 }
141 std::string wifiCountryCode;
142 WifiCountryCodeManager::GetInstance().GetWifiCountryCode(wifiCountryCode);
143 std::set<int> indoorChannels = GetIndoorChanByCountryCode(wifiCountryCode);
144 if (indoorChannels.empty()) {
145 WIFI_LOGI("indoor channel is empty");
146 return;
147 }
148 std::stringstream filteredChannels;
149 std::vector<int> tempChannels;
150 for (auto item : channels) {
151 if (indoorChannels.find(item) == indoorChannels.end()) {
152 tempChannels.push_back(item);
153 continue;
154 }
155 filteredChannels << item << " ";
156 }
157 WIFI_LOGI("filter indoor channels=%{public}s", filteredChannels.str().c_str());
158 channels = std::move(tempChannels);
159 }
160
161 /* Channel 165 cannot be combined with a channel with a bandwidth of 40 MHz or higher.
162 Therefore, channel 165 is not recommended */
Filter165Channel(std::vector<int> & channels) const163 void ApConfigUse::Filter165Channel(std::vector<int> &channels) const
164 {
165 if (channels.empty()) {
166 return;
167 }
168 auto iter = channels.begin();
169 while (iter != channels.end()) {
170 if (AP_CHANNEL_5G_NOT_RECOMMEND == *iter) {
171 channels.erase(iter);
172 WIFI_LOGI("filter not recommend channel=165");
173 return;
174 }
175 iter++;
176 }
177 }
178
JudgeDbacWithP2p(HotspotConfig & apConfig) const179 void ApConfigUse::JudgeDbacWithP2p(HotspotConfig &apConfig) const
180 {
181 WifiP2pLinkedInfo p2pLinkedInfo;
182 WifiConfigCenter::GetInstance().GetP2pInfo(p2pLinkedInfo);
183
184 // When playing the go role on the local end, the P2P and AP channels must be consistent,
185 // but the GC can be inconsistent. If consistency is required, the underlying layer will switch spontaneously.
186 if (p2pLinkedInfo.GetConnectState() != P2pConnectedState::P2P_CONNECTED || !p2pLinkedInfo.IsGroupOwner()) {
187 return;
188 }
189 WifiP2pGroupInfo group = WifiConfigCenter::GetInstance().GetCurrentP2pGroupInfo();
190 int p2pChannel = TransformFrequencyIntoChannel(group.GetFrequency());
191 int apChannel = apConfig.GetChannel();
192 if (IsChannelDbac(p2pChannel, apChannel) && TransformChannelToBand(p2pChannel) != BandType::BAND_NONE) {
193 WIFI_LOGI("dbac, follow the p2p band and channel, p2pChannel=%{public}d", p2pChannel);
194 apConfig.SetBand(TransformChannelToBand(p2pChannel));
195 apConfig.SetChannel(p2pChannel);
196 }
197 }
198
GetIndoorChanByCountryCode(const std::string & countryCode) const199 std::set<int> ApConfigUse::GetIndoorChanByCountryCode(const std::string &countryCode) const
200 {
201 std::set<int> indoorChannelByCode;
202 if (countryCode.empty() || m_softapIndoorChannels.find(countryCode) == m_softapIndoorChannels.end()) {
203 return indoorChannelByCode;
204 }
205 indoorChannelByCode = m_softapIndoorChannels.find(countryCode)->second;
206 return indoorChannelByCode;
207 }
208
GetPreferredChannelByBand(const BandType & bandType) const209 std::vector<int> ApConfigUse::GetPreferredChannelByBand(const BandType &bandType) const
210 {
211 std::vector<int> preferredChannelByBand;
212 if (m_softapPreferredChannels.find(bandType) == m_softapPreferredChannels.end()) {
213 return preferredChannelByBand;
214 }
215 preferredChannelByBand = m_softapPreferredChannels.find(bandType)->second;
216 return preferredChannelByBand;
217 }
218
GetAllIndoorChannels() const219 std::map<std::string, std::set<int>> ApConfigUse::SoftapChannelPolicyParser::GetAllIndoorChannels() const
220 {
221 return m_indoorChannels;
222 }
223
GetAllPreferredChannels() const224 std::map<BandType, std::vector<int>> ApConfigUse::SoftapChannelPolicyParser::GetAllPreferredChannels() const
225 {
226 return m_preferredChannels;
227 }
228
SoftapChannelPolicyParser()229 ApConfigUse::SoftapChannelPolicyParser::SoftapChannelPolicyParser()
230 {
231 g_softapChannelsPolicyMap = {
232 {SoftapChannelPolicyParser::XML_TAG_COUNTRY_CODE,
233 SoftapChannelPolicyParser::SoftapChannelsPolicyType::COUNTRY_CODE},
234 {SoftapChannelPolicyParser::XML_TAG_INDOOR_CHANNELS,
235 SoftapChannelPolicyParser::SoftapChannelsPolicyType::INDOOR_CHANNELS}
236 };
237 g_bandTypeMap = {
238 {SoftapChannelPolicyParser::XML_TAG_CHANNEL_2G_LIST, BandType::BAND_2GHZ},
239 {SoftapChannelPolicyParser::XML_TAG_CHANNEL_5G_LIST, BandType::BAND_5GHZ},
240 {SoftapChannelPolicyParser::XML_TAG_CHANNEL_6G_LIST, BandType::BAND_6GHZ},
241 {SoftapChannelPolicyParser::XML_TAG_CHANNEL_60G_LIST, BandType::BAND_60GHZ}
242 };
243 InitParser();
244 }
245
~SoftapChannelPolicyParser()246 ApConfigUse::SoftapChannelPolicyParser::~SoftapChannelPolicyParser()
247 {
248 m_indoorChannels.clear();
249 m_preferredChannels.clear();
250 }
251
InitParser()252 bool ApConfigUse::SoftapChannelPolicyParser::InitParser()
253 {
254 std::filesystem::path pathName = SOFTAP_CHANNELS_POLICY_FILE_PATH;
255 std::error_code code;
256 if (!std::filesystem::exists(pathName, code)) {
257 LOGI("softap_channels_policy_file.xml not exists, filtering indoor channels is not required");
258 return false;
259 }
260 bool ret = LoadConfiguration(SOFTAP_CHANNELS_POLICY_FILE_PATH);
261 if (!ret) {
262 LOGE("load softap_channels_policy_file fail");
263 return false;
264 }
265 ret = Parse(); // the parent class invokes ParseInternal
266 if (!ret) {
267 WIFI_LOGE("parse softap_channels_policy_file failed");
268 return ret;
269 }
270 return ret;
271 }
272
ParseInternal(xmlNodePtr node)273 bool ApConfigUse::SoftapChannelPolicyParser::ParseInternal(xmlNodePtr node)
274 {
275 if (node == nullptr || xmlStrcmp(node->name, BAD_CAST(XML_TAG_SOFTAP_CHANNELS_POLICY)) != 0) {
276 WIFI_LOGE("softap_channels_policy_file doc invalid");
277 return false;
278 }
279 ParseCountryPolicyList(node);
280 ParsePreferredChannelsList(node);
281 return true;
282 }
283
ParseCountryPolicyList(xmlNodePtr innode)284 void ApConfigUse::SoftapChannelPolicyParser::ParseCountryPolicyList(xmlNodePtr innode)
285 {
286 if (innode == nullptr) {
287 WIFI_LOGE("parse CountryPolicy node is null");
288 return;
289 }
290 xmlNodePtr policyNodeList = GotoCountryPolicy(innode);
291 if (policyNodeList == nullptr) {
292 WIFI_LOGE("policyNodeList is null");
293 return;
294 }
295 for (xmlNodePtr node = policyNodeList->children; node != nullptr; node = node->next) {
296 if (xmlStrcmp(node->name, BAD_CAST(XML_TAG_POLICY_ITEM)) != 0) {
297 continue;
298 }
299 std::string code;
300 std::set<int> channels;
301 for (xmlNodePtr item = node->children; item != nullptr; item = item->next) {
302 switch (GetPolicyItem(item)) {
303 case SoftapChannelsPolicyType::COUNTRY_CODE:
304 code = GetStringValue(item);
305 break;
306 case SoftapChannelsPolicyType::INDOOR_CHANNELS:
307 channels = ParseChannels(item);
308 break;
309 default:
310 break;
311 }
312 }
313 if (IsValidCountryCode(code) && channels.size() > 0) {
314 m_indoorChannels.insert({code, channels});
315 }
316 }
317 WIFI_LOGI("parse CountryPolicy final");
318 }
319
ParseChannels(xmlNodePtr innode)320 std::set<int> ApConfigUse::SoftapChannelPolicyParser::ParseChannels(xmlNodePtr innode)
321 {
322 if (innode == nullptr) {
323 WIFI_LOGE("parse channels node is null");
324 return {};
325 }
326 std::string channelsStr = GetStringValue(innode);
327 if (channelsStr.empty()) {
328 return {};
329 }
330 std::vector<int> channelsVector = SplitStringToIntVector(channelsStr, ",");
331 std::set<int> channelsSet(channelsVector.begin(), channelsVector.end());
332 return channelsSet;
333 }
334
GotoCountryPolicy(xmlNodePtr innode) const335 xmlNodePtr ApConfigUse::SoftapChannelPolicyParser::GotoCountryPolicy(xmlNodePtr innode) const
336 {
337 if (innode == nullptr) {
338 WIFI_LOGE("goto SoftapChannelsPolicy node is null");
339 return nullptr;
340 }
341 for (xmlNodePtr node = innode->children; node != nullptr; node = node->next) {
342 if (xmlStrcmp(node->name, BAD_CAST(XML_TAG_CHANNELS_POLICY)) == 0) {
343 return node;
344 }
345 }
346 return nullptr;
347 }
348
GetPolicyItem(xmlNodePtr node)349 ApConfigUse::SoftapChannelPolicyParser::SoftapChannelsPolicyType ApConfigUse::SoftapChannelPolicyParser::GetPolicyItem(
350 xmlNodePtr node)
351 {
352 if (node == nullptr) {
353 WIFI_LOGE("GetPolicyItem node is null");
354 return SoftapChannelsPolicyType::UNVALID;
355 }
356 std::string tagName = GetNodeValue(node);
357 if (g_softapChannelsPolicyMap.find(tagName) != g_softapChannelsPolicyMap.end()) {
358 return g_softapChannelsPolicyMap.at(tagName);
359 }
360 return SoftapChannelsPolicyType::UNVALID;
361 }
362
ParsePreferredChannelsList(xmlNodePtr innode)363 void ApConfigUse::SoftapChannelPolicyParser::ParsePreferredChannelsList(xmlNodePtr innode)
364 {
365 if (innode == nullptr) {
366 WIFI_LOGE("parse SoftapSupportChannels node is null");
367 return;
368 }
369 xmlNodePtr policyNode = GotoSoftapSupportChannels(innode);
370 if (policyNode == nullptr) {
371 WIFI_LOGE("policyNode is null");
372 return;
373 }
374 for (xmlNodePtr item = policyNode->children; item != nullptr; item = item->next) {
375 std::vector<int> channels;
376 switch (GetSupportChannelsItem(item)) {
377 case BandType::BAND_2GHZ:
378 channels = ParseSupportChannels(item, XML_TAG_CHANNEL_2G_LIST);
379 m_preferredChannels.insert({BandType::BAND_2GHZ, channels});
380 break;
381 case BandType::BAND_5GHZ:
382 channels = ParseSupportChannels(item, XML_TAG_CHANNEL_5G_LIST);
383 m_preferredChannels.insert({BandType::BAND_5GHZ, channels});
384 break;
385 case BandType::BAND_6GHZ:
386 channels = ParseSupportChannels(item, XML_TAG_CHANNEL_6G_LIST);
387 m_preferredChannels.insert({BandType::BAND_6GHZ, channels});
388 break;
389 case BandType::BAND_60GHZ:
390 channels = ParseSupportChannels(item, XML_TAG_CHANNEL_60G_LIST);
391 m_preferredChannels.insert({BandType::BAND_60GHZ, channels});
392 break;
393 default:
394 break;
395 }
396 }
397 WIFI_LOGI("parse SoftapSupportChannels final");
398 }
399
GotoSoftapSupportChannels(xmlNodePtr innode) const400 xmlNodePtr ApConfigUse::SoftapChannelPolicyParser::GotoSoftapSupportChannels(xmlNodePtr innode) const
401 {
402 if (innode == nullptr) {
403 WIFI_LOGE("goto SoftapSupportChannels node is null");
404 return nullptr;
405 }
406 for (xmlNodePtr node = innode->children; node != nullptr; node = node->next) {
407 if (xmlStrcmp(node->name, BAD_CAST(XML_TAG_SOFTAP_SUPPORT_CHANNELS)) == 0) {
408 return node;
409 }
410 }
411 return nullptr;
412 }
413
GetSupportChannelsItem(xmlNodePtr node)414 BandType ApConfigUse::SoftapChannelPolicyParser::GetSupportChannelsItem(xmlNodePtr node)
415 {
416 if (node == nullptr) {
417 WIFI_LOGE("GetSupportChannelsItem node is null");
418 return BandType::BAND_NONE;
419 }
420 std::string tagName = GetNodeValue(node);
421 if (g_bandTypeMap.find(tagName) != g_bandTypeMap.end()) {
422 return g_bandTypeMap.at(tagName);
423 }
424 return BandType::BAND_NONE;
425 }
426
ParseSupportChannels(xmlNodePtr innode,const char * const & bandXml)427 std::vector<int> ApConfigUse::SoftapChannelPolicyParser::ParseSupportChannels(
428 xmlNodePtr innode, const char* const &bandXml)
429 {
430 if (innode == nullptr) {
431 WIFI_LOGE("parse channels node is null");
432 return {};
433 }
434 std::string channelsStr = GetStringValue(innode);
435 if (channelsStr.empty()) {
436 return {};
437 }
438 return SplitStringToIntVector(channelsStr, ",");
439 }
440 } // namespace Wifi
441 } // namespace OHOS