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

Commit aa4d762b 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
Change-Id: I22f6c82c64a9a9bfb2a16d79182903e5aa011355
parent 1df3575f
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 encr_enable);
extern BOOLEAN 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 @@ BOOLEAN 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 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
                          LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap,
                          UINT8 pin_length)
{
    tBTM_SEC_DEV_REC  *p_dev_rec;
    int               i, j;
    BOOLEAN           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 @@ BOOLEAN 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 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
    p_dev_rec->num_read_pages = 0;
    if (features)
    {
        BOOLEAN 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 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
*******************************************************************************/
BOOLEAN 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 @@ BOOLEAN 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       ot = 0xFFFFFFFF;
    UINT32       ts_oldest = 0xFFFFFFFF;
    tBTM_SEC_DEV_REC *p_oldest_paired = NULL;
    UINT32       ot_paired = 0xFFFFFFFF;
    UINT32       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
@@ -1057,6 +1057,7 @@ extern void btm_report_device_status (tBTM_DEV_STATUS status);
*/
extern BOOLEAN 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 (BD_ADDR bd_addr);