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