| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * 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 "wifi.h" |
| |
| #include <android-base/logging.h> |
| #include <cutils/properties.h> |
| |
| #include "failure_reason_util.h" |
| #include "wifi_chip.h" |
| |
| using ::android::hardware::wifi::V1_0::CommandFailureReason; |
| using RunState = ::android::hardware::wifi::WifiHalState::RunState; |
| |
| namespace { |
| std::string GetWlanInterfaceName() { |
| char buffer[PROPERTY_VALUE_MAX]; |
| property_get("wifi.interface", buffer, "wlan0"); |
| return buffer; |
| } |
| } |
| |
| namespace android { |
| namespace hardware { |
| namespace wifi { |
| |
| Wifi::Wifi(sp<Looper>& looper) : state_(looper) { |
| CHECK_EQ(init_wifi_vendor_hal_func_table(&state_.func_table_), WIFI_SUCCESS) |
| << "Failed to initialize hal func table"; |
| } |
| |
| Return<void> Wifi::registerEventCallback( |
| const sp<V1_0::IWifiEventCallback>& callback) { |
| // TODO(b/31632518): remove the callback when the client is destroyed |
| callbacks_.insert(callback); |
| return Void(); |
| } |
| |
| Return<bool> Wifi::isStarted() { |
| return state_.run_state_ != RunState::STOPPED; |
| } |
| |
| Return<void> Wifi::start() { |
| if (state_.run_state_ == RunState::STARTED) { |
| for (auto& callback : callbacks_) { |
| callback->onStart(); |
| } |
| return Void(); |
| } else if (state_.run_state_ == RunState::STOPPING) { |
| for (auto& callback : callbacks_) { |
| callback->onStartFailure(CreateFailureReason( |
| CommandFailureReason::NOT_AVAILABLE, "HAL is stopping")); |
| } |
| return Void(); |
| } |
| |
| LOG(INFO) << "Initializing HAL"; |
| wifi_error status = state_.func_table_.wifi_initialize(&state_.hal_handle_); |
| if (status != WIFI_SUCCESS) { |
| LOG(ERROR) << "Failed to initialize Wifi HAL"; |
| for (auto& callback : callbacks_) { |
| callback->onStartFailure(CreateFailureReasonLegacyError( |
| status, "Failed to initialize HAL")); |
| } |
| return Void(); |
| } |
| |
| event_loop_thread_ = std::thread(&Wifi::DoHalEventLoop, this); |
| |
| wifi_interface_handle iface_handle = |
| FindInterfaceHandle(GetWlanInterfaceName()); |
| if (iface_handle != kInterfaceNotFoundHandle) { |
| chip_ = new WifiChip(&state_, iface_handle); |
| } else { |
| // TODO fail to init? |
| } |
| |
| state_.run_state_ = RunState::STARTED; |
| for (auto& callback : callbacks_) { |
| callback->onStart(); |
| } |
| return Void(); |
| } |
| |
| wifi_interface_handle Wifi::FindInterfaceHandle( |
| const std::string& ifname) { |
| int num_iface_handles = 0; |
| wifi_interface_handle* iface_handles = nullptr; |
| wifi_error ret = state_.func_table_.wifi_get_ifaces( |
| state_.hal_handle_, &num_iface_handles, &iface_handles); |
| if (ret != WIFI_SUCCESS) { |
| LOG(ERROR) << "Failed to enumerate interface handles: " |
| << LegacyErrorToString(ret); |
| return kInterfaceNotFoundHandle; |
| } |
| |
| char buffer[IFNAMSIZ]; |
| for (int i = 0; i < num_iface_handles; ++i) { |
| bzero(buffer, sizeof(buffer)); |
| ret = state_.func_table_.wifi_get_iface_name( |
| iface_handles[i], buffer, sizeof(buffer)); |
| if (ret != WIFI_SUCCESS) { |
| LOG(WARNING) << "Failed to get interface handle name: " |
| << LegacyErrorToString(ret); |
| continue; |
| } |
| if (ifname == buffer) { |
| return iface_handles[i]; |
| } |
| } |
| return kInterfaceNotFoundHandle; |
| } |
| |
| |
| void NoopHalCleanupHandler(wifi_handle) {} |
| |
| Return<void> Wifi::stop() { |
| if (state_.run_state_ == RunState::STOPPED) { |
| for (auto& callback : callbacks_) { |
| callback->onStop(); |
| } |
| return Void(); |
| } else if (state_.run_state_ == RunState::STOPPING) { |
| return Void(); |
| } |
| |
| LOG(INFO) << "Cleaning up HAL"; |
| awaiting_hal_cleanup_command_ = true; |
| awaiting_hal_event_loop_termination_ = true; |
| state_.run_state_ = RunState::STOPPING; |
| |
| if (chip_.get()) chip_->Invalidate(); |
| chip_.clear(); |
| |
| state_.func_table_.wifi_cleanup(state_.hal_handle_, NoopHalCleanupHandler); |
| awaiting_hal_cleanup_command_ = false; |
| LOG(VERBOSE) << "HAL cleanup command complete"; |
| FinishHalCleanup(); |
| return Void(); |
| } |
| |
| void Wifi::DoHalEventLoop() { |
| LOG(VERBOSE) << "Starting HAL event loop"; |
| state_.func_table_.wifi_event_loop(state_.hal_handle_); |
| if (state_.run_state_ != RunState::STOPPING) { |
| LOG(FATAL) << "HAL event loop terminated, but HAL was not stopping"; |
| } |
| LOG(VERBOSE) << "HAL Event loop terminated"; |
| event_loop_thread_.detach(); |
| state_.PostTask([this](){ |
| awaiting_hal_event_loop_termination_ = false; |
| FinishHalCleanup(); |
| }); |
| } |
| |
| void Wifi::FinishHalCleanup() { |
| if (!awaiting_hal_cleanup_command_ && !awaiting_hal_event_loop_termination_) { |
| state_.run_state_ = RunState::STOPPED; |
| LOG(INFO) << "HAL cleanup complete"; |
| for (auto& callback : callbacks_) { |
| callback->onStop(); |
| } |
| } |
| } |
| |
| |
| Return<void> Wifi::getChip(getChip_cb cb) { |
| cb(chip_); |
| return Void(); |
| } |
| |
| } // namespace wifi |
| } // namespace hardware |
| } // namespace android |