C++程序  |  441行  |  15.05 KB

/*
 * Copyright (C) 2017 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_hal.h>

#include "halstate.h"
#include "info.h"
#include "interface.h"

#include <memory>

template<typename>
struct NotSupportedFunction;

template<typename R, typename... Args>
struct NotSupportedFunction<R (*)(Args...)> {
    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
};

template<typename... Args>
struct NotSupportedFunction<void (*)(Args...)> {
    static constexpr void invoke(Args...) { }
};

template<typename T>
void notSupported(T& val) {
    val = &NotSupportedFunction<T>::invoke;
}

HalState* asHalState(wifi_handle h) {
    return reinterpret_cast<HalState*>(h);
}

Info* asInfo(wifi_handle h) {
    return asHalState(h)->info();
}

Interface* asInterface(wifi_interface_handle h) {
    return reinterpret_cast<Interface*>(h);
}

wifi_error wifi_initialize(wifi_handle* handle) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    // Make the HAL state static inside the function for lazy construction. When
    // stopping we want to keep track of the current HAL state because if the
    // HAL starts again we need to know if we're in a state where we can start
    // or not. If we're stopping with the intention of never starting back up
    // again we could destroy the HAL state. Unfortunately there is no
    // distinction between these two events so the safe choice is to leak this
    // memory and always keep track of the HAL state. This is allocated on the
    // heap instead of the stack to prevent any destructors being called when
    // the dynamic library is being unloaded since the program state could be
    // unreliable at this point.
    static HalState* sHalState = new HalState();

    if (!sHalState->init()) {
        return WIFI_ERROR_UNKNOWN;
    }
    *handle = reinterpret_cast<wifi_handle>(sHalState);

    return WIFI_SUCCESS;
}

void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) {
    if (handle == nullptr) {
        return;
    }

    std::condition_variable condition;
    std::mutex mutex;
    std::unique_lock<std::mutex> lock(mutex);
    bool stopped = false;
    // This lambda will be called when the stop completes. That will notify the
    // condition variable and this function will wake up and exit. This ensures
    // that this function is synchronous. The boolean is to ensure that when
    // waiting we're protected against spurious wakeups, we only exit once the
    // callback has signaled that it's been called.
    auto callback = [&mutex, &stopped, &condition] {
        std::unique_lock<std::mutex> lock(mutex);
        stopped = true;
        condition.notify_all();
    };
    if (asHalState(handle)->stop(callback)) {
        // The handler succeeded and will call our callback, wait for it. If the
        // stop call did not succeed we can't wait for this condition since our
        // callback will never call notify on it.
        while (!stopped) {
            condition.wait(lock);
        }
    }
    // The HAL seems to expect this callback to happen on the same thread, or at
    // least that's what happens in other WiFi HALs. This is why this method has
    // to be synchronous.
    handler(handle);
}

void wifi_event_loop(wifi_handle handle) {
    if (handle == nullptr) {
        return;
    }

    asHalState(handle)->eventLoop();
}

wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle,
                                          feature_set* set) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getSupportedFeatureSet(set);
}

wifi_error wifi_get_ifaces(wifi_handle handle,
                           int* num,
                           wifi_interface_handle** interfaces) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInfo(handle)->getInterfaces(num, interfaces);
}

wifi_error wifi_get_iface_name(wifi_interface_handle handle,
                               char* name,
                               size_t size) {
    if (handle == nullptr || (name == nullptr && size > 0)) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getName(name, size);
}

wifi_error wifi_get_link_stats(wifi_request_id id,
                               wifi_interface_handle handle,
                               wifi_stats_result_handler handler) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getLinkStats(id, handler);
}

wifi_error wifi_set_link_stats(wifi_interface_handle handle,
                               wifi_link_layer_params params) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->setLinkStats(params);
}

wifi_error wifi_set_alert_handler(wifi_request_id id,
                                  wifi_interface_handle handle,
                                  wifi_alert_handler handler) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->setAlertHandler(id, handler);
}

wifi_error wifi_reset_alert_handler(wifi_request_id id,
                                    wifi_interface_handle handle) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->resetAlertHandler(id);
}

wifi_error wifi_get_firmware_version(wifi_interface_handle handle,
                                     char* buffer,
                                     int buffer_size) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getFirmwareVersion(buffer, buffer_size);
}

wifi_error wifi_get_driver_version(wifi_interface_handle handle,
                                   char* buffer,
                                   int buffer_size) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getDriverVersion(buffer, buffer_size);
}

wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle,
                                     oui scan_oui) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->setScanningMacOui(scan_oui);
}

wifi_error wifi_clear_link_stats(wifi_interface_handle handle,
                                 u32 stats_clear_req_mask,
                                 u32 *stats_clear_rsp_mask,
                                 u8 stop_req,
                                 u8 *stop_rsp) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->clearLinkStats(stats_clear_req_mask,
                                               stats_clear_rsp_mask,
                                               stop_req,
                                               stop_rsp);
}

wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
                                   int band,
                                   int max_channels,
                                   wifi_channel *channels,
                                   int *num_channels)
{
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getValidChannels(band,
                                                 max_channels,
                                                 channels,
                                                 num_channels);
}

wifi_error wifi_start_logging(wifi_interface_handle handle,
                              u32 verbose_level,
                              u32 flags,
                              u32 max_interval_sec,
                              u32 min_data_size,
                              char *ring_name) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->startLogging(verbose_level,
                                             flags,
                                             max_interval_sec,
                                             min_data_size,
                                             ring_name);
}

wifi_error wifi_set_country_code(wifi_interface_handle handle,
                                 const char *country_code) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->setCountryCode(country_code);
}

wifi_error wifi_set_log_handler(wifi_request_id id,
                                wifi_interface_handle handle,
                                wifi_ring_buffer_data_handler handler) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->setLogHandler(id, handler);
}

wifi_error wifi_get_ring_buffers_status(wifi_interface_handle handle,
                                        u32 *num_rings,
                                        wifi_ring_buffer_status *status) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getRingBuffersStatus(num_rings, status);
}

wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle handle,
                                                 unsigned int *support) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getLoggerSupportedFeatureSet(support);
}

wifi_error wifi_get_ring_data(wifi_interface_handle handle, char *ring_name) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getRingData(ring_name);
}

wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->configureNdOffload(enable);
}

wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->startPacketFateMonitoring();
}

wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle,
                                 wifi_tx_report *tx_report_bufs,
                                 size_t n_requested_fates,
                                 size_t *n_provided_fates) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getTxPacketFates(tx_report_bufs,
                                                 n_requested_fates,
                                                 n_provided_fates);
}

wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle,
                                 wifi_rx_report *rx_report_bufs,
                                 size_t n_requested_fates,
                                 size_t *n_provided_fates) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getRxPacketFates(rx_report_bufs,
                                                 n_requested_fates,
                                                 n_provided_fates);
}

wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
                                               u32 *version,
                                               u32 *max_len) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getPacketFilterCapabilities(version, max_len);
}

wifi_error
wifi_get_wake_reason_stats(wifi_interface_handle handle,
                           WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt) {
    if (handle == nullptr) {
        return WIFI_ERROR_INVALID_ARGS;
    }

    return asInterface(handle)->getWakeReasonStats(wifi_wake_reason_cnt);
}

wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn* fn)
{
    if (fn == NULL) {
        return WIFI_ERROR_UNKNOWN;
    }
    fn->wifi_initialize = wifi_initialize;
    fn->wifi_cleanup = wifi_cleanup;
    fn->wifi_event_loop = wifi_event_loop;
    fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;

    fn->wifi_get_ifaces = wifi_get_ifaces;
    fn->wifi_get_iface_name = wifi_get_iface_name;
    fn->wifi_get_link_stats = wifi_get_link_stats;
    fn->wifi_set_link_stats = wifi_set_link_stats;
    fn->wifi_clear_link_stats = wifi_clear_link_stats;

    fn->wifi_set_alert_handler = wifi_set_alert_handler;
    fn->wifi_reset_alert_handler = wifi_reset_alert_handler;
    fn->wifi_get_firmware_version = wifi_get_firmware_version;
    fn->wifi_get_driver_version = wifi_get_driver_version;

    fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui;
    fn->wifi_get_valid_channels = wifi_get_valid_channels;
    fn->wifi_start_logging = wifi_start_logging;
    fn->wifi_set_country_code = wifi_set_country_code;
    fn->wifi_set_log_handler = wifi_set_log_handler;
    fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
    fn->wifi_get_logger_supported_feature_set
        = wifi_get_logger_supported_feature_set;
    fn->wifi_get_ring_data = wifi_get_ring_data;
    fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
    fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
    fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
    fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
    fn->wifi_get_packet_filter_capabilities
        = wifi_get_packet_filter_capabilities;
    fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;

    // These function will either return WIFI_ERROR_NOT_SUPPORTED or do nothing
    notSupported(fn->wifi_set_nodfs_flag);
    notSupported(fn->wifi_get_concurrency_matrix);
    notSupported(fn->wifi_start_gscan);
    notSupported(fn->wifi_stop_gscan);
    notSupported(fn->wifi_get_cached_gscan_results);
    notSupported(fn->wifi_set_bssid_hotlist);
    notSupported(fn->wifi_reset_bssid_hotlist);
    notSupported(fn->wifi_set_significant_change_handler);
    notSupported(fn->wifi_reset_significant_change_handler);
    notSupported(fn->wifi_get_gscan_capabilities);
    notSupported(fn->wifi_rtt_range_request);
    notSupported(fn->wifi_rtt_range_cancel);
    notSupported(fn->wifi_get_rtt_capabilities);
    notSupported(fn->wifi_rtt_get_responder_info);
    notSupported(fn->wifi_enable_responder);
    notSupported(fn->wifi_disable_responder);
    notSupported(fn->wifi_set_epno_list);
    notSupported(fn->wifi_reset_epno_list);
    notSupported(fn->wifi_get_firmware_memory_dump);
    notSupported(fn->wifi_reset_log_handler);
    notSupported(fn->wifi_start_rssi_monitoring);
    notSupported(fn->wifi_stop_rssi_monitoring);
    notSupported(fn->wifi_start_sending_offloaded_packet);
    notSupported(fn->wifi_stop_sending_offloaded_packet);
    notSupported(fn->wifi_set_packet_filter);

    return WIFI_SUCCESS;
}