1 /*
2  * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
3  * www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "stack/eatt/eatt.h"
19 
20 #include <bluetooth/log.h>
21 
22 #include <memory>
23 #include <vector>
24 
25 #include "stack/eatt/eatt_impl.h"
26 #include "stack/include/bt_hdr.h"
27 #include "stack/include/bt_psm_types.h"
28 #include "stack/include/l2cap_interface.h"
29 #include "stack/include/l2cdefs.h"
30 #include "types/raw_address.h"
31 
32 using bluetooth::eatt::eatt_impl;
33 
34 namespace bluetooth {
35 namespace eatt {
36 
37 struct EattExtension::impl {
38   impl() = default;
39   ~impl() = default;
40 
Startbluetooth::eatt::EattExtension::impl41   void Start() {
42     if (eatt_impl_) {
43       log::error("Eatt already started");
44       return;
45     }
46 
47     /* Register server for Eatt */
48     memset(&reg_info_, 0, sizeof(reg_info_));
49     reg_info_.pL2CA_CreditBasedConnectInd_Cb = eatt_connect_ind;
50     reg_info_.pL2CA_CreditBasedConnectCfm_Cb = eatt_connect_cfm;
51     reg_info_.pL2CA_CreditBasedReconfigCompleted_Cb = eatt_reconfig_completed;
52     reg_info_.pL2CA_DisconnectInd_Cb = eatt_disconnect_ind;
53     reg_info_.pL2CA_Error_Cb = eatt_error_cb;
54     reg_info_.pL2CA_DataInd_Cb = eatt_data_ind;
55     reg_info_.pL2CA_CreditBasedCollisionInd_Cb = eatt_collision_ind;
56 
57     if (stack::l2cap::get_interface().L2CA_RegisterLECoc(BT_PSM_EATT, reg_info_, BTM_SEC_NONE,
58                                                          {}) == 0) {
59       log::error("cannot register EATT");
60     } else {
61       eatt_impl_ = std::make_unique<eatt_impl>();
62     }
63   }
64 
Stopbluetooth::eatt::EattExtension::impl65   void Stop() {
66     if (!eatt_impl_) {
67       log::error("Eatt not started");
68       return;
69     }
70     eatt_impl_.reset(nullptr);
71     stack::l2cap::get_interface().L2CA_DeregisterLECoc(BT_PSM_EATT);
72   }
73 
IsRunningbluetooth::eatt::EattExtension::impl74   bool IsRunning() { return eatt_impl_ ? true : false; }
75 
GetImplInstancebluetooth::eatt::EattExtension::impl76   static eatt_impl* GetImplInstance(void) {
77     auto* instance = EattExtension::GetInstance();
78     return instance->pimpl_->eatt_impl_.get();
79   }
80 
eatt_connect_indbluetooth::eatt::EattExtension::impl81   static void eatt_connect_ind(const RawAddress& bda, std::vector<uint16_t>& lcids, uint16_t psm,
82                                uint16_t peer_mtu, uint8_t identifier) {
83     auto p_eatt_impl = GetImplInstance();
84     if (p_eatt_impl) {
85       p_eatt_impl->eatt_l2cap_connect_ind(bda, lcids, psm, peer_mtu, identifier);
86     }
87   }
88 
eatt_connect_cfmbluetooth::eatt::EattExtension::impl89   static void eatt_connect_cfm(const RawAddress& bda, uint16_t lcid, uint16_t peer_mtu,
90                                tL2CAP_LE_RESULT_CODE result) {
91     auto p_eatt_impl = GetImplInstance();
92     if (p_eatt_impl) {
93       p_eatt_impl->eatt_l2cap_connect_cfm(bda, lcid, peer_mtu, result);
94     }
95   }
96 
eatt_reconfig_completedbluetooth::eatt::EattExtension::impl97   static void eatt_reconfig_completed(const RawAddress& bda, uint16_t lcid, bool is_local_cfg,
98                                       tL2CAP_LE_CFG_INFO* p_cfg) {
99     auto p_eatt_impl = GetImplInstance();
100     if (p_eatt_impl) {
101       p_eatt_impl->eatt_l2cap_reconfig_completed(bda, lcid, is_local_cfg, p_cfg);
102     }
103   }
104 
eatt_collision_indbluetooth::eatt::EattExtension::impl105   static void eatt_collision_ind(const RawAddress& bd_addr) {
106     auto p_eatt_impl = GetImplInstance();
107     if (p_eatt_impl) {
108       p_eatt_impl->eatt_l2cap_collision_ind(bd_addr);
109     }
110   }
111 
eatt_error_cbbluetooth::eatt::EattExtension::impl112   static void eatt_error_cb(uint16_t lcid, uint16_t reason) {
113     auto p_eatt_impl = GetImplInstance();
114     if (p_eatt_impl) {
115       p_eatt_impl->eatt_l2cap_error_cb(lcid, reason);
116     }
117   }
118 
eatt_disconnect_indbluetooth::eatt::EattExtension::impl119   static void eatt_disconnect_ind(uint16_t lcid, bool please_confirm) {
120     auto p_eatt_impl = GetImplInstance();
121     if (p_eatt_impl) {
122       p_eatt_impl->eatt_l2cap_disconnect_ind(lcid, please_confirm);
123     }
124   }
125 
eatt_data_indbluetooth::eatt::EattExtension::impl126   static void eatt_data_ind(uint16_t lcid, BT_HDR* data_p) {
127     auto p_eatt_impl = GetImplInstance();
128     if (p_eatt_impl) {
129       p_eatt_impl->eatt_l2cap_data_ind(lcid, data_p);
130     }
131   }
132 
133   std::unique_ptr<eatt_impl> eatt_impl_;
134   tL2CAP_APPL_INFO reg_info_;
135 };
136 
AddFromStorage(const RawAddress & bd_addr)137 void EattExtension::AddFromStorage(const RawAddress& bd_addr) {
138   eatt_impl* p_eatt_impl = EattExtension::impl::GetImplInstance();
139   if (p_eatt_impl) {
140     p_eatt_impl->add_from_storage(bd_addr);
141   }
142 }
143 
EattExtension()144 EattExtension::EattExtension() : pimpl_(std::make_unique<impl>()) {}
145 
IsEattSupportedByPeer(const RawAddress & bd_addr)146 bool EattExtension::IsEattSupportedByPeer(const RawAddress& bd_addr) {
147   return pimpl_->eatt_impl_->is_eatt_supported_by_peer(bd_addr);
148 }
149 
Connect(const RawAddress & bd_addr)150 void EattExtension::Connect(const RawAddress& bd_addr) { pimpl_->eatt_impl_->connect(bd_addr); }
151 
Disconnect(const RawAddress & bd_addr,uint16_t cid)152 void EattExtension::Disconnect(const RawAddress& bd_addr, uint16_t cid) {
153   pimpl_->eatt_impl_->disconnect(bd_addr, cid);
154 }
155 
Reconfigure(const RawAddress & bd_addr,uint16_t cid,uint16_t mtu)156 void EattExtension::Reconfigure(const RawAddress& bd_addr, uint16_t cid, uint16_t mtu) {
157   pimpl_->eatt_impl_->reconfigure(bd_addr, cid, mtu);
158 }
ReconfigureAll(const RawAddress & bd_addr,uint16_t mtu)159 void EattExtension::ReconfigureAll(const RawAddress& bd_addr, uint16_t mtu) {
160   pimpl_->eatt_impl_->reconfigure_all(bd_addr, mtu);
161 }
162 
FindEattChannelByCid(const RawAddress & bd_addr,uint16_t cid)163 EattChannel* EattExtension::FindEattChannelByCid(const RawAddress& bd_addr, uint16_t cid) {
164   return pimpl_->eatt_impl_->find_eatt_channel_by_cid(bd_addr, cid);
165 }
166 
FindEattChannelByTransId(const RawAddress & bd_addr,uint32_t trans_id)167 EattChannel* EattExtension::FindEattChannelByTransId(const RawAddress& bd_addr, uint32_t trans_id) {
168   return pimpl_->eatt_impl_->find_eatt_channel_by_transid(bd_addr, trans_id);
169 }
170 
IsIndicationPending(const RawAddress & bd_addr,uint16_t indication_handle)171 bool EattExtension::IsIndicationPending(const RawAddress& bd_addr, uint16_t indication_handle) {
172   return pimpl_->eatt_impl_->is_indication_pending(bd_addr, indication_handle);
173 }
174 
GetChannelAvailableForIndication(const RawAddress & bd_addr)175 EattChannel* EattExtension::GetChannelAvailableForIndication(const RawAddress& bd_addr) {
176   return pimpl_->eatt_impl_->get_channel_available_for_indication(bd_addr);
177 }
178 
FreeGattResources(const RawAddress & bd_addr)179 void EattExtension::FreeGattResources(const RawAddress& bd_addr) {
180   pimpl_->eatt_impl_->free_gatt_resources(bd_addr);
181 }
182 
IsOutstandingMsgInSendQueue(const RawAddress & bd_addr)183 bool EattExtension::IsOutstandingMsgInSendQueue(const RawAddress& bd_addr) {
184   return pimpl_->eatt_impl_->is_outstanding_msg_in_send_queue(bd_addr);
185 }
186 
GetChannelWithQueuedDataToSend(const RawAddress & bd_addr)187 EattChannel* EattExtension::GetChannelWithQueuedDataToSend(const RawAddress& bd_addr) {
188   return pimpl_->eatt_impl_->get_channel_with_queued_data(bd_addr);
189 }
190 
GetChannelAvailableForClientRequest(const RawAddress & bd_addr)191 EattChannel* EattExtension::GetChannelAvailableForClientRequest(const RawAddress& bd_addr) {
192   return pimpl_->eatt_impl_->get_channel_available_for_client_request(bd_addr);
193 }
194 
195 /* Start stop GATT indication timer per CID */
StartIndicationConfirmationTimer(const RawAddress & bd_addr,uint16_t cid)196 void EattExtension::StartIndicationConfirmationTimer(const RawAddress& bd_addr, uint16_t cid) {
197   pimpl_->eatt_impl_->start_indication_confirm_timer(bd_addr, cid);
198 }
199 
StopIndicationConfirmationTimer(const RawAddress & bd_addr,uint16_t cid)200 void EattExtension::StopIndicationConfirmationTimer(const RawAddress& bd_addr, uint16_t cid) {
201   pimpl_->eatt_impl_->stop_indication_confirm_timer(bd_addr, cid);
202 }
203 
204 /* Start stop application indication timeout */
StartAppIndicationTimer(const RawAddress & bd_addr,uint16_t cid)205 void EattExtension::StartAppIndicationTimer(const RawAddress& bd_addr, uint16_t cid) {
206   pimpl_->eatt_impl_->start_app_indication_timer(bd_addr, cid);
207 }
208 
StopAppIndicationTimer(const RawAddress & bd_addr,uint16_t cid)209 void EattExtension::StopAppIndicationTimer(const RawAddress& bd_addr, uint16_t cid) {
210   pimpl_->eatt_impl_->stop_app_indication_timer(bd_addr, cid);
211 }
212 
Start()213 void EattExtension::Start() { pimpl_->Start(); }
214 
Stop()215 void EattExtension::Stop() { pimpl_->Stop(); }
216 
217 EattExtension::~EattExtension() = default;
218 
219 }  // namespace eatt
220 }  // namespace bluetooth
221