1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "stack/arbiter/acl_arbiter.h"
18
19 #include <base/functional/bind.h>
20 #include <bluetooth/log.h>
21
22 #include <iterator>
23
24 #include "osi/include/allocator.h"
25 #include "stack/gatt/gatt_int.h"
26 #include "stack/include/l2cap_interface.h"
27 #include "stack/include/l2cdefs.h"
28 #include "stack/include/main_thread.h"
29
30 namespace bluetooth {
31 namespace shim {
32 namespace arbiter {
33
34 namespace {
35 struct RustArbiterCallbacks {
36 ::rust::Fn<void(uint8_t tcb_idx, uint8_t advertiser)> on_le_connect;
37 ::rust::Fn<void(uint8_t tcb_idx)> on_le_disconnect;
38 ::rust::Fn<InterceptAction(uint8_t tcb_idx, ::rust::Vec<uint8_t> buffer)> intercept_packet;
39 ::rust::Fn<void(uint8_t tcb_idx)> on_outgoing_mtu_req;
40 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_resp;
41 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_req;
42 };
43
44 RustArbiterCallbacks callbacks_{};
45 } // namespace
46
OnLeConnect(uint8_t tcb_idx,uint16_t advertiser_id)47 void AclArbiter::OnLeConnect(uint8_t tcb_idx, uint16_t advertiser_id) {
48 #ifdef TARGET_FLOSS
49 return;
50 #endif
51 log::info("Notifying Rust of LE connection");
52 callbacks_.on_le_connect(tcb_idx, advertiser_id);
53 }
54
OnLeDisconnect(uint8_t tcb_idx)55 void AclArbiter::OnLeDisconnect(uint8_t tcb_idx) {
56 #ifdef TARGET_FLOSS
57 return;
58 #endif
59 log::info("Notifying Rust of LE disconnection");
60 callbacks_.on_le_disconnect(tcb_idx);
61 }
62
InterceptAttPacket(uint8_t tcb_idx,const BT_HDR * packet)63 InterceptAction AclArbiter::InterceptAttPacket(uint8_t tcb_idx, const BT_HDR* packet) {
64 #ifdef TARGET_FLOSS
65 return InterceptAction::FORWARD;
66 #endif
67 log::debug("Intercepting ATT packet and forwarding to Rust");
68
69 uint8_t* packet_start = (uint8_t*)(packet + 1) + packet->offset;
70 uint8_t* packet_end = packet_start + packet->len;
71
72 auto vec = ::rust::Vec<uint8_t>();
73 std::copy(packet_start, packet_end, std::back_inserter(vec));
74 return callbacks_.intercept_packet(tcb_idx, std::move(vec));
75 }
76
OnOutgoingMtuReq(uint8_t tcb_idx)77 void AclArbiter::OnOutgoingMtuReq(uint8_t tcb_idx) {
78 #ifdef TARGET_FLOSS
79 return;
80 #endif
81 log::debug("Notifying Rust of outgoing MTU request");
82 callbacks_.on_outgoing_mtu_req(tcb_idx);
83 }
84
OnIncomingMtuResp(uint8_t tcb_idx,size_t mtu)85 void AclArbiter::OnIncomingMtuResp(uint8_t tcb_idx, size_t mtu) {
86 #ifdef TARGET_FLOSS
87 return;
88 #endif
89 log::debug("Notifying Rust of incoming MTU response {}", mtu);
90 callbacks_.on_incoming_mtu_resp(tcb_idx, mtu);
91 }
92
OnIncomingMtuReq(uint8_t tcb_idx,size_t mtu)93 void AclArbiter::OnIncomingMtuReq(uint8_t tcb_idx, size_t mtu) {
94 #ifdef TARGET_FLOSS
95 return;
96 #endif
97 log::debug("Notifying Rust of incoming MTU request {}", mtu);
98 callbacks_.on_incoming_mtu_req(tcb_idx, mtu);
99 }
100
SendPacketToPeer(uint8_t tcb_idx,::rust::Vec<uint8_t> buffer)101 void AclArbiter::SendPacketToPeer(uint8_t tcb_idx, ::rust::Vec<uint8_t> buffer) {
102 #ifdef TARGET_FLOSS
103 return;
104 #endif
105 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
106 if (p_tcb != nullptr) {
107 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + buffer.size() + L2CAP_MIN_OFFSET);
108 if (p_buf == nullptr) {
109 log::fatal("OOM when sending packet");
110 }
111 auto p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
112 std::copy(buffer.begin(), buffer.end(), p);
113 p_buf->offset = L2CAP_MIN_OFFSET;
114 p_buf->len = buffer.size();
115 if (stack::l2cap::get_interface().L2CA_SendFixedChnlData(L2CAP_ATT_CID, p_tcb->peer_bda,
116 p_buf) != tL2CAP_DW_RESULT::SUCCESS) {
117 log::warn("Unable to send L2CAP data peer:{} fixed_cid:{} len:{}", p_tcb->peer_bda,
118 L2CAP_ATT_CID, p_buf->len);
119 }
120 } else {
121 log::error("Dropping packet since connection no longer exists");
122 }
123 }
124
StoreCallbacksFromRust(::rust::Fn<void (uint8_t tcb_idx,uint8_t advertiser)> on_le_connect,::rust::Fn<void (uint8_t tcb_idx)> on_le_disconnect,::rust::Fn<InterceptAction (uint8_t tcb_idx,::rust::Vec<uint8_t> buffer)> intercept_packet,::rust::Fn<void (uint8_t tcb_idx)> on_outgoing_mtu_req,::rust::Fn<void (uint8_t tcb_idx,size_t mtu)> on_incoming_mtu_resp,::rust::Fn<void (uint8_t tcb_idx,size_t mtu)> on_incoming_mtu_req)125 void StoreCallbacksFromRust(
126 ::rust::Fn<void(uint8_t tcb_idx, uint8_t advertiser)> on_le_connect,
127 ::rust::Fn<void(uint8_t tcb_idx)> on_le_disconnect,
128 ::rust::Fn<InterceptAction(uint8_t tcb_idx, ::rust::Vec<uint8_t> buffer)> intercept_packet,
129 ::rust::Fn<void(uint8_t tcb_idx)> on_outgoing_mtu_req,
130 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_resp,
131 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_req) {
132 log::info("Received callbacks from Rust, registering in Arbiter");
133 callbacks_ = {on_le_connect, on_le_disconnect, intercept_packet,
134 on_outgoing_mtu_req, on_incoming_mtu_resp, on_incoming_mtu_req};
135 }
136
SendPacketToPeer(uint8_t tcb_idx,::rust::Vec<uint8_t> buffer)137 void SendPacketToPeer(uint8_t tcb_idx, ::rust::Vec<uint8_t> buffer) {
138 do_in_main_thread(base::BindOnce(&AclArbiter::SendPacketToPeer, base::Unretained(&GetArbiter()),
139 tcb_idx, std::move(buffer)));
140 }
141
GetArbiter()142 AclArbiter& GetArbiter() {
143 static auto singleton = AclArbiter();
144 return singleton;
145 }
146
147 } // namespace arbiter
148 } // namespace shim
149 } // namespace bluetooth
150