/* * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "cpp_bindings.h" #include "gscan.h" class GetChannelListCommand : public WifiCommand { std::vector mFreqs; int mBand; public: GetChannelListCommand(wifiInterfaceHandle iface, int band) : WifiCommand("GetChannelListCommand", iface, 0), mBand(band) {} int Create() override { int ret = mMsg.Create(FamilyId(), NL80211_CMD_GET_WIPHY, NLM_F_DUMP, 0); if (ret < 0) { HDF_LOGE("Can't create message to send to driver - %{public}d", ret); return ret; } mMsg.PutFlag(NL80211_ATTR_SPLIT_WIPHY_DUMP); ret = mMsg.PutU32(NL80211_ATTR_IFINDEX, IfaceId()); if (ret < 0) { HDF_LOGE("put ifaceid fail %{public}d", IfaceId()); } return ret; } void AddFreqs(bool& isDfsChannel, uint32_t& freq) { switch (mBand) { case SCAN_BAND_24_GHZ: if (freq > LOW_LIMIT_FREQ_2_4G && freq < HIGH_LIMIT_FREQ_2_4G) { mFreqs.push_back(freq); } break; case SCAN_BAND_5_GHZ: if (isDfsChannel) { break; } if (freq > LOW_LIMIT_FREQ_5G && freq < HIGH_LIMIT_FREQ_5G) { mFreqs.push_back(freq); } break; case SCAN_BAND_5_GHZ_DFS_ONLY: if (isDfsChannel && freq > LOW_LIMIT_FREQ_5G && freq < HIGH_LIMIT_FREQ_5G) { mFreqs.push_back(freq); } break; case SCAN_BAND_5_GHZ_WITH_DFS: if (freq > LOW_LIMIT_FREQ_5G && freq < HIGH_LIMIT_FREQ_5G) { mFreqs.push_back(freq); } break; default: break; } } void GetCenterFreq(struct nlattr *bands) { struct nlattr *attrFreq[NL80211_FREQUENCY_ATTR_MAX + 1]; struct nlattr *nlFreq = nullptr; void *data = nullptr; int32_t len; int32_t i; uint32_t freq; static struct nla_policy freqPolicy[NL80211_FREQUENCY_ATTR_MAX + 1]; freqPolicy[NL80211_FREQUENCY_ATTR_FREQ].type = NLA_U32; freqPolicy[NL80211_FREQUENCY_ATTR_MAX_TX_POWER].type = NLA_U32; enum nl80211_dfs_state dfsState; nla_for_each_nested(nlFreq, bands, i) { data = nla_data(nlFreq); len = nla_len(nlFreq); if (nla_parse(attrFreq, NL80211_FREQUENCY_ATTR_MAX, (struct nlattr *)data, len, freqPolicy) != 0) { HDF_LOGE("GetCenterFreq parse failed"); continue; } if (attrFreq[NL80211_FREQUENCY_ATTR_FREQ] == nullptr) { continue; } if (attrFreq[NL80211_FREQUENCY_ATTR_DISABLED] != nullptr) { continue; } bool isDfsChannel = false; if (attrFreq[NL80211_FREQUENCY_ATTR_DFS_STATE] != nullptr) { dfsState = static_cast( nla_get_u32(attrFreq[NL80211_FREQUENCY_ATTR_DFS_STATE])); isDfsChannel = (dfsState == NL80211_DFS_USABLE || dfsState == NL80211_DFS_AVAILABLE); } freq = nla_get_u32(attrFreq[NL80211_FREQUENCY_ATTR_FREQ]); AddFreqs(isDfsChannel, freq); } } std::vector &GetFreqs() { return mFreqs; } protected: int HandleResponse(WifiEvent& reply) override { struct nlattr *attrBand[NL80211_BAND_ATTR_MAX + 1]; struct nlattr *nlBand = nullptr; struct nlattr **attr = reply.Attributes(); int32_t i; void *data = nullptr; int32_t len; if (!attr[NL80211_ATTR_WIPHY_BANDS]) { return NL_SKIP; } struct nlattr *attrWiphyBands = attr[NL80211_ATTR_WIPHY_BANDS]; if (attrWiphyBands == nullptr) { return NL_SKIP; } nla_for_each_nested(nlBand, attrWiphyBands, i) { data = nla_data(nlBand); len = nla_len(nlBand); nla_parse(attrBand, NL80211_BAND_ATTR_MAX, (struct nlattr *)data, len, NULL); if (attrBand[NL80211_BAND_ATTR_FREQS] == nullptr) { continue; } GetCenterFreq(attrBand[NL80211_BAND_ATTR_FREQS]); } return NL_OK; } }; WifiError VendorHalGetChannelsInBand(wifiInterfaceHandle handle, int band, std::vector& freqs) { HDF_LOGI("VendorHalGetChannelsInBand band = %{public}d", band); if (!handle) { HDF_LOGE("Handle is null"); return HAL_INVALID_ARGS; } if (band > SCAN_BAND_BOTH_WITH_DFS || band <= SCAN_BAND_UNSPECIFIED) { HDF_LOGE("Invalid input parameter, band = %{public}d", band); return HAL_INVALID_ARGS; } GetChannelListCommand command(handle, band); auto lock = ReadLockData(); int ret = command.RequestResponse(); if (ret < 0) { return HAL_NONE; } freqs = command.GetFreqs(); return HAL_SUCCESS; }