[WifiCoex] Add WifiChip HIDL APIs for coex

Add HIDL APIs to convey a list of unsafe Wifi channels to the driver for
coex channel avoidance.

Bug: 153651001
Test: build
Change-Id: I8b14f0e2d8855c1f1e363d612617256d8e928f30
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
index 2702759..e9caa3d 100644
--- a/wifi/1.5/IWifiChip.hal
+++ b/wifi/1.5/IWifiChip.hal
@@ -17,6 +17,7 @@
 package android.hardware.wifi@1.5;
 
 import @1.0::WifiStatus;
+import @1.0::IfaceType;
 import @1.5::IWifiApIface;
 import @1.0::IWifiIface;
 import @1.3::IWifiChip;
@@ -129,7 +130,6 @@
      */
     setMultiStaUseCase(MultiStaUseCase useCase) generates (WifiStatus status);
 
-
     /**
      * Create bridged IWifiApIface.
      *
@@ -167,4 +167,47 @@
      */
     removeIfaceInstanceFromBridgedApIface(string brIfaceName, string ifaceInstanceName)
         generates (WifiStatus status);
+
+    /**
+     * Representation of a Wi-Fi channel for Wi-Fi coex channel avoidance.
+     */
+    struct CoexUnsafeChannel {
+        /* The band of the channel */
+        WifiBand band;
+        /* The channel number */
+        uint32_t channel;
+        /** The power cap will be a maximum power value in dbm that is allowed to be transmitted by
+            the chip on this channel. A value of PowerCapConstant.NO_POWER_CAP means no limitation
+            on transmitted power is needed by the chip for this channel.
+        */
+        int32_t powerCapDbm;
+    };
+
+    enum PowerCapConstant : int32_t {
+        NO_POWER_CAP = 0x7FFFFFFF,
+    };
+
+    /**
+     * Invoked to indicate that the provided |CoexUnsafeChannels| should be avoided with the
+     * specified restrictions.
+     *
+     * Channel avoidance is a suggestion and should be done on a best-effort approach. If a provided
+     * channel is used, then the specified power cap should be applied.
+     *
+     * In addition, hard restrictions on the Wifi modes may be indicated by |IfaceType| bits
+     * (STA, AP, P2P, NAN, etc) in the |restrictions| bitfield. If a hard restriction is provided,
+     * then the channels should be completely avoided for the provided Wifi modes instead of by
+     * best-effort.
+     *
+     * @param unsafeChannels List of |CoexUnsafeChannels| to avoid.
+     * @param restrictions Bitset of |IfaceType| values indicating Wifi modes to completely avoid.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     */
+    setCoexUnsafeChannels(
+        vec<CoexUnsafeChannel> unsafeChannels, bitfield<IfaceType> restrictions)
+            generates (WifiStatus status);
 };
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index 83d06fe..8e2e647 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -2800,6 +2800,47 @@
     }
     CHECK(false);
 }
+
+bool convertHidlCoexUnsafeChannelToLegacy(
+    const IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+    legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
+    if (!legacy_unsafe_channel) {
+        return false;
+    }
+    *legacy_unsafe_channel = {};
+    switch (hidl_unsafe_channel.band) {
+        case WifiBand::BAND_24GHZ:
+            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
+            break;
+        case WifiBand::BAND_5GHZ:
+            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
+            break;
+        default:
+            return false;
+    };
+    legacy_unsafe_channel->channel = hidl_unsafe_channel.channel;
+    legacy_unsafe_channel->power_cap_dbm = hidl_unsafe_channel.powerCapDbm;
+    return true;
+}
+
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+    const std::vector<IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+    std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels) {
+    if (!legacy_unsafe_channels) {
+        return false;
+    }
+    *legacy_unsafe_channels = {};
+    for (const auto& hidl_unsafe_channel : hidl_unsafe_channels) {
+        legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
+        if (!hidl_struct_util::convertHidlCoexUnsafeChannelToLegacy(
+                hidl_unsafe_channel, &legacy_unsafe_channel)) {
+            return false;
+        }
+        legacy_unsafe_channels->push_back(legacy_unsafe_channel);
+    }
+    return true;
+}
+
 }  // namespace hidl_struct_util
 }  // namespace implementation
 }  // namespace V1_5
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
index 49d8a12..feb47ef 100644
--- a/wifi/1.5/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -71,6 +71,12 @@
     IfaceType hidl_interface_type);
 legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
     IWifiChip::MultiStaUseCase use_case);
+bool convertHidlCoexUnsafeChannelToLegacy(
+    const IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+    legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+    const std::vector<IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+    std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index dd39551..1b0353b 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -722,6 +722,15 @@
                            hidl_status_cb, use_case);
 }
 
+Return<void> WifiChip::setCoexUnsafeChannels(
+    const hidl_vec<CoexUnsafeChannel>& unsafeChannels,
+    hidl_bitfield<IfaceType> restrictions,
+    setCoexUnsafeChannels_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setCoexUnsafeChannelsInternal,
+                           hidl_status_cb, unsafeChannels, restrictions);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
     invalidateAndClearBridgedApAll();
     invalidateAndClearAll(ap_ifaces_);
@@ -1447,6 +1456,18 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
+WifiStatus WifiChip::setCoexUnsafeChannelsInternal(
+    std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions) {
+    std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
+    if (!hidl_struct_util::convertHidlVectorOfCoexUnsafeChannelToLegacy(
+            unsafe_channels, &legacy_unsafe_channels)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    auto legacy_status = legacy_hal_.lock()->setCoexUnsafeChannels(
+        legacy_unsafe_channels, restrictions);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 WifiStatus WifiChip::handleChipConfiguration(
     /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
     ChipModeId mode_id) {
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index bff8d68..95c122d 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -174,6 +174,10 @@
     Return<void> setMultiStaUseCase(
         MultiStaUseCase use_case,
         setMultiStaUseCase_cb hidl_status_cb) override;
+    Return<void> setCoexUnsafeChannels(
+        const hidl_vec<CoexUnsafeChannel>& unsafe_channels,
+        hidl_bitfield<IfaceType> restrictions,
+        setCoexUnsafeChannels_cb hidl_status_cb) override;
 
    private:
     void invalidateAndRemoveAllIfaces();
@@ -252,6 +256,8 @@
         const sp<V1_4::IWifiChipEventCallback>& event_callback);
     WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
     WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
+    WifiStatus setCoexUnsafeChannelsInternal(
+        std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions);
 
     WifiStatus handleChipConfiguration(
         std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 76e718b..773dd9b 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -1521,6 +1521,14 @@
                                                           use_case);
 }
 
+wifi_error WifiLegacyHal::setCoexUnsafeChannels(
+    std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+    uint32_t restrictions) {
+    return global_func_table_.wifi_set_coex_unsafe_channels(
+        global_handle_, unsafe_channels.size(), unsafe_channels.data(),
+        restrictions);
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index 555c540..6266cf6 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -386,6 +386,11 @@
     virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
     virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
 
+    // Coex functions.
+    virtual wifi_error setCoexUnsafeChannels(
+        std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+        uint32_t restrictions);
+
    private:
     // Retrieve interface handles for all the available interfaces.
     wifi_error retrieveIfaceHandles();
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index 71d2ddf..b6c908b 100644
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -149,6 +149,7 @@
     populateStubFor(&hal_fn->wifi_get_chip_feature_set);
     populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
     populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
+    populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
 
     return true;
 }