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