| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "fake_channel.h" |
| |
| #include <lib/async/cpp/task.h> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/log.h" |
| |
| namespace bt { |
| namespace l2cap { |
| namespace testing { |
| |
| FakeChannel::FakeChannel(ChannelId id, ChannelId remote_id, |
| hci::ConnectionHandle handle, |
| hci::Connection::LinkType link_type) |
| : Channel(id, remote_id, link_type, handle), |
| handle_(handle), |
| fragmenter_(handle), |
| dispatcher_(nullptr), |
| send_dispatcher_(nullptr), |
| link_err_dispatcher_(nullptr), |
| activate_fails_(false), |
| link_error_(false), |
| weak_ptr_factory_(this) { |
| ZX_DEBUG_ASSERT(handle_); |
| } |
| |
| void FakeChannel::Receive(const ByteBuffer& data) { |
| ZX_DEBUG_ASSERT(!!rx_cb_ == !!dispatcher_); |
| |
| auto pdu = fragmenter_.BuildBasicFrame(id(), data); |
| auto sdu = std::make_unique<DynamicByteBuffer>(pdu.length()); |
| pdu.Copy(sdu.get()); |
| if (dispatcher_) { |
| async::PostTask(dispatcher_, |
| [cb = rx_cb_.share(), sdu = std::move(sdu)]() mutable { |
| cb(std::move(sdu)); |
| }); |
| } else { |
| pending_rx_sdus_.push(std::move(sdu)); |
| } |
| } |
| |
| void FakeChannel::SetSendCallback(SendCallback callback, |
| async_dispatcher_t* dispatcher) { |
| ZX_DEBUG_ASSERT(static_cast<bool>(callback) == static_cast<bool>(dispatcher)); |
| |
| send_cb_ = std::move(callback); |
| send_dispatcher_ = dispatcher; |
| } |
| |
| void FakeChannel::SetLinkErrorCallback(LinkErrorCallback callback, |
| async_dispatcher_t* dispatcher) { |
| ZX_DEBUG_ASSERT(static_cast<bool>(callback) == static_cast<bool>(dispatcher)); |
| |
| link_err_cb_ = std::move(callback); |
| link_err_dispatcher_ = dispatcher; |
| } |
| |
| void FakeChannel::SetSecurityCallback(SecurityUpgradeCallback callback, |
| async_dispatcher_t* dispatcher) { |
| ZX_DEBUG_ASSERT(static_cast<bool>(callback) == static_cast<bool>(dispatcher)); |
| |
| security_cb_ = std::move(callback); |
| security_dispatcher_ = dispatcher; |
| } |
| |
| void FakeChannel::Close() { |
| if (closed_cb_) |
| closed_cb_(); |
| } |
| |
| bool FakeChannel::Activate(RxCallback rx_callback, |
| ClosedCallback closed_callback, |
| async_dispatcher_t* dispatcher) { |
| ZX_DEBUG_ASSERT(rx_callback); |
| ZX_DEBUG_ASSERT(closed_callback); |
| ZX_DEBUG_ASSERT(!rx_cb_); |
| ZX_DEBUG_ASSERT(!closed_cb_); |
| |
| if (activate_fails_) |
| return false; |
| |
| dispatcher_ = dispatcher; |
| closed_cb_ = std::move(closed_callback); |
| rx_cb_ = std::move(rx_callback); |
| |
| while (!pending_rx_sdus_.empty()) { |
| rx_cb_(std::move(pending_rx_sdus_.front())); |
| pending_rx_sdus_.pop(); |
| } |
| |
| return true; |
| } |
| |
| void FakeChannel::Deactivate() { |
| dispatcher_ = nullptr; |
| closed_cb_ = {}; |
| rx_cb_ = {}; |
| } |
| |
| void FakeChannel::SignalLinkError() { |
| link_error_ = true; |
| |
| if (link_err_cb_) { |
| async::PostTask(link_err_dispatcher_, link_err_cb_.share()); |
| } |
| } |
| |
| bool FakeChannel::Send(ByteBufferPtr sdu) { |
| ZX_DEBUG_ASSERT(sdu); |
| |
| if (!send_cb_) |
| return false; |
| |
| if (sdu->size() > tx_mtu()) { |
| bt_log(ERROR, "l2cap", |
| "Dropping oversized SDU (sdu->size()=%zu, tx_mtu()=%u)", sdu->size(), |
| tx_mtu()); |
| return false; |
| } |
| |
| ZX_DEBUG_ASSERT(send_dispatcher_); |
| async::PostTask(send_dispatcher_, |
| [cb = send_cb_.share(), sdu = std::move(sdu)]() mutable { |
| cb(std::move(sdu)); |
| }); |
| |
| return true; |
| } |
| |
| void FakeChannel::UpgradeSecurity(sm::SecurityLevel level, |
| sm::StatusCallback callback) { |
| ZX_DEBUG_ASSERT(security_dispatcher_); |
| async::PostTask( |
| security_dispatcher_, |
| [cb = std::move(callback), f = security_cb_.share(), handle = handle_, |
| level]() mutable { f(handle, level, std::move(cb)); }); |
| } |
| |
| } // namespace testing |
| } // namespace l2cap |
| } // namespace bt |