2f7443f4创建于 2025年8月29日历史提交
/*
 * 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 <cctype>
#include <cerrno>
#include <cstdint>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/nl80211.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include "common.h"
#include "cpp_bindings.h"
#include "gscan.h"

class GetChannelListCommand : public WifiCommand {
    std::vector<uint32_t> 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<nl80211_dfs_state>(
                    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<uint32_t> &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<uint32_t>& 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;
}