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

Commit ac3f3353 authored by Hansong Zhang's avatar Hansong Zhang
Browse files

L2cap shim: Introduce Classic Dynamic Channel Helper

Same as LE.

Tag: #gd-refactor
Bug: 141555841
Test: cert/run --host
Change-Id: Ie9c85f5bdadf5235095d357ae77d1668d7fcc694
parent 432050b4
Loading
Loading
Loading
Loading
+225 −26
Original line number Diff line number Diff line
@@ -38,6 +38,205 @@ using namespace bluetooth::l2cap;

static bluetooth::shim::legacy::L2cap shim_l2cap;

// Classic Dynamic Channel Shim Helper

uint16_t classic_cid_token_counter_ = 1;

struct ClassicDynamicChannelInfo {
  uint16_t psm;
  RawAddress remote;
};
std::unordered_map<uint16_t, ClassicDynamicChannelInfo>
    classic_cid_token_to_channel_map_;

uint16_t add_classic_cid_token_entry(uint16_t psm, RawAddress remote) {
  uint16_t new_token = classic_cid_token_counter_;
  classic_cid_token_to_channel_map_[new_token] = {psm, remote};
  classic_cid_token_counter_++;
  if (classic_cid_token_counter_ == 0) classic_cid_token_counter_++;
  return new_token;
}

void remove_classic_cid_token_entry(uint16_t cid_token) {
  classic_cid_token_to_channel_map_.erase(cid_token);
}

uint16_t find_classic_cid_token_by_psm_address(uint16_t psm,
                                               RawAddress remote) {
  for (const auto& entry : classic_cid_token_to_channel_map_) {
    if (entry.second.psm == psm && entry.second.remote == remote) {
      return entry.first;
    }
  }
  LOG(ERROR) << __func__ << "Can't find channel";
  return 0;
}

struct ClassicDynamicChannelHelper {
  ClassicDynamicChannelHelper(uint16_t psm, tL2CAP_APPL_INFO appl_info)
      : psm_(psm), appl_info_(appl_info) {}

  uint16_t psm_;
  tL2CAP_APPL_INFO appl_info_;

  void Register() {
    bluetooth::shim::GetL2capClassicModule()
        ->GetDynamicChannelManager()
        ->RegisterService(
            psm_, {}, {},
            bluetooth::shim::GetGdShimHandler()->BindOnceOn(
                this, &ClassicDynamicChannelHelper::on_registration_complete),
            bluetooth::shim::GetGdShimHandler()->BindOn(
                this, &ClassicDynamicChannelHelper::on_channel_open));
  }

  void on_registration_complete(
      classic::DynamicChannelManager::RegistrationResult result,
      std::unique_ptr<classic::DynamicChannelService> service) {
    if (result != classic::DynamicChannelManager::RegistrationResult::SUCCESS) {
      LOG(ERROR) << "Channel is not registered. psm=" << +psm_ << (int)result;
      return;
    }
    channel_service_ = std::move(service);
  }

  std::unique_ptr<classic::DynamicChannelService> channel_service_ = nullptr;

  void Connect(bluetooth::hci::AddressWithType device) {
    if (channel_service_ == nullptr) {
      return;
    }
    initiated_by_us_[device] = true;
    bluetooth::shim::GetL2capClassicModule()
        ->GetDynamicChannelManager()
        ->ConnectChannel(
            device.GetAddress(), {}, psm_,
            bluetooth::shim::GetGdShimHandler()->BindOn(
                this, &ClassicDynamicChannelHelper::on_channel_open),
            bluetooth::shim::GetGdShimHandler()->BindOnceOn(
                this,
                &ClassicDynamicChannelHelper::on_outgoing_connection_fail));
  }

  void Disconnect(bluetooth::hci::AddressWithType device) {
    if (channel_service_ == nullptr) {
      return;
    }
    if (channels_.count(device) == 0) {
      return;
    }
    channels_[device]->Close();
    disconnected_by_us_[device] = true;
  }

