Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e427b2d1 authored by Andre Eisenbach's avatar Andre Eisenbach
Browse files

Fix 100 LE device connection limitation

Currently after 100 devices are added to the device security database,
any subsequent LE connection to a newly discovered LE device address
will fail as entries in the security record database are not reused.

This patch removes a device record if the device itself is removed and
also ensures that the oldest device security record is deleted if the
limit is reached to ensure a new record can be allocated.

Bug: 31625900
Test: SL4A multi-device connection test + regression
Change-Id: I22f6c82c64a9a9bfb2a16d79182903e5aa011355
(cherry picked from commit aa4d762b)
parent bc551894
Loading
Loading
Loading
Loading
+5 −9
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ extern void smp_link_encrypted(BD_ADDR bda, uint8_t encr_enable);
extern bool    smp_proc_ltk_request(BD_ADDR bda);
#endif
extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);

/*******************************************************************************/
/* External Function to be called by other modules                             */
/*******************************************************************************/
@@ -73,16 +74,11 @@ bool BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE d
                             tBLE_ADDR_TYPE addr_type)
{
    BTM_TRACE_DEBUG ("%s: dev_type=0x%x", __func__, dev_type);
    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev(bd_addr);

    if (!p_dev_rec) {
        if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) {
            BTM_TRACE_ERROR("%s: %d max devices reached!", __func__, BTM_SEC_MAX_DEVICE_RECORDS);
            return false;
        }

        p_dev_rec = osi_calloc(sizeof(tBTM_SEC_DEV_REC));
        list_append(btm_cb.sec_dev_rec, p_dev_rec);
    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
    if (!p_dev_rec)
    {
        p_dev_rec = btm_sec_allocate_dev_rec();

        memcpy(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
        p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
+75 −73
Original line number Diff line number Diff line
@@ -37,8 +37,6 @@
#include "hcidefs.h"
#include "l2c_api.h"

static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void);

/*******************************************************************************
**
** Function         BTM_SecAddDevice
@@ -63,22 +61,12 @@ bool BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
                          LINK_KEY link_key, uint8_t key_type, tBTM_IO_CAP io_cap,
                          uint8_t pin_length)
{
    tBTM_SEC_DEV_REC  *p_dev_rec;
    int               i, j;
    bool              found = false;

    BTM_TRACE_API("%s: link key type:%x", __func__, key_type);
    p_dev_rec = btm_find_dev (bd_addr);

    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
    if (!p_dev_rec)
    {
        if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) {
            BTM_TRACE_DEBUG("%s: Max devices reached!", __func__);
            return false;
        }

        BTM_TRACE_DEBUG ("%s: allocate a new dev rec", __func__);
        p_dev_rec = osi_calloc(sizeof(tBTM_SEC_DEV_REC));
        list_append(btm_cb.sec_dev_rec, p_dev_rec);
        p_dev_rec = btm_sec_allocate_dev_rec();

        memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
        p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
@@ -88,11 +76,19 @@ bool BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
        /* update conn params, use default value for background connection params */
        memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
#endif
    }

    p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;           /* Default value */
    } else {
        /* "Bump" timestamp for existing record */
        p_dev_rec->timestamp = btm_cb.dev_rec_count++;

        /* TODO(eisenbach):
         * Small refactor, but leaving original logic for now.
         * On the surface, this does not make any sense at all. Why change the
         * bond state for an existing device here? This logic should be verified
         * as part of a larger refactor.
         */
        p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
    }

    if (dev_class)
        memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN);

@@ -108,26 +104,23 @@ bool BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
    p_dev_rec->num_read_pages = 0;
    if (features)
    {
        bool found = false;
        memcpy (p_dev_rec->features, features, sizeof (p_dev_rec->features));
        for (i = HCI_EXT_FEATURES_PAGE_MAX; i >= 0; i--)
        for (int i = HCI_EXT_FEATURES_PAGE_MAX; !found && i >= 0; i--)
        {
            for (j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++)
            for (int j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++)
            {
                if (p_dev_rec->features[i][j] != 0)
                {
                    found = true;
                    break;
                }
            }
            if (found)
            {
                    p_dev_rec->num_read_pages = i + 1;
                    break;
                }
            }
        }
    else
    } else {
        memset (p_dev_rec->features, 0, sizeof (p_dev_rec->features));
    }

    BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);

