1 /******************************************************************************
2  *
3  *  Copyright 2024 The Android Open Source Project
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 
19 /******************************************************************************
20  *
21  *  this file contains functions relating to BLE connection parameter
22  *management.
23  *
24  ******************************************************************************/
25 
26 #define LOG_TAG "l2c_ble_conn_params"
27 
28 #include <bluetooth/log.h>
29 
30 #include "hci/controller_interface.h"
31 #include "internal_include/stack_config.h"
32 #include "main/shim/acl_api.h"
33 #include "main/shim/entry.h"
34 #include "stack/btm/btm_dev.h"
35 #include "stack/include/acl_api.h"
36 #include "stack/include/btm_ble_api_types.h"
37 #include "stack/include/l2c_api.h"
38 #include "stack/l2cap/l2c_int.h"
39 #include "types/raw_address.h"
40 
41 using namespace bluetooth;
42 
43 void l2cble_start_conn_update(tL2C_LCB* p_lcb);
44 static void l2cble_start_subrate_change(tL2C_LCB* p_lcb);
45 
46 /*******************************************************************************
47  *
48  *  Function        L2CA_UpdateBleConnParams
49  *
50  *  Description     Update BLE connection parameters.
51  *
52  *  Parameters:     BD Address of remote
53  *
54  *  Return value:   true if update started
55  *
56  ******************************************************************************/
L2CA_UpdateBleConnParams(const RawAddress & rem_bda,uint16_t min_int,uint16_t max_int,uint16_t latency,uint16_t timeout,uint16_t min_ce_len,uint16_t max_ce_len)57 bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
58                               uint16_t max_int, uint16_t latency,
59                               uint16_t timeout, uint16_t min_ce_len,
60                               uint16_t max_ce_len) {
61   tL2C_LCB* p_lcb;
62 
63   /* See if we have a link control block for the remote device */
64   p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
65 
66   /* If we do not have one, create one and accept the connection. */
67   if (!p_lcb || !BTM_IsAclConnectionUp(rem_bda, BT_TRANSPORT_LE)) {
68     log::warn("- unknown BD_ADDR {}", rem_bda);
69     return (false);
70   }
71 
72   if (p_lcb->transport != BT_TRANSPORT_LE) {
73     log::warn("- BD_ADDR {} not LE", rem_bda);
74     return (false);
75   }
76 
77   log::verbose(
78       "BD_ADDR={}, min_int={}, max_int={}, min_ce_len={}, max_ce_len={}",
79       rem_bda, min_int, max_int, min_ce_len, max_ce_len);
80 
81   p_lcb->min_interval = min_int;
82   p_lcb->max_interval = max_int;
83   p_lcb->latency = latency;
84   p_lcb->timeout = timeout;
85   p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
86   p_lcb->min_ce_len = min_ce_len;
87   p_lcb->max_ce_len = max_ce_len;
88 
89   l2cble_start_conn_update(p_lcb);
90 
91   return (true);
92 }
93 
94 static bool l2c_enable_update_ble_conn_params(tL2C_LCB* p_lcb, bool enable);
95 
96 /* When called with lock=true, LE connection parameters will be locked on
97  * fastest value, and we won't accept request to change it from remote. When
98  * called with lock=false, parameters are relaxed.
99  */
L2CA_LockBleConnParamsForServiceDiscovery(const RawAddress & rem_bda,bool lock)100 void L2CA_LockBleConnParamsForServiceDiscovery(const RawAddress& rem_bda,
101                                                bool lock) {
102   if (stack_config_get_interface()->get_pts_conn_updates_disabled()) return;
103 
104   tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
105   if (!p_lcb) {
106     log::warn("unknown address {}", rem_bda);
107     return;
108   }
109 
110   if (p_lcb->transport != BT_TRANSPORT_LE) {
111     log::warn("{} not LE, link role {}", rem_bda, p_lcb->LinkRole());
112     return;
113   }
114 
115   if (lock == p_lcb->conn_update_blocked_by_service_discovery) {
116     log::warn("{} service discovery already locked/unlocked conn params: {}",
117               rem_bda, lock);
118     return;
119   }
120 
121   p_lcb->conn_update_blocked_by_service_discovery = lock;
122 
123   if (p_lcb->conn_update_blocked_by_profile_connection) {
124     log::info("{} conn params stay locked because of audio setup", rem_bda);
125     return;
126   }
127 
128   log::info("{} Locking/unlocking conn params for service discovery: {}",
129             rem_bda, lock);
130   l2c_enable_update_ble_conn_params(p_lcb, !lock);
131 }
132 
133 /* When called with lock=true, LE connection parameters will be locked on
134  * fastest value, and we won't accept request to change it from remote. When
135  * called with lock=false, parameters are relaxed.
136  */
L2CA_LockBleConnParamsForProfileConnection(const RawAddress & rem_bda,bool lock)137 void L2CA_LockBleConnParamsForProfileConnection(const RawAddress& rem_bda,
138                                                 bool lock) {
139   if (stack_config_get_interface()->get_pts_conn_updates_disabled()) return;
140 
141   tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
142   if (!p_lcb) {
143     log::warn("unknown address {}", rem_bda);
144     return;
145   }
146 
147   if (p_lcb->transport != BT_TRANSPORT_LE) {
148     log::warn("{} not LE, link role {}", rem_bda, p_lcb->LinkRole());
149     return;
150   }
151 
152   if (lock == p_lcb->conn_update_blocked_by_profile_connection) {
153     log::info("{} audio setup already locked/unlocked conn params: {}", rem_bda,
154               lock);
155     return;
156   }
157 
158   p_lcb->conn_update_blocked_by_profile_connection = lock;
159 
160   if (p_lcb->conn_update_blocked_by_service_discovery) {
161     log::info("{} conn params stay locked because of service discovery",
162               rem_bda);
163     return;
164   }
165 
166   log::info("{} Locking/unlocking conn params for audio setup: {}", rem_bda,
167             lock);
168   l2c_enable_update_ble_conn_params(p_lcb, !lock);
169 }
170 
l2c_enable_update_ble_conn_params(tL2C_LCB * p_lcb,bool enable)171 static bool l2c_enable_update_ble_conn_params(tL2C_LCB* p_lcb, bool enable) {
172   log::debug("{} enable {} current upd state 0x{:02x}", p_lcb->remote_bd_addr,
173              enable, p_lcb->conn_update_mask);
174 
175   if (enable) {
176     p_lcb->conn_update_mask &= ~L2C_BLE_CONN_UPDATE_DISABLE;
177     p_lcb->subrate_req_mask &= ~L2C_BLE_SUBRATE_REQ_DISABLE;
178   } else {
179     p_lcb->conn_update_mask |= L2C_BLE_CONN_UPDATE_DISABLE;
180     p_lcb->subrate_req_mask |= L2C_BLE_SUBRATE_REQ_DISABLE;
181   }
182 
183   l2cble_start_conn_update(p_lcb);
184 
185   return (true);
186 }
187 
188 /*******************************************************************************
189  *
190  *  Function        l2cble_start_conn_update
191  *
192  *  Description     Start the BLE connection parameter update process based on
193  *                  status.
194  *
195  *  Parameters:     lcb : l2cap link control block
196  *
197  *  Return value:   none
198  *
199  ******************************************************************************/
l2cble_start_conn_update(tL2C_LCB * p_lcb)200 void l2cble_start_conn_update(tL2C_LCB* p_lcb) {
201   uint16_t min_conn_int, max_conn_int, peripheral_latency, supervision_tout;
202   if (!BTM_IsAclConnectionUp(p_lcb->remote_bd_addr, BT_TRANSPORT_LE)) {
203     log::error("No known connection ACL for {}", p_lcb->remote_bd_addr);
204     return;
205   }
206 
207   // TODO(armansito): The return value of this call wasn't being used but the
208   // logic of this function might be depending on its side effects. We should
209   // verify if this call is needed at all and remove it otherwise.
210   btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
211 
212   if ((p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) ||
213       (p_lcb->subrate_req_mask & L2C_BLE_SUBRATE_REQ_PENDING)) {
214     return;
215   }
216 
217   if (p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) {
218     /* application requests to disable parameters update.
219        If parameters are already updated, lets set them
220        up to what has been requested during connection establishement */
221     if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM &&
222         /* current connection interval is greater than default min */
223         p_lcb->min_interval > BTM_BLE_CONN_INT_MIN) {
224       /* use 7.5 ms as fast connection parameter, 0 peripheral latency */
225       min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
226 
227       L2CA_AdjustConnectionIntervals(&min_conn_int, &max_conn_int,
228                                      BTM_BLE_CONN_INT_MIN);
229 
230       peripheral_latency = BTM_BLE_CONN_PERIPHERAL_LATENCY_DEF;
231       supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
232 
233       /* if both side 4.1, or we are central device, send HCI command */
234       if (p_lcb->IsLinkRoleCentral() ||
235           (bluetooth::shim::GetController()
236                ->SupportsBleConnectionParametersRequest() &&
237            acl_peer_supports_ble_connection_parameters_request(
238                p_lcb->remote_bd_addr))) {
239         acl_ble_connection_parameters_request(p_lcb->Handle(), min_conn_int,
240                                               max_conn_int, peripheral_latency,
241                                               supervision_tout, 0, 0);
242         p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
243       } else {
244         l2cu_send_peer_ble_par_req(p_lcb, min_conn_int, max_conn_int,
245                                    peripheral_latency, supervision_tout);
246       }
247       p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM;
248       p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
249     }
250   } else {
251     /* application allows to do update, if we were delaying one do it now */
252     if (p_lcb->conn_update_mask & L2C_BLE_NEW_CONN_PARAM) {
253       /* if both side 4.1, or we are central device, send HCI command */
254       if (p_lcb->IsLinkRoleCentral() ||
255           (bluetooth::shim::GetController()
256                ->SupportsBleConnectionParametersRequest() &&
257            acl_peer_supports_ble_connection_parameters_request(
258                p_lcb->remote_bd_addr))) {
259         acl_ble_connection_parameters_request(
260             p_lcb->Handle(), p_lcb->min_interval, p_lcb->max_interval,
261             p_lcb->latency, p_lcb->timeout, p_lcb->min_ce_len,
262             p_lcb->max_ce_len);
263         p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
264       } else {
265         l2cu_send_peer_ble_par_req(p_lcb, p_lcb->min_interval,
266                                    p_lcb->max_interval, p_lcb->latency,
267                                    p_lcb->timeout);
268       }
269       p_lcb->conn_update_mask &= ~L2C_BLE_NEW_CONN_PARAM;
270       p_lcb->conn_update_mask |= L2C_BLE_NOT_DEFAULT_PARAM;
271     }
272   }
273 }
274 
275 /*******************************************************************************
276  *
277  * Function         l2cble_process_conn_update_evt
278  *
279  * Description      This function enables the connection update request from
280  *                  remote after a successful connection update response is
281  *                  received.
282  *
283  * Returns          void
284  *
285  ******************************************************************************/
l2cble_process_conn_update_evt(uint16_t handle,uint8_t status,uint16_t,uint16_t,uint16_t)286 void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
287                                     uint16_t /* interval */,
288                                     uint16_t /* latency */,
289                                     uint16_t /* timeout */) {
290   log::verbose("");
291 
292   /* See if we have a link control block for the remote device */
293   tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
294   if (!p_lcb) {
295     log::warn("Invalid handle: {}", handle);
296     return;
297   }
298 
299   p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING;
300 
301   if (status != HCI_SUCCESS) {
302     log::warn("Error status: {}", status);
303   }
304 
305   l2cble_start_conn_update(p_lcb);
306 
307   l2cble_start_subrate_change(p_lcb);
308 
309   log::verbose("conn_update_mask={} , subrate_req_mask={}",
310                p_lcb->conn_update_mask, p_lcb->subrate_req_mask);
311 }
312 
l2cble_use_preferred_conn_params(const RawAddress & bda)313 void l2cble_use_preferred_conn_params(const RawAddress& bda) {
314   tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
315   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
316 
317   /* If there are any preferred connection parameters, set them now */
318   if ((p_lcb != NULL) && (p_dev_rec != NULL) &&
319       (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
320       (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX) &&
321       (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN) &&
322       (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX) &&
323       (p_dev_rec->conn_params.peripheral_latency <= BTM_BLE_CONN_LATENCY_MAX) &&
324       (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
325       (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
326       ((p_lcb->min_interval < p_dev_rec->conn_params.min_conn_int &&
327         p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
328        (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) ||
329        (p_lcb->latency > p_dev_rec->conn_params.peripheral_latency) ||
330        (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout))) {
331     log::verbose(
332         "HANDLE={} min_conn_int={} max_conn_int={} peripheral_latency={} "
333         "supervision_tout={}",
334         p_lcb->Handle(), p_dev_rec->conn_params.min_conn_int,
335         p_dev_rec->conn_params.max_conn_int,
336         p_dev_rec->conn_params.peripheral_latency,
337         p_dev_rec->conn_params.supervision_tout);
338 
339     p_lcb->min_interval = p_dev_rec->conn_params.min_conn_int;
340     p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int;
341     p_lcb->timeout = p_dev_rec->conn_params.supervision_tout;
342     p_lcb->latency = p_dev_rec->conn_params.peripheral_latency;
343 
344     acl_ble_connection_parameters_request(
345         p_lcb->Handle(), p_dev_rec->conn_params.min_conn_int,
346         p_dev_rec->conn_params.max_conn_int,
347         p_dev_rec->conn_params.peripheral_latency,
348         p_dev_rec->conn_params.supervision_tout, 0, 0);
349   }
350 }
351 
352 /*******************************************************************************
353  *
354  *  Function        l2cble_start_subrate_change
355  *
356  *  Description     Start the BLE subrate change process based on
357  *                  status.
358  *
359  *  Parameters:     lcb : l2cap link control block
360  *
361  *  Return value:   none
362  *
363  ******************************************************************************/
l2cble_start_subrate_change(tL2C_LCB * p_lcb)364 static void l2cble_start_subrate_change(tL2C_LCB* p_lcb) {
365   if (!BTM_IsAclConnectionUp(p_lcb->remote_bd_addr, BT_TRANSPORT_LE)) {
366     log::error("No known connection ACL for {}", p_lcb->remote_bd_addr);
367     return;
368   }
369 
370   btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
371 
372   log::verbose("subrate_req_mask={} conn_update_mask={}",
373                p_lcb->subrate_req_mask, p_lcb->conn_update_mask);
374 
375   if (p_lcb->subrate_req_mask & L2C_BLE_SUBRATE_REQ_PENDING) {
376     log::verbose("returning L2C_BLE_SUBRATE_REQ_PENDING");
377     return;
378   }
379 
380   if (p_lcb->subrate_req_mask & L2C_BLE_SUBRATE_REQ_DISABLE) {
381     log::verbose("returning L2C_BLE_SUBRATE_REQ_DISABLE");
382     return;
383   }
384 
385   /* application allows to do update, if we were delaying one do it now */
386   if (!(p_lcb->subrate_req_mask & L2C_BLE_NEW_SUBRATE_PARAM) ||
387       (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) ||
388       (p_lcb->conn_update_mask & L2C_BLE_NEW_CONN_PARAM)) {
389     log::verbose("returning L2C_BLE_NEW_SUBRATE_PARAM");
390     return;
391   }
392 
393   if (!bluetooth::shim::GetController()->SupportsBleConnectionSubrating() ||
394       !acl_peer_supports_ble_connection_subrating(p_lcb->remote_bd_addr) ||
395       !acl_peer_supports_ble_connection_subrating_host(p_lcb->remote_bd_addr)) {
396     log::verbose(
397         "returning L2C_BLE_NEW_SUBRATE_PARAM local_host_sup={}, "
398         "local_conn_subrarte_sup={}, peer_subrate_sup={}, peer_host_sup={}",
399         bluetooth::shim::GetController()->SupportsBleConnectionSubratingHost(),
400         bluetooth::shim::GetController()->SupportsBleConnectionSubrating(),
401         acl_peer_supports_ble_connection_subrating(p_lcb->remote_bd_addr),
402         acl_peer_supports_ble_connection_subrating_host(p_lcb->remote_bd_addr));
403     return;
404   }
405 
406   log::verbose("Sending HCI cmd for subrate req");
407   bluetooth::shim::ACL_LeSubrateRequest(
408       p_lcb->Handle(), p_lcb->subrate_min, p_lcb->subrate_max,
409       p_lcb->max_latency, p_lcb->cont_num, p_lcb->supervision_tout);
410 
411   p_lcb->subrate_req_mask |= L2C_BLE_SUBRATE_REQ_PENDING;
412   p_lcb->subrate_req_mask &= ~L2C_BLE_NEW_SUBRATE_PARAM;
413   p_lcb->conn_update_mask |= L2C_BLE_NOT_DEFAULT_PARAM;
414 }
415 
416 /*******************************************************************************
417  *
418  *  Function        L2CA_SetDefaultSubrate
419  *
420  *  Description     BLE Set Default Subrate
421  *
422  *  Parameters:     Subrate parameters
423  *
424  *  Return value:   void
425  *
426  ******************************************************************************/
L2CA_SetDefaultSubrate(uint16_t subrate_min,uint16_t subrate_max,uint16_t max_latency,uint16_t cont_num,uint16_t timeout)427 void L2CA_SetDefaultSubrate(uint16_t subrate_min, uint16_t subrate_max,
428                             uint16_t max_latency, uint16_t cont_num,
429                             uint16_t timeout) {
430   log::verbose(
431       "subrate_min={}, subrate_max={}, max_latency={}, cont_num={}, timeout={}",
432       subrate_min, subrate_max, max_latency, cont_num, timeout);
433 
434   bluetooth::shim::ACL_LeSetDefaultSubrate(subrate_min, subrate_max,
435                                            max_latency, cont_num, timeout);
436 }
437 
438 /*******************************************************************************
439  *
440  *  Function        L2CA_SubrateRequest
441  *
442  *  Description     BLE Subrate request.
443  *
444  *  Parameters:     Subrate parameters
445  *
446  *  Return value:   true if update started
447  *
448  ******************************************************************************/
L2CA_SubrateRequest(const RawAddress & rem_bda,uint16_t subrate_min,uint16_t subrate_max,uint16_t max_latency,uint16_t cont_num,uint16_t timeout)449 bool L2CA_SubrateRequest(const RawAddress& rem_bda, uint16_t subrate_min,
450                          uint16_t subrate_max, uint16_t max_latency,
451                          uint16_t cont_num, uint16_t timeout) {
452   tL2C_LCB* p_lcb;
453 
454   /* See if we have a link control block for the remote device */
455   p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
456 
457   /* If we don't have one, create one and accept the connection. */
458   if (!p_lcb || !BTM_IsAclConnectionUp(rem_bda, BT_TRANSPORT_LE)) {
459     log::warn("unknown BD_ADDR {}", rem_bda);
460     return (false);
461   }
462 
463   if (p_lcb->transport != BT_TRANSPORT_LE) {
464     log::warn("BD_ADDR {} not LE", rem_bda);
465     return (false);
466   }
467 
468   log::verbose(
469       "BD_ADDR={}, subrate_min={}, subrate_max={}, max_latency={}, "
470       "cont_num={}, timeout={}",
471       rem_bda, subrate_min, subrate_max, max_latency, cont_num, timeout);
472 
473   p_lcb->subrate_min = subrate_min;
474   p_lcb->subrate_max = subrate_max;
475   p_lcb->max_latency = max_latency;
476   p_lcb->cont_num = cont_num;
477   p_lcb->subrate_req_mask |= L2C_BLE_NEW_SUBRATE_PARAM;
478   p_lcb->supervision_tout = timeout;
479 
480   l2cble_start_subrate_change(p_lcb);
481 
482   return (true);
483 }
484 
485 /*******************************************************************************
486  *
487  * Function         l2cble_process_subrate_change_evt
488  *
489  * Description      This function enables LE subrating
490  *                  after a successful subrate change process is
491  *                  done.
492  *
493  * Parameters:      LE connection handle
494  *                  status
495  *                  subrate factor
496  *                  peripheral latency
497  *                  continuation number
498  *                  supervision timeout
499  *
500  * Returns          void
501  *
502  ******************************************************************************/
l2cble_process_subrate_change_evt(uint16_t handle,uint8_t status,uint16_t,uint16_t,uint16_t,uint16_t)503 void l2cble_process_subrate_change_evt(uint16_t handle, uint8_t status,
504                                        uint16_t /* subrate_factor */,
505                                        uint16_t /* peripheral_latency */,
506                                        uint16_t /* cont_num */,
507                                        uint16_t /* timeout */) {
508   log::verbose("");
509 
510   /* See if we have a link control block for the remote device */
511   tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
512   if (!p_lcb) {
513     log::warn("Invalid handle: {}", handle);
514     return;
515   }
516 
517   p_lcb->subrate_req_mask &= ~L2C_BLE_SUBRATE_REQ_PENDING;
518 
519   if (status != HCI_SUCCESS) {
520     log::warn("Error status: {}", status);
521   }
522 
523   l2cble_start_conn_update(p_lcb);
524 
525   l2cble_start_subrate_change(p_lcb);
526 
527   log::verbose("conn_update_mask={} , subrate_req_mask={}",
528                p_lcb->conn_update_mask, p_lcb->subrate_req_mask);
529 }
530