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