• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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