  void Unregister() {
    if (channel_service_ != nullptr) {
      channel_service_->Unregister(
          bluetooth::shim::GetGdShimHandler()->BindOnceOn(
              this, &ClassicDynamicChannelHelper::on_unregistered));
      channel_service_ = nullptr;
    }
  }

  void on_unregistered() {
    for (const auto& device : channels_) {
      device.second->Close();
    }
  }

  void on_channel_close(bluetooth::hci::AddressWithType device,
                        bluetooth::hci::ErrorCode error_code) {
    channel_enqueue_buffer_[device] = nullptr;
    channels_[device]->GetQueueUpEnd()->UnregisterDequeue();
    channels_.erase(device);
    auto address = bluetooth::ToRawAddress(device.GetAddress());
    auto cid_token = find_classic_cid_token_by_psm_address(psm_, address);
    (appl_info_.pL2CA_DisconnectInd_Cb)(cid_token, false);
    remove_classic_cid_token_entry(cid_token);
    initiated_by_us_.erase(device);

    if (channel_service_ == nullptr && channels_.empty()) {
      // Try again
      bluetooth::shim::L2CA_Deregister(psm_);
    }
  }

  void on_channel_open(std::unique_ptr<classic::DynamicChannel> channel) {
    auto device = channel->GetDevice();
    channel->RegisterOnCloseCallback(
        bluetooth::shim::GetGdShimHandler()->BindOnceOn(
            this, &ClassicDynamicChannelHelper::on_channel_close, device));
    channel_enqueue_buffer_[device] = std::make_unique<
        bluetooth::os::EnqueueBuffer<bluetooth::packet::BasePacketBuilder>>(
        channel->GetQueueUpEnd());
    channel->GetQueueUpEnd()->RegisterDequeue(
        bluetooth::shim::GetGdShimHandler(),
        bluetooth::common::Bind(&ClassicDynamicChannelHelper::on_incoming_data,
                                bluetooth::common::Unretained(this), device));
    channels_[device] = std::move(channel);

    auto address = bluetooth::ToRawAddress(device.GetAddress());
    if (initiated_by_us_[device]) {
      auto cid_token = find_classic_cid_token_by_psm_address(psm_, address);
      appl_info_.pL2CA_ConnectCfm_Cb(cid_token, 0);
    } else {
      if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) {
        Disconnect(device);
        return;
      }
      auto cid_token = add_classic_cid_token_entry(psm_, address);
      appl_info_.pL2CA_ConnectInd_Cb(address, cid_token, psm_, 0);
    }
  }

  void on_incoming_data(bluetooth::hci::AddressWithType remote) {
    auto channel = channels_.find(remote);
    if (channel == channels_.end()) {
      LOG_ERROR("Channel is not open");
      return;
    }
    auto packet = channel->second->GetQueueUpEnd()->TryDequeue();
    std::vector<uint8_t> packet_vector(packet->begin(), packet->end());
    BT_HDR* buffer =
        static_cast<BT_HDR*>(osi_calloc(packet_vector.size() + sizeof(BT_HDR)));
    std::copy(packet_vector.begin(), packet_vector.end(), buffer->data);
    buffer->len = packet_vector.size();
    auto address = bluetooth::ToRawAddress(remote.GetAddress());
    auto cid_token = find_classic_cid_token_by_psm_address(psm_, address);
    appl_info_.pL2CA_DataInd_Cb(cid_token, buffer);
  }

  void on_outgoing_connection_fail(
      classic::DynamicChannelManager::ConnectionResult result) {
    LOG(ERROR) << "Outgoing connection failed";
  }

  bool send(AddressWithType remote,
            std::unique_ptr<bluetooth::packet::BasePacketBuilder> packet) {
    auto buffer = channel_enqueue_buffer_.find(remote);
    if (buffer == channel_enqueue_buffer_.end() || buffer->second == nullptr) {
      LOG(ERROR) << "Channel is not open";
      return false;
    }
    buffer->second->Enqueue(std::move(packet),
                            bluetooth::shim::GetGdShimHandler());
    return true;
  }

  std::unordered_map<AddressWithType, std::unique_ptr<classic::DynamicChannel>>
      channels_;
  std::unordered_map<AddressWithType,
                     std::unique_ptr<bluetooth::os::EnqueueBuffer<
                         bluetooth::packet::BasePacketBuilder>>>
      channel_enqueue_buffer_;
  std::unordered_map<AddressWithType, uint16_t> cid_map_;
  std::unordered_map<AddressWithType, bool> initiated_by_us_;
  std::unordered_map<AddressWithType, bool> disconnected_by_us_;
};

