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/l2c_api.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)>
39 intercept_packet;
40 ::rust::Fn<void(uint8_t tcb_idx)> on_outgoing_mtu_req;
41 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_resp;
42 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_req;
43 };
44
45 RustArbiterCallbacks callbacks_{};
46 } // namespace
47
OnLeConnect(uint8_t tcb_idx,uint16_t advertiser_id)48 void AclArbiter::OnLeConnect(uint8_t tcb_idx, uint16_t advertiser_id) {
49 #ifdef TARGET_FLOSS
50 return;
51 #endif
52 log::info("Notifying Rust of LE connection");
53 callbacks_.on_le_connect(tcb_idx, advertiser_id);
54 }
55
OnLeDisconnect(uint8_t tcb_idx)56 void AclArbiter::OnLeDisconnect(uint8_t tcb_idx) {
57 #ifdef TARGET_FLOSS
58 return;
59 #endif
60 log::info("Notifying Rust of LE disconnection");
61 callbacks_.on_le_disconnect(tcb_idx);
62 }
63
InterceptAttPacket(uint8_t tcb_idx,const BT_HDR * packet)64 InterceptAction AclArbiter::InterceptAttPacket(uint8_t tcb_idx,
65 const BT_HDR* packet) {
66 #ifdef TARGET_FLOSS
67 return InterceptAction::FORWARD;
68 #endif
69 log::debug("Intercepting ATT packet and forwarding to Rust");
70
71 uint8_t* packet_start = (uint8_t*)(packet + 1) + packet->offset;
72 uint8_t* packet_end = packet_start + packet->len;
73
74 auto vec = ::rust::Vec<uint8_t>();
75 std::copy(packet_start, packet_end, std::back_inserter(vec));
76 return callbacks_.intercept_packet(tcb_idx, std::move(vec));
77 }
78
OnOutgoingMtuReq(uint8_t tcb_idx)79 void AclArbiter::OnOutgoingMtuReq(uint8_t tcb_idx) {
80 #ifdef TARGET_FLOSS
81 return;
82 #endif
83 log::debug("Notifying Rust of outgoing MTU request");
84 callbacks_.on_outgoing_mtu_req(tcb_idx);
85 }
86
OnIncomingMtuResp(uint8_t tcb_idx,size_t mtu)87 void AclArbiter::OnIncomingMtuResp(uint8_t tcb_idx, size_t mtu) {
88 #ifdef TARGET_FLOSS
89 return;
90 #endif
91 log::debug("Notifying Rust of incoming MTU response {}", mtu);
92 callbacks_.on_incoming_mtu_resp(tcb_idx, mtu);
93 }
94
OnIncomingMtuReq(uint8_t tcb_idx,size_t mtu)95 void AclArbiter::OnIncomingMtuReq(uint8_t tcb_idx, size_t mtu) {
96 #ifdef TARGET_FLOSS
97 return;
98 #endif
99 log::debug("Notifying Rust of incoming MTU request {}", mtu);
100 callbacks_.on_incoming_mtu_req(tcb_idx, mtu);
101 }
102
SendPacketToPeer(uint8_t tcb_idx,::rust::Vec<uint8_t> buffer)103 void AclArbiter::SendPacketToPeer(uint8_t tcb_idx,
104 ::rust::Vec<uint8_t> buffer) {
105 #ifdef TARGET_FLOSS
106 return;
107 #endif
108 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
109 if (p_tcb != nullptr) {
110 BT_HDR* p_buf =
111 (BT_HDR*)osi_malloc(sizeof(BT_HDR) + buffer.size() + L2CAP_MIN_OFFSET);
112 if (p_buf == nullptr) {
113 log::fatal("OOM when sending packet");
114 }
115 auto p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
116 std::copy(buffer.begin(), buffer.end(), p);
117 p_buf->offset = L2CAP_MIN_OFFSET;
118 p_buf->len = buffer.size();
119 if (L2CA_SendFixedChnlData(L2CAP_ATT_CID, p_tcb->peer_bda, p_buf) !=
120 L2CAP_DW_SUCCESS) {
121 log::warn("Unable to send L2CAP data peer:{} fixed_cid:{} len:{}",
122 p_tcb->peer_bda, L2CAP_ATT_CID, p_buf->len);
123 }
124 } else {
125 log::error("Dropping packet since connection no longer exists");
126 }
127 }
128
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)129 void StoreCallbacksFromRust(
130 ::rust::Fn<void(uint8_t tcb_idx, uint8_t advertiser)> on_le_connect,
131 ::rust::Fn<void(uint8_t tcb_idx)> on_le_disconnect,
132 ::rust::Fn<InterceptAction(uint8_t tcb_idx, ::rust::Vec<uint8_t> buffer)>
133 intercept_packet,
134 ::rust::Fn<void(uint8_t tcb_idx)> on_outgoing_mtu_req,
135 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_resp,
136 ::rust::Fn<void(uint8_t tcb_idx, size_t mtu)> on_incoming_mtu_req) {
137 log::info("Received callbacks from Rust, registering in Arbiter");
138 callbacks_ = {on_le_connect, on_le_disconnect, intercept_packet,
139 on_outgoing_mtu_req, on_incoming_mtu_resp, on_incoming_mtu_req};
140 }
141
SendPacketToPeer(uint8_t tcb_idx,::rust::Vec<uint8_t> buffer)142 void SendPacketToPeer(uint8_t tcb_idx, ::rust::Vec<uint8_t> buffer) {
143 do_in_main_thread(FROM_HERE, base::BindOnce(&AclArbiter::SendPacketToPeer,
144 base::Unretained(&GetArbiter()),
145 tcb_idx, std::move(buffer)));
146 }
147
GetArbiter()148 AclArbiter& GetArbiter() {
149 static auto singleton = AclArbiter();
150 return singleton;
151 }
152
153 } // namespace arbiter
154 } // namespace shim
155 } // namespace bluetooth
156