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 <map>
19 #include <queue>
20 
21 #include "acl_api.h"
22 #include "base/bind_helpers.h"
23 #include "bt_types.h"
24 #include "device/include/controller.h"
25 #include "eatt.h"
26 #include "l2c_api.h"
27 #include "osi/include/alarm.h"
28 #include "stack/btm/btm_sec.h"
29 #include "stack/gatt/gatt_int.h"
30 #include "stack/l2cap/l2c_int.h"
31 
32 namespace bluetooth {
33 namespace eatt {
34 
35 #define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
36 
37 class eatt_device {
38  public:
39   RawAddress bda_;
40   uint16_t rx_mtu_;
41   uint16_t rx_mps_;
42 
43   tGATT_TCB* eatt_tcb_;
44 
45   std::map<uint16_t, std::shared_ptr<EattChannel>> eatt_channels;
46 
eatt_device(const RawAddress & bd_addr,uint16_t mtu,uint16_t mps)47   eatt_device(const RawAddress& bd_addr, uint16_t mtu, uint16_t mps)
48       : rx_mtu_(mtu), rx_mps_(mps), eatt_tcb_(nullptr) {
49     bda_ = bd_addr;
50   }
51 };
52 
53 struct eatt_impl {
54   std::vector<eatt_device> devices_;
55   uint16_t psm_;
56   uint16_t default_mtu_;
57   uint16_t max_mps_;
58   tL2CAP_APPL_INFO reg_info_;
59 
eatt_impleatt_impl60   eatt_impl() {
61     default_mtu_ = EATT_DEFAULT_MTU;
62     max_mps_ = EATT_MIN_MTU_MPS;
63     psm_ = BT_PSM_EATT;
64   };
65 
66   ~eatt_impl() = default;
67 
find_device_by_cideatt_impl68   eatt_device* find_device_by_cid(uint16_t lcid) {
69     /* This works only because Android CIDs are unique across the ACL
70      * connections */
71     auto iter = find_if(devices_.begin(), devices_.end(),
72                         [&lcid](const eatt_device& ed) {
73                           auto it = ed.eatt_channels.find(lcid);
74                           return it != ed.eatt_channels.end();
75                         });
76 
77     return (iter == devices_.end()) ? nullptr : &(*iter);
78   }
79 
find_channel_by_cideatt_impl80   EattChannel* find_channel_by_cid(uint16_t lcid) {
81     eatt_device* eatt_dev = find_device_by_cid(lcid);
82     if (!eatt_dev) return nullptr;
83 
84     auto it = eatt_dev->eatt_channels.find(lcid);
85     return (it == eatt_dev->eatt_channels.end()) ? nullptr : it->second.get();
86   }
87 
find_channel_by_cideatt_impl88   EattChannel* find_channel_by_cid(const RawAddress& bdaddr, uint16_t lcid) {
89     eatt_device* eatt_dev = find_device_by_address(bdaddr);
90     if (!eatt_dev) return nullptr;
91 
92     auto it = eatt_dev->eatt_channels.find(lcid);
93     return (it == eatt_dev->eatt_channels.end()) ? nullptr : it->second.get();
94   }
95 
remove_channel_by_cideatt_impl96   void remove_channel_by_cid(eatt_device* eatt_dev, uint16_t lcid) {
97     eatt_dev->eatt_channels.erase(lcid);
98 
99     if (eatt_dev->eatt_channels.size() == 0) eatt_dev->eatt_tcb_ = NULL;
100   }
101 
remove_channel_by_cideatt_impl102   void remove_channel_by_cid(uint16_t lcid) {
103     eatt_device* eatt_dev = find_device_by_cid(lcid);
104     if (!eatt_dev) return;
105 
106     remove_channel_by_cid(eatt_dev, lcid);
107   }
108 
eatt_l2cap_connect_indeatt_impl109   void eatt_l2cap_connect_ind(const RawAddress& bda,
110                               std::vector<uint16_t>& lcids, uint16_t psm,
111                               uint16_t peer_mtu, uint8_t identifier) {
112     /* The assumption is that L2CAP layer already check parameters etc.
113      * Get our capabilities and accept all the channels.
114      */
115     eatt_device* eatt_dev = this->find_device_by_address(bda);
116     if (!eatt_dev) {
117       LOG(ERROR) << __func__ << " unknown device: " << bda;
118       L2CA_ConnectCreditBasedRsp(bda, identifier, lcids,
119                                  L2CAP_CONN_NO_RESOURCES, NULL);
120       return;
121     }
122 
123     uint16_t max_mps = controller_get_interface()->get_acl_data_size_ble();
124 
125     tL2CAP_LE_CFG_INFO local_coc_cfg = {
126         .mtu = eatt_dev->rx_mtu_,
127         .mps = eatt_dev->rx_mps_ < max_mps ? eatt_dev->rx_mps_ : max_mps,
128         .credits = L2CAP_LE_CREDIT_DEFAULT};
129 
130     if (!L2CA_ConnectCreditBasedRsp(bda, identifier, lcids, L2CAP_CONN_OK,
131                                     &local_coc_cfg))
132       return;
133 
134     if (!eatt_dev->eatt_tcb_) {
135       eatt_dev->eatt_tcb_ =
136           gatt_find_tcb_by_addr(eatt_dev->bda_, BT_TRANSPORT_LE);
137       CHECK(eatt_dev->eatt_tcb_);
138     }
139 
140     for (uint16_t cid : lcids) {
141       EattChannel* channel = find_eatt_channel_by_cid(bda, cid);
142       CHECK(!channel);
143 
144       auto chan = std::make_shared<EattChannel>(eatt_dev->bda_, cid, peer_mtu,
145                                                 eatt_dev->rx_mtu_);
146       eatt_dev->eatt_channels.insert({cid, chan});
147 
148       chan->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED);
149       eatt_dev->eatt_tcb_->eatt++;
150 
151       LOG(INFO) << __func__ << " Channel connected CID " << loghex(cid);
152     }
153   }
154 
eatt_l2cap_connect_cfmeatt_impl155   void eatt_l2cap_connect_cfm(const RawAddress& bda, uint16_t lcid,
156                               uint16_t peer_mtu, uint16_t result) {
157     LOG(INFO) << __func__ << " bda: " << bda << " cid: " << +lcid
158               << "peer mtu: " << +peer_mtu << " result " << +result;
159 
160     eatt_device* eatt_dev = find_device_by_address(bda);
161     if (!eatt_dev) {
162       LOG(ERROR) << __func__ << " unknown device";
163       return;
164     }
165 
166     EattChannel* channel = this->find_channel_by_cid(bda, lcid);
167     if (!channel) {
168       LOG(ERROR) << __func__ << " unknown cid: " << loghex(lcid);
169       return;
170     }
171 
172     if (result != L2CAP_CONN_OK) {
173       LOG(ERROR) << __func__
174                  << " Could not connect CoC result: " << loghex(result);
175       remove_channel_by_cid(eatt_dev, lcid);
176       return;
177     }
178 
179     channel->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED);
180     channel->EattChannelSetTxMTU(peer_mtu);
181 
182     CHECK(eatt_dev->eatt_tcb_);
183     CHECK(eatt_dev->bda_ == channel->bda_);
184     eatt_dev->eatt_tcb_->eatt++;
185 
186     LOG(INFO) << __func__ << " Channel connected CID " << loghex(lcid);
187   }
188 
eatt_l2cap_reconfig_completedeatt_impl189   void eatt_l2cap_reconfig_completed(const RawAddress& bda, uint16_t lcid,
190                                      bool is_local_cfg,
191                                      tL2CAP_LE_CFG_INFO* p_cfg) {
192     LOG(INFO) << __func__ << "lcid: " << loghex(lcid)
193               << " local cfg?: " << is_local_cfg;
194 
195     if (p_cfg->result != L2CAP_CFG_OK) {
196       LOG(INFO) << __func__ << " reconfig failed lcid: " << loghex(lcid)
197                 << " result: " << loghex(p_cfg->result);
198       return;
199     }
200 
201     EattChannel* channel = find_channel_by_cid(bda, lcid);
202     if (!channel) return;
203 
204     /* On this layer we don't care about mps as this is handled in L2CAP layer
205      */
206     if (is_local_cfg)
207       channel->rx_mtu_ = p_cfg->mtu;
208     else
209       channel->tx_mtu_ = p_cfg->mtu;
210 
211     /* Go back to open state */
212     channel->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED);
213   }
214 
eatt_l2cap_error_cbeatt_impl215   void eatt_l2cap_error_cb(uint16_t lcid, uint16_t reason) {
216     LOG(INFO) << __func__ << " cid: " << loghex(lcid) << " reason "
217               << loghex(reason);
218 
219     /*TODO: provide address in the L2CAP callback */
220 
221     EattChannel* channel = find_channel_by_cid(lcid);
222     if (!channel) {
223       LOG(ERROR) << __func__ << "Unknown lcid";
224       return;
225     }
226 
227     eatt_device* eatt_dev = find_device_by_address(channel->bda_);
228 
229     switch (channel->state_) {
230       case EattChannelState::EATT_CHANNEL_PENDING:
231         LOG(ERROR) << "Connecting failed";
232         remove_channel_by_cid(eatt_dev, lcid);
233         break;
234       case EattChannelState::EATT_CHANNEL_RECONFIGURING:
235         /* Just go back to open state */
236         LOG(ERROR) << "Reconfig failed";
237         channel->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED);
238         break;
239       default:
240         LOG(ERROR) << __func__ << "Invalid state: "
241                    << static_cast<uint8_t>(channel->state_);
242         break;
243     }
244   }
245 
eatt_l2cap_disconnect_indeatt_impl246   void eatt_l2cap_disconnect_ind(uint16_t lcid, bool please_confirm) {
247     LOG(INFO) << __func__ << " cid: " << loghex(lcid);
248     eatt_device* eatt_dev = find_device_by_cid(lcid);
249     if (!eatt_dev) {
250       LOG(ERROR) << __func__ << " unknown cid: " << loghex(lcid);
251       return;
252     }
253 
254     eatt_dev->eatt_tcb_->eatt--;
255     remove_channel_by_cid(eatt_dev, lcid);
256   }
257 
eatt_l2cap_data_indeatt_impl258   void eatt_l2cap_data_ind(uint16_t lcid, BT_HDR* data_p) {
259     LOG(INFO) << __func__ << " cid: " << loghex(lcid);
260     eatt_device* eatt_dev = find_device_by_cid(lcid);
261     if (!eatt_dev) {
262       LOG(ERROR) << __func__ << " unknown cid: " << loghex(lcid);
263       return;
264     }
265 
266     EattChannel* channel = find_channel_by_cid(eatt_dev->bda_, lcid);
267     if (!channel) {
268       LOG(ERROR) << __func__ << "Received data on closed channel "
269                  << loghex(lcid);
270       return;
271     }
272 
273     gatt_data_process(*eatt_dev->eatt_tcb_, channel->cid_, data_p);
274     osi_free(data_p);
275   }
276 
is_eatt_supported_by_peereatt_impl277   bool is_eatt_supported_by_peer(const RawAddress& bd_addr) {
278     return gatt_profile_get_eatt_support(bd_addr);
279   }
280 
find_device_by_addresseatt_impl281   eatt_device* find_device_by_address(const RawAddress& bd_addr) {
282     auto iter = find_if(
283         devices_.begin(), devices_.end(),
284         [&bd_addr](const eatt_device& ed) { return ed.bda_ == bd_addr; });
285 
286     return iter == devices_.end() ? nullptr : &(*iter);
287   }
288 
add_eatt_deviceeatt_impl289   eatt_device* add_eatt_device(const RawAddress& bd_addr) {
290     devices_.push_back(eatt_device(bd_addr, default_mtu_, max_mps_));
291     eatt_device* eatt_dev = &devices_.back();
292     return eatt_dev;
293   }
294 
connect_eatteatt_impl295   void connect_eatt(eatt_device* eatt_dev) {
296     /* Let us use maximum possible mps */
297     if (eatt_dev->rx_mps_ == EATT_MIN_MTU_MPS)
298       eatt_dev->rx_mps_ = controller_get_interface()->get_acl_data_size_ble();
299 
300     tL2CAP_LE_CFG_INFO local_coc_cfg = {
301         .mtu = eatt_dev->rx_mtu_,
302         .mps = eatt_dev->rx_mps_,
303         .credits = L2CAP_LE_CREDIT_DEFAULT,
304     };
305 
306     /* Warning! CIDs in Android are unique across the ACL connections */
307     std::vector<uint16_t> connecting_cids =
308         L2CA_ConnectCreditBasedReq(psm_, eatt_dev->bda_, &local_coc_cfg);
309 
310     if (connecting_cids.size() == 0) {
311       LOG(ERROR) << "Unable to get cid";
312       return;
313     }
314 
315     LOG(INFO) << __func__
316               << "Successfully sent CoC request, number of channel: "
317               << +connecting_cids.size();
318 
319     for (uint16_t cid : connecting_cids) {
320       LOG(INFO) << " \t cid: " << loghex(cid);
321 
322       auto chan = std::make_shared<EattChannel>(eatt_dev->bda_, cid, 0,
323                                                 eatt_dev->rx_mtu_);
324       eatt_dev->eatt_channels.insert({cid, chan});
325     }
326 
327     if (eatt_dev->eatt_tcb_) {
328       LOG(INFO) << __func__ << " has tcb ? " << eatt_dev->eatt_tcb_;
329       return;
330     }
331 
332     eatt_dev->eatt_tcb_ =
333         gatt_find_tcb_by_addr(eatt_dev->bda_, BT_TRANSPORT_LE);
334     CHECK(eatt_dev->eatt_tcb_);
335   }
336 
find_eatt_channel_by_cideatt_impl337   EattChannel* find_eatt_channel_by_cid(const RawAddress& bd_addr,
338                                         uint16_t cid) {
339     eatt_device* eatt_dev = find_device_by_address(bd_addr);
340 
341     LOG(INFO) << __func__ << bd_addr << " " << +cid;
342 
343     if (!eatt_dev) return nullptr;
344 
345     auto iter = find_if(
346         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
347         [&cid](const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
348           return el.first == cid;
349         });
350 
351     return iter == eatt_dev->eatt_channels.end() ? nullptr : iter->second.get();
352   }
353 
find_eatt_channel_by_transideatt_impl354   EattChannel* find_eatt_channel_by_transid(const RawAddress& bd_addr,
355                                             uint32_t trans_id) {
356     eatt_device* eatt_dev = find_device_by_address(bd_addr);
357     if (!eatt_dev) return nullptr;
358 
359     auto iter = find_if(
360         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
361         [&trans_id](
362             const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
363           return el.second->server_outstanding_cmd_.trans_id == trans_id;
364         });
365 
366     return iter == eatt_dev->eatt_channels.end() ? nullptr : iter->second.get();
367   }
368 
is_indication_pendingeatt_impl369   bool is_indication_pending(const RawAddress& bd_addr,
370                              uint16_t indication_handle) {
371     eatt_device* eatt_dev = find_device_by_address(bd_addr);
372     if (!eatt_dev) return false;
373 
374     auto iter = find_if(
375         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
376         [&indication_handle](
377             const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
378           return el.second->indicate_handle_ == indication_handle;
379         });
380 
381     return (iter != eatt_dev->eatt_channels.end());
382   };
383 
get_channel_available_for_indicationeatt_impl384   EattChannel* get_channel_available_for_indication(const RawAddress& bd_addr) {
385     eatt_device* eatt_dev = find_device_by_address(bd_addr);
386     auto iter = find_if(
387         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
388         [](const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
389           return !GATT_HANDLE_IS_VALID(el.second->indicate_handle_);
390         });
391 
392     return (iter == eatt_dev->eatt_channels.end()) ? nullptr
393                                                    : iter->second.get();
394   };
395 
get_channel_available_for_client_requesteatt_impl396   EattChannel* get_channel_available_for_client_request(
397       const RawAddress& bd_addr) {
398     eatt_device* eatt_dev = find_device_by_address(bd_addr);
399     if (!eatt_dev) return nullptr;
400 
401     auto iter = find_if(
402         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
403         [](const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
404           return el.second->cl_cmd_q_.empty();
405         });
406 
407     return (iter == eatt_dev->eatt_channels.end()) ? nullptr
408                                                    : iter->second.get();
409   }
410 
free_gatt_resourceseatt_impl411   void free_gatt_resources(const RawAddress& bd_addr) {
412     eatt_device* eatt_dev = find_device_by_address(bd_addr);
413     if (!eatt_dev) return;
414 
415     auto iter = eatt_dev->eatt_channels.begin();
416     while (iter != eatt_dev->eatt_channels.end()) {
417       EattChannel* channel = iter->second.get();
418 
419       fixed_queue_free(channel->server_outstanding_cmd_.multi_rsp_q, NULL);
420       channel->server_outstanding_cmd_.multi_rsp_q = NULL;
421     }
422   }
423 
is_outstanding_msg_in_send_queueeatt_impl424   bool is_outstanding_msg_in_send_queue(const RawAddress& bd_addr) {
425     eatt_device* eatt_dev = find_device_by_address(bd_addr);
426     if (!eatt_dev) return false;
427 
428     auto iter = find_if(
429         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
430         [](const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
431           return !el.second->cl_cmd_q_.empty();
432         });
433     return (iter != eatt_dev->eatt_channels.end());
434   }
435 
get_channel_with_queued_dataeatt_impl436   EattChannel* get_channel_with_queued_data(const RawAddress& bd_addr) {
437     eatt_device* eatt_dev = find_device_by_address(bd_addr);
438     if (!eatt_dev) return nullptr;
439 
440     auto iter = find_if(
441         eatt_dev->eatt_channels.begin(), eatt_dev->eatt_channels.end(),
442         [](const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el) {
443           return !el.second->cl_cmd_q_.empty();
444         });
445     return (iter == eatt_dev->eatt_channels.end()) ? nullptr
446                                                    : iter->second.get();
447   }
448 
eatt_ind_ack_timeouteatt_impl449   static void eatt_ind_ack_timeout(void* data) {
450     EattChannel* channel = (EattChannel*)data;
451     tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(channel->bda_, BT_TRANSPORT_LE);
452 
453     LOG(WARNING) << __func__ << ": send ack now";
454     attp_send_cl_confirmation_msg(*p_tcb, channel->cid_);
455   }
456 
eatt_ind_confirmation_timeouteatt_impl457   static void eatt_ind_confirmation_timeout(void* data) {
458     EattChannel* channel = (EattChannel*)data;
459     tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(channel->bda_, BT_TRANSPORT_LE);
460 
461     LOG(WARNING) << __func__ << " disconnecting...";
462     gatt_disconnect(p_tcb);
463   }
464 
start_indication_confirm_timereatt_impl465   void start_indication_confirm_timer(const RawAddress& bd_addr, uint16_t cid) {
466     EattChannel* channel = find_eatt_channel_by_cid(bd_addr, cid);
467     if (!channel) {
468       LOG(ERROR) << __func__ << "Unknown cid: " << loghex(cid) << " or device "
469                  << bd_addr;
470       return;
471     }
472 
473     alarm_set_on_mloop(channel->ind_confirmation_timer_,
474                        GATT_WAIT_FOR_RSP_TIMEOUT_MS,
475                        eatt_ind_confirmation_timeout, channel);
476   }
477 
stop_indication_confirm_timereatt_impl478   void stop_indication_confirm_timer(const RawAddress& bd_addr, uint16_t cid) {
479     EattChannel* channel = find_eatt_channel_by_cid(bd_addr, cid);
480     if (!channel) {
481       LOG(ERROR) << __func__ << "Unknown cid: " << loghex(cid) << " or device "
482                  << bd_addr;
483       return;
484     }
485 
486     alarm_cancel(channel->ind_confirmation_timer_);
487   }
488 
start_app_indication_timereatt_impl489   void start_app_indication_timer(const RawAddress& bd_addr, uint16_t cid) {
490     EattChannel* channel = find_eatt_channel_by_cid(bd_addr, cid);
491     if (!channel) {
492       LOG(ERROR) << __func__ << "Unknown cid: " << loghex(cid) << " or device "
493                  << bd_addr;
494       return;
495     }
496 
497     alarm_set_on_mloop(channel->ind_ack_timer_, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
498                        eatt_ind_ack_timeout, channel);
499   }
500 
stop_app_indication_timereatt_impl501   void stop_app_indication_timer(const RawAddress& bd_addr, uint16_t cid) {
502     EattChannel* channel = find_eatt_channel_by_cid(bd_addr, cid);
503     if (!channel) {
504       LOG(ERROR) << __func__ << "Unknown cid: " << loghex(cid) << " or device "
505                  << bd_addr;
506       return;
507     }
508 
509     alarm_cancel(channel->ind_ack_timer_);
510   }
511 
reconfigureeatt_impl512   void reconfigure(const RawAddress& bd_addr, uint16_t cid, uint16_t new_mtu) {
513     eatt_device* eatt_dev = find_device_by_address(bd_addr);
514     if (!eatt_dev) {
515       LOG(ERROR) << __func__ << "Unknown device " << bd_addr;
516       return;
517     }
518 
519     EattChannel* channel = find_eatt_channel_by_cid(bd_addr, cid);
520     if (!channel) {
521       LOG(ERROR) << __func__ << "Unknown cid: " << loghex(cid) << " or device "
522                  << bd_addr;
523       return;
524     }
525 
526     if (new_mtu <= channel->rx_mtu_) {
527       LOG(ERROR) << __func__ << "Invalid mtu: " << loghex(new_mtu);
528       return;
529     }
530 
531     std::vector<uint16_t> cids = {cid};
532 
533     tL2CAP_LE_CFG_INFO cfg = {.mps = eatt_dev->rx_mps_, .mtu = new_mtu};
534 
535     if (!L2CA_ReconfigCreditBasedConnsReq(eatt_dev->bda_, cids, &cfg))
536       LOG(ERROR) << __func__ << "Could not start reconfig cid: " << loghex(cid)
537                  << " or device " << bd_addr;
538   }
539 
reconfigure_alleatt_impl540   void reconfigure_all(const RawAddress& bd_addr, uint16_t new_mtu) {
541     eatt_device* eatt_dev = find_device_by_address(bd_addr);
542     if (!eatt_dev) {
543       LOG(ERROR) << __func__ << "Unknown device " << bd_addr;
544       return;
545     }
546 
547     uint8_t num_of_channels = eatt_dev->eatt_channels.size();
548     if (num_of_channels == 0) {
549       LOG(ERROR) << __func__ << "No channels for device " << bd_addr;
550       return;
551     }
552 
553     std::vector<uint16_t> cids;
554 
555     auto iter = eatt_dev->eatt_channels.begin();
556     while (iter != eatt_dev->eatt_channels.end()) {
557       uint16_t cid = iter->first;
558       cids.push_back(cid);
559       iter++;
560     }
561 
562     if (new_mtu <= EATT_MIN_MTU_MPS) {
563       LOG(ERROR) << __func__ << "Invalid mtu: " << loghex(new_mtu);
564       return;
565     }
566 
567     tL2CAP_LE_CFG_INFO cfg = {.mps = eatt_dev->rx_mps_, .mtu = new_mtu};
568 
569     if (!L2CA_ReconfigCreditBasedConnsReq(eatt_dev->bda_, cids, &cfg))
570       LOG(ERROR) << __func__ << "Could not start reconfig for device "
571                  << bd_addr;
572   }
573 
supported_features_cbeatt_impl574   void supported_features_cb(uint8_t role, const RawAddress& bd_addr,
575                              uint8_t features) {
576     bool is_eatt_supported = features & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
577 
578     LOG(INFO) << __func__ << " " << bd_addr
579               << " is_eatt_supported = " << int(is_eatt_supported);
580     if (!is_eatt_supported) return;
581 
582     eatt_device* eatt_dev = add_eatt_device(bd_addr);
583 
584     if (role != HCI_ROLE_CENTRAL) {
585       /* TODO For now do nothing, we could run a timer here and start EATT if
586        * not started by central */
587       LOG(INFO)
588           << " EATT Should be connected by the central. Let's wait for it.";
589       return;
590     }
591 
592     connect_eatt(eatt_dev);
593   }
594 
disconnect_channeleatt_impl595   void disconnect_channel(uint16_t cid) { L2CA_DisconnectReq(cid); }
596 
disconnecteatt_impl597   void disconnect(const RawAddress& bd_addr) {
598     LOG(INFO) << __func__ << " " << bd_addr;
599 
600     eatt_device* eatt_dev = find_device_by_address(bd_addr);
601     if (!eatt_dev) {
602       LOG(WARNING) << __func__ << " no eatt device found";
603       return;
604     }
605 
606     if (!eatt_dev->eatt_tcb_) {
607       LOG_ASSERT(eatt_dev->eatt_channels.size() == 0);
608       LOG(WARNING) << __func__ << " no eatt channels found";
609       return;
610     }
611 
612     auto iter = eatt_dev->eatt_channels.begin();
613     while (iter != eatt_dev->eatt_channels.end()) {
614       uint16_t cid = iter->first;
615       disconnect_channel(cid);
616       /* When initiating disconnection, stack will not notify us that it is
617        * done. We need to assume success
618        */
619       iter = eatt_dev->eatt_channels.erase(iter);
620     }
621     eatt_dev->eatt_tcb_->eatt = 0;
622     eatt_dev->eatt_tcb_ = nullptr;
623   }
624 
connecteatt_impl625   void connect(const RawAddress& bd_addr) {
626     eatt_device* eatt_dev = find_device_by_address(bd_addr);
627 
628     uint8_t role = L2CA_GetBleConnRole(bd_addr);
629     if (role == HCI_ROLE_UNKNOWN) {
630       LOG(ERROR) << __func__ << "Could not get device role" << bd_addr;
631       return;
632     }
633 
634     LOG(INFO) << __func__ << " device " << bd_addr << " role"
635               << (role == HCI_ROLE_CENTRAL ? "central" : "peripheral");
636 
637     if (eatt_dev) {
638       /* We are reconnecting device we know that support EATT.
639        * Just connect CoC
640        */
641       LOG(INFO) << __func__ << " Known device, connect eCoC";
642 
643       if (role != HCI_ROLE_CENTRAL) {
644         LOG(INFO)
645             << " EATT Should be connected by the central. Let's wait for it.";
646         return;
647       }
648 
649       connect_eatt(eatt_dev);
650       return;
651     }
652 
653     /* For new device, first read GATT server supported features. */
654     if (gatt_cl_read_sr_supp_feat_req(
655             bd_addr, base::BindOnce(&eatt_impl::supported_features_cb,
656                                     base::Unretained(this), role)) == false) {
657       LOG(INFO) << __func__ << "Eatt is not supported. Checked for device "
658                 << bd_addr;
659     }
660   }
661 
add_from_storageeatt_impl662   void add_from_storage(const RawAddress& bd_addr) {
663     eatt_device* eatt_dev = find_device_by_address(bd_addr);
664 
665     LOG(INFO) << __func__ << ", restoring: " << bd_addr;
666 
667     if (!eatt_dev) add_eatt_device(bd_addr);
668   }
669 };
670 
671 }  // namespace eatt
672 }  // namespace bluetooth
673