@@ -177,8 +170,6 @@ bool BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
*******************************************************************************/
bool    BTM_SecDeleteDevice (BD_ADDR bd_addr)
{
    tBTM_SEC_DEV_REC *p_dev_rec;

    if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) ||
        BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR))
    {
@@ -186,7 +177,8 @@ bool BTM_SecDeleteDevice (BD_ADDR bd_addr)
        return false;
    }

    if ((p_dev_rec = btm_find_dev(bd_addr)) != NULL)
    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
    if (p_dev_rec != NULL)
    {
        btm_sec_free_dev(p_dev_rec);
        /* Tell controller to get rid of the link key, if it has one stored */
@@ -240,20 +232,10 @@ bool is_bd_addr_equal(void *data, void *context)
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
{
    tBTM_SEC_DEV_REC *p_dev_rec = NULL;
    tBTM_INQ_INFO    *p_inq_info;
    BTM_TRACE_EVENT ("btm_sec_alloc_dev");

    if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) {
        p_dev_rec = btm_find_oldest_dev();
    } else {
        BTM_TRACE_DEBUG ("allocate a new dev rec");
        p_dev_rec = osi_calloc(sizeof(tBTM_SEC_DEV_REC));
        list_append(btm_cb.sec_dev_rec, p_dev_rec);
    }

    p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;           /* Default value */
    p_dev_rec->sec_flags = BTM_SEC_IN_USE;
    tBTM_SEC_DEV_REC *p_dev_rec = btm_sec_allocate_dev_rec();

    /* Check with the BT manager if details about remote device are known */
    /* outgoing connection */
@@ -280,7 +262,6 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
    p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
#endif
    p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
    p_dev_rec->timestamp = btm_cb.dev_rec_count++;

    return(p_dev_rec);
}
@@ -295,17 +276,11 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
*******************************************************************************/
void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec)
{
    p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
    p_dev_rec->sec_flags = 0;

#if (BLE_INCLUDED == TRUE)
    /* Clear out any saved BLE keys */
    btm_sec_clear_ble_keys (p_dev_rec);
    /* clear the ble block */
    memset(&p_dev_rec->ble, 0, sizeof(tBTM_SEC_BLE));
#endif


    list_remove(btm_cb.sec_dev_rec, p_dev_rec);
}

/*******************************************************************************
@@ -475,8 +450,6 @@ void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec)

            /* remove the combined record */
            list_remove(btm_cb.sec_dev_rec, p_dev_rec);

            p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
            break;
        }

@@ -490,8 +463,6 @@ void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec)

                /* remove the combined record */
                list_remove(btm_cb.sec_dev_rec, p_dev_rec);

                p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
            }
            break;
        }
@@ -524,48 +495,79 @@ tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr)

/*******************************************************************************
**
** Function         btm_find_oldest_dev
** Function         btm_find_oldest_dev_rec
**
** Description      Locates the oldest device in use. It first looks for
**                  the oldest non-paired device.  If all devices are paired it
**                  deletes the oldest paired device.
**                  returns the oldest paired device.
**
** Returns          Pointer to the record or NULL
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
static tBTM_SEC_DEV_REC* btm_find_oldest_dev_rec (void)
{
    tBTM_SEC_DEV_REC *p_oldest = NULL;
    uint32_t     ot = 0xFFFFFFFF;
    uint32_t ts_oldest = 0xFFFFFFFF;
    tBTM_SEC_DEV_REC *p_oldest_paired = NULL;
    uint32_t     ot_paired = 0xFFFFFFFF;
    uint32_t ts_oldest_paired = 0xFFFFFFFF;

    /* First look for the non-paired devices for the oldest entry */
    list_node_t *end = list_end(btm_cb.sec_dev_rec);
    for (list_node_t *node = list_begin(btm_cb.sec_dev_rec); node != end; node = list_next(node)) {
        tBTM_SEC_DEV_REC *p_dev_rec = list_node(node);
        /* Device is not paired */

        if ((p_dev_rec->sec_flags & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) == 0) {
            if (p_dev_rec->timestamp < ot) {
            // Device is not paired
            if (p_dev_rec->timestamp < ts_oldest) {
                p_oldest = p_dev_rec;
                ot       = p_dev_rec->timestamp;
                ts_oldest = p_dev_rec->timestamp;
            }
        } else {
            // Paired device
            if (p_dev_rec->timestamp < ts_oldest_paired) {
                p_oldest_paired = p_dev_rec;
                ts_oldest_paired = p_dev_rec->timestamp;
            }
        }
            continue;
    }

        if (p_dev_rec->timestamp < ot_paired) {
            p_oldest_paired = p_dev_rec;
            ot_paired       = p_dev_rec->timestamp;
    // If we did not find any non-paired devices, use the oldest paired one...
    if (ts_oldest == 0xFFFFFFFF)
        p_oldest = p_oldest_paired;

    return p_oldest;
}

/*******************************************************************************
**
** Function         btm_sec_allocate_dev_rec
**
** Description      Attempts to allocate a new device record. If we have
**                  exceeded the maximum number of allowable records to
**                  allocate, the oldest record will be deleted to make room
**                  for the new record.
**
** Returns          Pointer to the newly allocated record
**
*******************************************************************************/
tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void)
{
    tBTM_SEC_DEV_REC *p_dev_rec = NULL;

    if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS)
    {
        p_dev_rec = btm_find_oldest_dev_rec();
        list_remove(btm_cb.sec_dev_rec, p_dev_rec);
    }

    /* if non-paired device return oldest */
    if (ot != 0xFFFFFFFF)
        return(p_oldest);
    p_dev_rec = osi_calloc(sizeof(tBTM_SEC_DEV_REC));
    list_append(btm_cb.sec_dev_rec, p_dev_rec);

    // Initialize defaults
    p_dev_rec->sec_flags = BTM_SEC_IN_USE;
    p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
    p_dev_rec->timestamp = btm_cb.dev_rec_count++;

    /* only paired devices present, return oldest */
    return p_oldest_paired;
    return p_dev_rec;
}

/*******************************************************************************
+1 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ extern void btm_report_device_status (tBTM_DEV_STATUS status);
*/
extern bool    btm_dev_support_switch (BD_ADDR bd_addr);

extern tBTM_SEC_DEV_REC  *btm_sec_allocate_dev_rec(void);
extern tBTM_SEC_DEV_REC  *btm_sec_alloc_dev (BD_ADDR bd_addr);
extern void               btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec);
extern tBTM_SEC_DEV_REC  *btm_find_dev (const BD_ADDR bd_addr);