1/*
2 * Copyright (c) 2024 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.h"
17#include <hdf_base.h>
18#include <hdf_log.h>
19#include "wifi_hal.h"
20#include "hdi_sync_util.h"
21#include "iproxy_broker.h"
22
23namespace OHOS {
24namespace HDI {
25namespace Wlan {
26namespace Chip {
27namespace V1_0 {
28#ifdef FEATURE_ANCO_WIFI
29const int CHIP_ID_STA = 1;
30const int CHIP_ID_P2P = 2;
31const int CHIP_ID_AP = 3;
32#endif
33
34static constexpr int32_t K_PRIMARY_CHIP_ID = 0;
35static std::mutex g_chipMutex;
36
37extern "C" IChipController *ChipControllerImplGetInstance(void)
38{
39    static IChipController *gWifiService = NULL;
40    std::unique_lock<std::mutex> lock(g_chipMutex);
41    if (gWifiService == NULL) {
42        gWifiService = new (std::nothrow) Wifi();
43    }
44    return gWifiService;
45}
46
47Wifi::Wifi()
48    :ifaceTool_(std::make_shared<IfaceTool>()),
49    vendorHalList_(std::make_shared<WifiVendorHalList>(ifaceTool_)),
50    runState_(RunState::STOPPED) {
51    remoteDeathRecipient_ =
52        new RemoteDeathRecipient(std::bind(&Wifi::OnRemoteDied, this, std::placeholders::_1));
53}
54
55Wifi::~Wifi()
56{
57    for (const auto& callback : cbHandler_.GetCallbacks()) {
58        if (callback != nullptr) {
59            RemoveWifiDeathRecipient(callback);
60        }
61    }
62    cbHandler_.Invalidate();
63}
64
65int32_t Wifi::RegisterWifiEventCallback(const sptr<IChipControllerCallback>& eventCallback)
66{
67    if (AddWifiDeathRecipient(eventCallback) != HDF_SUCCESS) {
68        return HDF_FAILURE;
69    }
70
71    if (!cbHandler_.AddCallback(eventCallback)) {
72        return HDF_FAILURE;
73    }
74    return HDF_SUCCESS;
75}
76
77int32_t Wifi::IsInit(bool& inited)
78{
79    inited = runState_ != RunState::STOPPED;
80    return HDF_SUCCESS;
81}
82
83int32_t Wifi::Init()
84{
85    HDF_LOGI("Wifi HAL start enter");
86    if (runState_ == RunState::STARTED) {
87        return HDF_SUCCESS;
88    } else if (runState_ == RunState::STOPPING) {
89        return HDF_FAILURE;
90    }
91    ErrorCode res = InitializVendorHal();
92    if (res == ErrorCode::SUCCESS) {
93        const auto& onVendorHalRestartCallback =
94            [this](const std::string& error) {
95            ErrorCode res = ErrorCode::UNKNOWN;
96            for (const auto& callback : cbHandler_.GetCallbacks()) {
97                callback->OnVendorHalRestart(res);
98            }
99        };
100
101        int32_t chipId = K_PRIMARY_CHIP_ID;
102        for (auto& hal : vendorHals_) {
103            chips_.push_back(new WifiChip(
104                chipId, chipId == K_PRIMARY_CHIP_ID, hal,
105                std::make_shared<IfaceUtil>(ifaceTool_),
106                onVendorHalRestartCallback));
107            chipId++;
108        }
109        runState_ = RunState::STARTED;
110        HDF_LOGI("Wifi HAL started");
111        return HDF_SUCCESS;
112    } else {
113        HDF_LOGE("Wifi HAL start failed");
114        return HDF_FAILURE;
115    }
116}
117
118int32_t Wifi::Release()
119{
120    if (runState_ == RunState::STOPPED) {
121        return HDF_SUCCESS;
122    } else if (runState_ == RunState::STOPPING) {
123        return HDF_SUCCESS;
124    }
125    for (auto& chip : chips_) {
126        if (chip) {
127            chip->Invalidate();
128        }
129    }
130    chips_.clear();
131    auto lock = AcquireGlobalLock();
132    ErrorCode res = StopVendorHal(&lock);
133    if (res == ErrorCode::SUCCESS) {
134        return HDF_SUCCESS;
135        HDF_LOGI("Wifi HAL stopped");
136    } else {
137        return HDF_FAILURE;
138        HDF_LOGE("Wifi HAL stop failed");
139    }
140}
141
142int32_t Wifi::GetAvailableChips(std::vector<uint32_t>& chipIds)
143{
144    for (auto& chip : chips_) {
145        uint32_t chipId = GetChipIdFromWifiChip(chip);
146        if (chipId != UINT32_MAX) chipIds.emplace_back(chipId);
147    }
148#ifdef FEATURE_ANCO_WIFI
149    if (chipIds.empty()) {
150        chipIds.emplace_back(CHIP_ID_STA);
151        chipIds.emplace_back(CHIP_ID_P2P);
152        chipIds.emplace_back(CHIP_ID_AP);
153    }
154#endif
155    return HDF_SUCCESS;
156}
157
158int32_t Wifi::GetChipService(uint32_t chipId, sptr<IConcreteChip>& chip)
159{
160    for (auto& ch : chips_) {
161        uint32_t cand_id = GetChipIdFromWifiChip(ch);
162        if ((cand_id != UINT32_MAX) && (cand_id == chipId)) {
163            chip = ch;
164            return HDF_SUCCESS;
165        }
166    }
167    chip = nullptr;
168    return HDF_FAILURE;
169}
170
171ErrorCode Wifi::StopVendorHal(std::unique_lock<std::recursive_mutex>* lock)
172{
173    WifiError legacyStatus = HAL_SUCCESS;
174    int index = 0;
175    ErrorCode res;
176
177    runState_ = RunState::STOPPING;
178    for (auto& hal : vendorHals_) {
179        WifiError tmp = hal->Stop(lock, [&]() {});
180        if (tmp != HAL_SUCCESS) {
181            HDF_LOGE("Failed to stop vendor hal index: %{public}d, error %{public}d", index, tmp);
182            legacyStatus = tmp;
183        }
184        index++;
185    }
186    runState_ = RunState::STOPPED;
187
188    if (legacyStatus != HAL_SUCCESS) {
189        HDF_LOGE("One or more vendor hals failed to stop error is %{public}d", legacyStatus);
190        res = ErrorCode::UNKNOWN;
191        return res;
192    }
193    res = ErrorCode::SUCCESS;
194    return res;
195}
196
197ErrorCode Wifi::InitializVendorHal()
198{
199    ErrorCode res;
200
201    vendorHals_ = vendorHalList_->GetHals();
202    if (vendorHals_.empty()) {
203        res = ErrorCode::UNKNOWN;
204        return res;
205    }
206    int index = 0;
207    for (auto& hal : vendorHals_) {
208        WifiError legacyStatus = hal->Initialize();
209        if (legacyStatus != HAL_SUCCESS) {
210            res = ErrorCode::UNKNOWN;
211            return res;
212        }
213        index++;
214    }
215
216    res = ErrorCode::SUCCESS;
217    return res;
218}
219
220uint32_t Wifi::GetChipIdFromWifiChip(sptr <WifiChip>& chip)
221{
222    uint32_t chipId = UINT32_MAX;
223    int32_t id;
224
225    if (chip) {
226        chip->GetChipId(id);
227        chipId = static_cast<uint32_t>(id);
228    }
229    return chipId;
230}
231
232void Wifi::OnRemoteDied(const wptr<IRemoteObject> &object)
233{
234    HDF_LOGI("chip service OnRemoteDied");
235    runState_ = RunState::STOPPING;
236    for (auto& chip : chips_) {
237        if (chip) {
238            chip->Invalidate();
239        }
240    }
241    chips_.clear();
242    auto lock = AcquireGlobalLock();
243    StopVendorHal(&lock);
244    runState_ = RunState::STOPPED;
245}
246
247int32_t Wifi::AddWifiDeathRecipient(const sptr<IChipControllerCallback>& eventCallback)
248{
249    HDF_LOGI("AddWifiDeathRecipient");
250    const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<IChipControllerCallback>(eventCallback);
251    bool result = remote->AddDeathRecipient(remoteDeathRecipient_);
252    if (!result) {
253        HDF_LOGE("Wifi AddDeathRecipient fail");
254        return HDF_FAILURE;
255    }
256    return HDF_SUCCESS;
257}
258
259int32_t Wifi::RemoveWifiDeathRecipient(const sptr<IChipControllerCallback>& eventCallback)
260{
261    HDF_LOGI("RemoveWifiDeathRecipient");
262    const sptr<IRemoteObject>& remote = OHOS::HDI::hdi_objcast<IChipControllerCallback>(eventCallback);
263    bool result = remote->RemoveDeathRecipient(remoteDeathRecipient_);
264    if (!result) {
265        HDF_LOGE("Wifi RemoveDeathRecipient fail");
266        return HDF_FAILURE;
267    }
268    return HDF_SUCCESS;
269}
270
271} // namespace V1_0
272} // namespace Chip
273} // namespace Wlan
274} // namespace HDI
275} // namespace OHOS