std::unordered_map<uint16_t, std::unique_ptr<ClassicDynamicChannelHelper>>
    classic_dynamic_channel_helper_map_;

// Helper: L2cap security enforcement shim

std::unordered_map<intptr_t,
@@ -649,28 +848,28 @@ void bluetooth::shim::L2CA_SetBondingState(const RawAddress& bd_addr,

// LE COC Shim Helper

uint16_t cid_token_counter_ = 1;
uint16_t le_cid_token_counter_ = 1;

struct LeCocChannelInfo {
  uint16_t psm;
  RawAddress remote;
};
std::unordered_map<uint16_t, LeCocChannelInfo> cid_token_to_channel_map_;
std::unordered_map<uint16_t, LeCocChannelInfo> le_cid_token_to_channel_map_;

uint16_t add_cid_token_entry(uint16_t psm, RawAddress remote) {
  uint16_t new_token = cid_token_counter_;
  cid_token_to_channel_map_[new_token] = {psm, remote};
  cid_token_counter_++;
  if (cid_token_counter_ == 0) cid_token_counter_++;
uint16_t add_le_cid_token_entry(uint16_t psm, RawAddress remote) {
  uint16_t new_token = le_cid_token_counter_;
  le_cid_token_to_channel_map_[new_token] = {psm, remote};
  le_cid_token_counter_++;
  if (le_cid_token_counter_ == 0) le_cid_token_counter_++;
  return new_token;
}

void remove_cid_token_entry(uint16_t cid_token) {
  cid_token_to_channel_map_.erase(cid_token);
void remove_le_cid_token_entry(uint16_t cid_token) {
  le_cid_token_to_channel_map_.erase(cid_token);
}

uint16_t find_cid_token_by_psm_address(uint16_t psm, RawAddress remote) {
  for (const auto& entry : cid_token_to_channel_map_) {
uint16_t find_le_cid_token_by_psm_address(uint16_t psm, RawAddress remote) {
  for (const auto& entry : le_cid_token_to_channel_map_) {
    if (entry.second.psm == psm && entry.second.remote == remote) {
      return entry.first;
    }
@@ -761,9 +960,9 @@ struct LeDynamicChannelHelper {
    channels_[device]->GetQueueUpEnd()->UnregisterDequeue();
    channels_.erase(device);
    auto address = bluetooth::ToRawAddress(device.GetAddress());
    auto cid_token = find_cid_token_by_psm_address(psm_, address);
    auto cid_token = find_le_cid_token_by_psm_address(psm_, address);
    (appl_info_.pL2CA_DisconnectInd_Cb)(cid_token, false);
    remove_cid_token_entry(cid_token);
    remove_le_cid_token_entry(cid_token);
    initiated_by_us_.erase(device);

    if (channel_service_ == nullptr && channels_.empty()) {
@@ -788,14 +987,14 @@ struct LeDynamicChannelHelper {

    auto address = bluetooth::ToRawAddress(device.GetAddress());
    if (initiated_by_us_[device]) {
      auto cid_token = find_cid_token_by_psm_address(psm_, address);
      auto cid_token = find_le_cid_token_by_psm_address(psm_, address);
      appl_info_.pL2CA_ConnectCfm_Cb(cid_token, 0);
    } else {
      if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) {
        Disconnect(device);
        return;
      }
      auto cid_token = add_cid_token_entry(psm_, address);
      auto cid_token = add_le_cid_token_entry(psm_, address);
      appl_info_.pL2CA_ConnectInd_Cb(address, cid_token, psm_, 0);
    }
  }
@@ -813,7 +1012,7 @@ struct LeDynamicChannelHelper {
    std::copy(packet_vector.begin(), packet_vector.end(), buffer->data);
    buffer->len = packet_vector.size();
    auto address = bluetooth::ToRawAddress(remote.GetAddress());
    auto cid_token = find_cid_token_by_psm_address(psm_, address);
    auto cid_token = find_le_cid_token_by_psm_address(psm_, address);
    appl_info_.pL2CA_DataInd_Cb(cid_token, buffer);
  }

@@ -891,17 +1090,17 @@ uint16_t bluetooth::shim::L2CA_ConnectLECocReq(uint16_t psm,
  }
  le_dynamic_channel_helper_map_[psm]->Connect(
      ToAddressWithType(p_bd_addr, Btm::GetAddressType(p_bd_addr)));
  return add_cid_token_entry(psm, p_bd_addr);
  return add_le_cid_token_entry(psm, p_bd_addr);
}

bool bluetooth::shim::L2CA_GetPeerLECocConfig(uint16_t cid,
                                              tL2CAP_LE_CFG_INFO* peer_cfg) {
  if (cid_token_to_channel_map_.count(cid) == 0) {
  if (le_cid_token_to_channel_map_.count(cid) == 0) {
    LOG(ERROR) << __func__ << "Invalid cid: " << cid;
    return false;
  }
  auto psm = cid_token_to_channel_map_[cid].psm;
  auto remote = cid_token_to_channel_map_[cid].remote;
  auto psm = le_cid_token_to_channel_map_[cid].psm;
  auto remote = le_cid_token_to_channel_map_[cid].remote;
  if (le_dynamic_channel_helper_map_.count(psm) == 0) {
    LOG(ERROR) << __func__ << "Not registered psm: " << psm;
    return false;
@@ -913,12 +1112,12 @@ bool bluetooth::shim::L2CA_GetPeerLECocConfig(uint16_t cid,
}

bool bluetooth::shim::L2CA_DisconnectLECocReq(uint16_t cid) {
  if (cid_token_to_channel_map_.count(cid) == 0) {
  if (le_cid_token_to_channel_map_.count(cid) == 0) {
    LOG(ERROR) << __func__ << "Invalid cid: " << cid;
    return false;
  }
  auto psm = cid_token_to_channel_map_[cid].psm;
  auto remote = cid_token_to_channel_map_[cid].remote;
  auto psm = le_cid_token_to_channel_map_[cid].psm;
  auto remote = le_cid_token_to_channel_map_[cid].remote;
  if (le_dynamic_channel_helper_map_.count(psm) == 0) {
    LOG(ERROR) << __func__ << "Not registered psm: " << psm;
    return false;
@@ -929,12 +1128,12 @@ bool bluetooth::shim::L2CA_DisconnectLECocReq(uint16_t cid) {
}

uint8_t bluetooth::shim::L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) {
  if (cid_token_to_channel_map_.count(cid) == 0) {
  if (le_cid_token_to_channel_map_.count(cid) == 0) {
    LOG(ERROR) << __func__ << "Invalid cid: " << cid;
    return 0;
  }
  auto psm = cid_token_to_channel_map_[cid].psm;
  auto remote = cid_token_to_channel_map_[cid].remote;
  auto psm = le_cid_token_to_channel_map_[cid].psm;
  auto remote = le_cid_token_to_channel_map_[cid].remote;
  if (le_dynamic_channel_helper_map_.count(psm) == 0) {
    LOG(ERROR) << __func__ << "Not registered psm: " << psm;
    return 0;