Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4b098c4 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski Committed by Automerger Merge Worker
Browse files

stack/eatt: Add initial implementation for EATT am: 3bde05cc

Original change: https://android-review.googlesource.com/c/platform/system/bt/+/1348752

Change-Id: Ib18ebd874157952cd3922ff84ecf0ab9b94863f5
parents cf122be3 3bde05cc
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@
    {
      "name" : "net_test_device"
    },
    {
      "name" : "net_test_eatt"
    },
    {
      "name" : "net_test_hci"
    },
@@ -77,6 +80,10 @@
      "name" : "net_test_btpackets",
      "host" : true
    },
    {
      "name" : "net_test_eatt",
      "host" : true
    },
    {
      "name" : "net_test_types",
      "host" : true
+59 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ cc_library_static {
        "avrc",
        "l2cap",
        "avdt",
        "eatt",
        "gatt",
        "gap",
        "pan",
@@ -125,6 +126,7 @@ cc_library_static {
        "btm/btm_scn.cc",
        "btu/btu_hcif.cc",
        "btu/btu_task.cc",
        "eatt/eatt.cc",
        "gap/gap_ble.cc",
        "gap/gap_conn.cc",
        "gatt/att_protocol.cc",
@@ -453,6 +455,7 @@ cc_test {
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/stack/include",
        "packages/modules/Bluetooth/system/stack/eatt",
        "packages/modules/Bluetooth/system/stack/l2cap",
        "packages/modules/Bluetooth/system/stack/btm",
        "packages/modules/Bluetooth/system/utils/include",
@@ -460,6 +463,8 @@ cc_test {
    srcs: [
        "test/gatt/gatt_sr_test.cc",
        "gatt/gatt_utils.cc",
        "test/common/mock_eatt.cc",
        "test/common/mock_gatt_layer.cc",
    ],
    shared_libs: [
        "libcutils",
@@ -471,6 +476,7 @@ cc_test {
        "libosi",
        "libbt-common",
        "libbt-protos-lite",
        "libgmock",
        "libosi-AllocationTestHarness",
    ],
    sanitize: {
@@ -489,6 +495,7 @@ cc_test {
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/stack/btm",
        "packages/modules/Bluetooth/system/stack/eatt",
        "packages/modules/Bluetooth/system/stack/include",
        "packages/modules/Bluetooth/system/utils/include",
    ],
@@ -497,6 +504,8 @@ cc_test {
        "gatt/gatt_sr_hash.cc",
        "gatt/gatt_utils.cc",
        "test/gatt/mock_gatt_utils_ref.cc",
        "test/common/mock_eatt.cc",
        "test/common/mock_gatt_layer.cc",
        "test/stack_gatt_sr_hash_test.cc",
    ],
    shared_libs: [
@@ -508,6 +517,7 @@ cc_test {
        "libbt-common",
        "libbt-protos-lite",
        "liblog",
        "libgmock",
        "libosi",
    ],
}
@@ -531,6 +541,7 @@ cc_test {
        "btm/btm_iso.cc",
        "test/btm_iso_test.cc",
        "test/common/mock_controller.cc",
        "test/common/mock_gatt_layer.cc",
        "test/common/mock_hcic_layer.cc",
    ],
    static_libs: [
@@ -550,3 +561,51 @@ cc_test {
        },
    },
}

// EATT unit tests
cc_test {
    name: "net_test_eatt",
    test_suites: ["device-tests"],
    host_supported: true,
    defaults: [
        "fluoride_defaults",
        "clang_coverage_bin",
    ],
    local_include_dirs: [
        "include",
        "btm",
        "eatt",
        "gatt",
        "l2cap",
        "test/common",
    ],
    include_dirs:[
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/btcore/include",
    ],
    srcs: [
        "eatt/eatt.cc",
        "test/common/mock_btm_api_layer.cc",
	"test/common/mock_btif_storage.cc",
        "test/common/mock_controller.cc",
        "test/common/mock_gatt_layer.cc",
        "test/common/mock_l2cap_layer.cc",
        "test/gatt/mock_gatt_utils_ref.cc",
        "test/eatt/eatt_test.cc",
    ],
    shared_libs: [
        "libcutils",
        "libcrypto",
        "libprotobuf-cpp-lite",
    ],
    static_libs: [
        "libbt-common",
        "libbt-protos-lite",
        "liblog",
        "libgmock",
        "libosi",
    ],
    sanitize: {
        cfi: false,
    },
}
+3 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ static_library("stack") {
    "btm/btm_sec.cc",
    "btu/btu_hcif.cc",
    "btu/btu_task.cc",
    "eatt/eatt.cc",
    "gap/gap_ble.cc",
    "gap/gap_conn.cc",
    "gatt/att_protocol.cc",
@@ -166,6 +167,7 @@ static_library("stack") {
    "gap",
    "pan",
    "bnep",
    "eatt",
    "hid",
    "sdp",
    "smp",
@@ -208,6 +210,7 @@ executable("stack_unittests") {
  include_dirs = [
    "include",
    "//",
    "//bta/eatt",
    "//bta/include",
    "//bta/sys",
    "//btcore/include",
+207 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
 * www.ehima.com
 *
 * 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 "eatt_impl.h"
#include "stack/l2cap/l2c_int.h"

using bluetooth::eatt::eatt_impl;

namespace bluetooth {
namespace eatt {

struct EattExtension::impl {
  impl() = default;
  ~impl() = default;

  void Start() {
    if (eatt_impl_) {
      LOG(ERROR) << "Eatt already started";
      return;
    };

    /* Register server for Eatt */
    memset(&reg_info_, 0, sizeof(reg_info_));
    reg_info_.pL2CA_CreditBasedConnectInd_Cb = eatt_connect_ind;
    reg_info_.pL2CA_CreditBasedConnectCfm_Cb = eatt_connect_cfm;
    reg_info_.pL2CA_CreditBasedReconfigCompleted_Cb = eatt_reconfig_completed;
    reg_info_.pL2CA_DisconnectInd_Cb = eatt_disconnect_ind;
    reg_info_.pL2CA_Error_Cb = eatt_error_cb;
    reg_info_.pL2CA_DataInd_Cb = eatt_data_ind;

    if (L2CA_RegisterLECoc(BT_PSM_EATT, reg_info_, BTM_SEC_NONE) == 0) {
      LOG(ERROR) << __func__ << " cannot register EATT";
    } else {
      eatt_impl_ = std::make_unique<eatt_impl>();
    }
  }

  void Stop() {
    if (!eatt_impl_) {
      LOG(ERROR) << "Eatt not started";
      return;
    }
    eatt_impl_.reset(nullptr);
    L2CA_DeregisterLECoc(BT_PSM_EATT);
  }

  bool IsRunning() { return eatt_impl_ ? true : false; }

  static eatt_impl* GetImplInstance(void) {
    auto* instance = EattExtension::GetInstance();
    return instance->pimpl_->eatt_impl_.get();
  }

  static void eatt_connect_ind(const RawAddress& bda,
                               std::vector<uint16_t>& lcids, uint16_t psm,
                               uint16_t peer_mtu, uint8_t identifier) {
    auto p_eatt_impl = GetImplInstance();
    if (p_eatt_impl)
      p_eatt_impl->eatt_l2cap_connect_ind(bda, lcids, psm, peer_mtu,
                                          identifier);
  }

  static void eatt_connect_cfm(const RawAddress& bda, uint16_t lcid,
                               uint16_t peer_mtu, uint16_t result) {
    auto p_eatt_impl = GetImplInstance();
    if (p_eatt_impl)
      p_eatt_impl->eatt_l2cap_connect_cfm(bda, lcid, peer_mtu, result);
  }

  static void eatt_reconfig_completed(const RawAddress& bda, uint16_t lcid,
                                      bool is_local_cfg,
                                      tL2CAP_LE_CFG_INFO* p_cfg) {
    auto p_eatt_impl = GetImplInstance();
    if (p_eatt_impl)
      p_eatt_impl->eatt_l2cap_reconfig_completed(bda, lcid, is_local_cfg,
                                                 p_cfg);
  }

  static void eatt_error_cb(uint16_t lcid, uint16_t reason) {
    auto p_eatt_impl = GetImplInstance();
    if (p_eatt_impl) p_eatt_impl->eatt_l2cap_error_cb(lcid, reason);
  }

  static void eatt_disconnect_ind(uint16_t lcid, bool please_confirm) {
    auto p_eatt_impl = GetImplInstance();
    if (p_eatt_impl)
      p_eatt_impl->eatt_l2cap_disconnect_ind(lcid, please_confirm);
  }

  static void eatt_data_ind(uint16_t lcid, BT_HDR* data_p) {
    auto p_eatt_impl = GetImplInstance();
    if (p_eatt_impl) p_eatt_impl->eatt_l2cap_data_ind(lcid, data_p);
  }

  std::unique_ptr<eatt_impl> eatt_impl_;
  tL2CAP_APPL_INFO reg_info_;
};

void EattExtension::AddFromStorage(const RawAddress& bd_addr) {
  eatt_impl* p_eatt_impl = EattExtension::impl::GetImplInstance();
  if (p_eatt_impl) p_eatt_impl->add_from_storage(bd_addr);
}

EattExtension::EattExtension() : pimpl_(std::make_unique<impl>()) {}

bool EattExtension::IsEattSupportedByPeer(const RawAddress& bd_addr) {
  return pimpl_->eatt_impl_->is_eatt_supported_by_peer(bd_addr);
}

void EattExtension::Connect(const RawAddress& bd_addr) {
  pimpl_->eatt_impl_->connect(bd_addr);
}

void EattExtension::Disconnect(const RawAddress& bd_addr) {
  pimpl_->eatt_impl_->disconnect(bd_addr);
}

void EattExtension::Reconfigure(const RawAddress& bd_addr, uint16_t cid,
                                uint16_t mtu) {
  pimpl_->eatt_impl_->reconfigure(bd_addr, cid, mtu);
}
void EattExtension::ReconfigureAll(const RawAddress& bd_addr, uint16_t mtu) {
  pimpl_->eatt_impl_->reconfigure_all(bd_addr, mtu);
}

EattChannel* EattExtension::FindEattChannelByCid(const RawAddress& bd_addr,
                                                 uint16_t cid) {
  return pimpl_->eatt_impl_->find_eatt_channel_by_cid(bd_addr, cid);
}

EattChannel* EattExtension::FindEattChannelByTransId(const RawAddress& bd_addr,
                                                     uint32_t trans_id) {
  return pimpl_->eatt_impl_->find_eatt_channel_by_transid(bd_addr, trans_id);
}

bool EattExtension::IsIndicationPending(const RawAddress& bd_addr,
                                        uint16_t indication_handle) {
  return pimpl_->eatt_impl_->is_indication_pending(bd_addr, indication_handle);
}

EattChannel* EattExtension::GetChannelAvailableForIndication(
    const RawAddress& bd_addr) {
  return pimpl_->eatt_impl_->get_channel_available_for_indication(bd_addr);
}

void EattExtension::FreeGattResources(const RawAddress& bd_addr) {
  pimpl_->eatt_impl_->free_gatt_resources(bd_addr);
}

bool EattExtension::IsOutstandingMsgInSendQueue(const RawAddress& bd_addr) {
  return pimpl_->eatt_impl_->is_outstanding_msg_in_send_queue(bd_addr);
}

EattChannel* EattExtension::GetChannelWithQueuedData(
    const RawAddress& bd_addr) {
  return pimpl_->eatt_impl_->get_channel_with_queued_data(bd_addr);
}

EattChannel* EattExtension::GetChannelAvailableForClientRequest(
    const RawAddress& bd_addr) {
  return pimpl_->eatt_impl_->get_channel_available_for_client_request(bd_addr);
}

/* Start stop GATT indication timer per CID */
void EattExtension::StartIndicationConfirmationTimer(const RawAddress& bd_addr,
                                                     uint16_t cid) {
  pimpl_->eatt_impl_->start_indication_confirm_timer(bd_addr, cid);
}

void EattExtension::StopIndicationConfirmationTimer(const RawAddress& bd_addr,
                                                    uint16_t cid) {
  pimpl_->eatt_impl_->stop_indication_confirm_timer(bd_addr, cid);
}

/* Start stop application indication timeout */
void EattExtension::StartAppIndicationTimer(const RawAddress& bd_addr,
                                            uint16_t cid) {
  pimpl_->eatt_impl_->start_app_indication_timer(bd_addr, cid);
}

void EattExtension::StopAppIndicationTimer(const RawAddress& bd_addr,
                                           uint16_t cid) {
  pimpl_->eatt_impl_->stop_app_indication_timer(bd_addr, cid);
}

void EattExtension::Start() { pimpl_->Start(); }

void EattExtension::Stop() { pimpl_->Stop(); }

EattExtension::~EattExtension() = default;

}  // namespace eatt
}  // namespace bluetooth
+284 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
 * www.ehima.com
 *
 * 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.
 */

#pragma once

#include <queue>

#include "stack/gatt/gatt_int.h"

#define EATT_MIN_MTU_MPS (64)
#define EATT_DEFAULT_MTU (256)

namespace bluetooth {
namespace eatt {

/* Enums */
enum class EattChannelState : uint8_t {
  EATT_CHANNEL_PENDING = 0x00,
  EATT_CHANNEL_OPENED,
  EATT_CHANNEL_RECONFIGURING,
};

class EattChannel {
 public:
  /* Pointer to EattDevice */
  RawAddress bda_;
  uint16_t cid_;
  uint16_t tx_mtu_;
  uint16_t rx_mtu_;
  EattChannelState state_;

  /* Used to keep server commands */
  tGATT_SR_CMD server_outstanding_cmd_;
  /* Used to veryfy indication confirmation*/
  uint16_t indicate_handle_;
  /* local app confirm to indication timer */
  alarm_t* ind_ack_timer_;
  /* indication confirmation timer */
  alarm_t* ind_confirmation_timer_;
  /* GATT client command queue */
  std::queue<tGATT_CMD_Q> cl_cmd_q_;

  EattChannel(RawAddress& bda, uint16_t cid, uint16_t tx_mtu, uint16_t rx_mtu)
      : bda_(bda),
        cid_(cid),
        tx_mtu_(tx_mtu),
        rx_mtu_(rx_mtu),
        state_(EattChannelState::EATT_CHANNEL_PENDING),
        indicate_handle_(0),
        ind_ack_timer_(NULL),
        ind_confirmation_timer_(NULL) {}

  ~EattChannel() {
    if (ind_ack_timer_ != NULL) {
      alarm_free(ind_ack_timer_);
    }

    if (ind_confirmation_timer_ != NULL) {
      alarm_free(ind_confirmation_timer_);
    }
  }

  void EattChannelSetState(EattChannelState state) {
    if (state_ == EattChannelState::EATT_CHANNEL_PENDING) {
      if (state == EattChannelState::EATT_CHANNEL_OPENED) {
        cl_cmd_q_ = std::queue<tGATT_CMD_Q>();
        memset(&server_outstanding_cmd_, 0, sizeof(tGATT_SR_CMD));
        char name[64];
        sprintf(name, "eatt_ind_ack_timer_%s_cid_0x%04x",
                bda_.ToString().c_str(), cid_);
        ind_ack_timer_ = alarm_new(name);

        sprintf(name, "eatt_ind_conf_timer_%s_cid_0x%04x",
                bda_.ToString().c_str(), cid_);
        ind_confirmation_timer_ = alarm_new(name);
      }
    }
    state_ = state;
  }
  void EattChannelSetTxMTU(uint16_t tx_mtu) { this->tx_mtu_ = tx_mtu; }
};

/* Interface class */
class EattExtension {
 public:
  EattExtension();
  virtual ~EattExtension();

  static EattExtension* GetInstance() {
    static EattExtension* instance = new EattExtension();
    return instance;
  }

  static void AddFromStorage(const RawAddress& bd_addr);

  /**
   * Checks if EATT is supported on peer device.
   *
   * @param bd_addr peer device address
   */
  virtual bool IsEattSupportedByPeer(const RawAddress& bd_addr);

  /**
   * Connect at maximum 5 EATT channels to peer device.
   *
   * @param bd_addr peer device address
   */
  virtual void Connect(const RawAddress& bd_addr);

  /**
   * Disconnect all EATT channels to peer device.
   *
   * @param bd_addr peer device address
   */
  virtual void Disconnect(const RawAddress& bd_addr);

  /**
   * Reconfigure EATT channel for give CID
   *
   * @param bd_addr peer device address
   * @param cid channel id
   * @param mtu new maximum transmit unit available of local device
   */
  virtual void Reconfigure(const RawAddress& bd_addr, uint16_t cid,
                           uint16_t mtu);

  /**
   * Reconfigure all EATT channels to peer device.
   *
   * @param bd_addr peer device address
   * @param mtu new maximum transmit unit available of local device
   */
  virtual void ReconfigureAll(const RawAddress& bd_addr, uint16_t mtu);

  /* Below methods required by GATT implementation */

  /**
   * Find EATT channel by cid.
   *
   * @param bd_addr peer device address
   * @param cid channel id
   *
   * @return Eatt Channel instance.
   */
  virtual EattChannel* FindEattChannelByCid(const RawAddress& bd_addr,
                                            uint16_t cid);

  /**
   * Find EATT channel by transaction id.
   *
   * @param bd_addr peer device address
   * @param trans_id transaction id
   *
   * @return pointer to EATT channel.
   */
  virtual EattChannel* FindEattChannelByTransId(const RawAddress& bd_addr,
                                                uint32_t trans_id);

  /**
   * Check if EATT channel on given handle is waiting for a indication
   * confirmation
   *
   * @param bd_addr peer device address
   * @param indication_handle handle of the pending indication
   *
   * @return true if confirmation is pending false otherwise
   */
  virtual bool IsIndicationPending(const RawAddress& bd_addr,
                                   uint16_t indication_handle);

  /**
   * Get EATT channel available for indication.
   *
   * @param bd_addr peer device address
   *
   * @return pointer to EATT channel.
   */
  virtual EattChannel* GetChannelAvailableForIndication(
      const RawAddress& bd_addr);

  /**
   * Free Resources.
   *
   * (Maybe not needed)
   * @param bd_addr peer device address
   *
   */
  virtual void FreeGattResources(const RawAddress& bd_addr);

  /**
   * Check if there is any EATT channels having some msg in its send queue
   *
   * @param bd_addr peer device address
   *
   * @return true when there is at least one EATT channel ready to send
   */
  virtual bool IsOutstandingMsgInSendQueue(const RawAddress& bd_addr);

  /**
   * Get EATT channel ready to send.
   *
   * @param bd_addr peer device address
   *
   * @return pointer to EATT channel.
   */
  virtual EattChannel* GetChannelWithQueuedData(const RawAddress& bd_addr);

  /**
   * Get EATT channel available to send GATT request.
   *
   * @param bd_addr peer device address
   *
   * @return pointer to EATT channel.
   */
  virtual EattChannel* GetChannelAvailableForClientRequest(
      const RawAddress& bd_addr);

  /**
   * Start GATT indication timer per CID.
   *
   * @param bd_addr peer device address
   * @param cid channel id
   */
  virtual void StartIndicationConfirmationTimer(const RawAddress& bd_addr,
                                                uint16_t cid);

  /**
   * Stop GATT indication timer per CID.
   *
   * @param bd_addr peer device address
   * @param cid channel id
   */
  virtual void StopIndicationConfirmationTimer(const RawAddress& bd_addr,
                                               uint16_t cid);

  /**
   *  Start application time for incoming indication on given CID
   *
   * @param bd_addr peer device address
   * @param cid channel id
   */
  virtual void StartAppIndicationTimer(const RawAddress& bd_addr, uint16_t cid);

  /**
   *  Stop application time for incoming indication on given CID
   *
   * @param bd_addr peer device address
   * @param cid channel id
   */
  virtual void StopAppIndicationTimer(const RawAddress& bd_addr, uint16_t cid);

  /**
   * Starts the EattExtension module
   */
  void Start();

  /**
   * Stops the EattExtension module
   */
  void Stop();

 private:
  struct impl;
  std::unique_ptr<impl> pimpl_;

  DISALLOW_COPY_AND_ASSIGN(EattExtension);
};

}  // namespace eatt
}  // namespace bluetooth
 No newline at end of file
Loading