/**************************************************************************** * wireless/bluetooth/bt_keys.c * * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2016, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS * ; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include "bt_hcicore.h" #include "bt_smp.h" #include "bt_keys.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define bt_keys_foreach(list, cur, member) \ for (cur = list; *cur; cur = &(*cur)->member) /**************************************************************************** * Private Data ****************************************************************************/ static struct bt_keys_s g_key_pool[CONFIG_BLUETOOTH_MAX_PAIRED]; static FAR struct bt_keys_s *g_ltks; static FAR struct bt_keys_s *g_slave_ltks; static FAR struct bt_keys_s *g_irks; static FAR struct bt_keys_s *g_local_csrks; static FAR struct bt_keys_s *g_remote_csrks; /**************************************************************************** * Public Functions ****************************************************************************/ FAR struct bt_keys_s *bt_keys_get_addr(FAR const bt_addr_le_t *addr) { FAR struct bt_keys_s *keys; int i; wlinfo("%s\n", bt_addr_le_str(addr)); for (i = 0; i < CONFIG_BLUETOOTH_MAX_PAIRED; i++) { keys = &g_key_pool[i]; if (!bt_addr_le_cmp(&keys->addr, addr)) { return keys; } if (!bt_addr_le_cmp(&keys->addr, BT_ADDR_LE_ANY)) { bt_addr_le_copy(&keys->addr, addr); wlinfo("created %p for %s\n", keys, bt_addr_le_str(addr)); return keys; } } wlinfo("unable to create keys for %s\n", bt_addr_le_str(addr)); return NULL; } void bt_keys_clear(FAR struct bt_keys_s *keys, int type) { FAR struct bt_keys_s **cur; wlinfo("keys for %s type %d\n", bt_addr_le_str(&keys->addr), type); if (((type & keys->keys) & BT_KEYS_SLAVE_LTK)) { bt_keys_foreach(&g_slave_ltks, cur, slave_ltk.next) { if (*cur == keys) { *cur = (*cur)->slave_ltk.next; break; } } keys->keys &= ~BT_KEYS_SLAVE_LTK; } if (((type & keys->keys) & BT_KEYS_LTK)) { bt_keys_foreach(&g_ltks, cur, ltk.next) { if (*cur == keys) { *cur = (*cur)->ltk.next; break; } } keys->keys &= ~BT_KEYS_LTK; } if (((type & keys->keys) & BT_KEYS_IRK)) { bt_keys_foreach(&g_irks, cur, irk.next) { if (*cur == keys) { *cur = (*cur)->irk.next; break; } } keys->keys &= ~BT_KEYS_IRK; } if (((type & keys->keys) & BT_KEYS_LOCAL_CSRK)) { bt_keys_foreach(&g_local_csrks, cur, local_csrk.next) { if (*cur == keys) { *cur = (*cur)->local_csrk.next; break; } } keys->keys &= ~BT_KEYS_LOCAL_CSRK; } if (((type & keys->keys) & BT_KEYS_REMOTE_CSRK)) { bt_keys_foreach(&g_remote_csrks, cur, remote_csrk.next) { if (*cur == keys) { *cur = (*cur)->remote_csrk.next; break; } } keys->keys &= ~BT_KEYS_REMOTE_CSRK; } if (!keys->keys) { memset(keys, 0, sizeof(*keys)); } } FAR struct bt_keys_s *bt_keys_find(int type, FAR const bt_addr_le_t *addr) { FAR struct bt_keys_s **cur; wlinfo("type %d %s\n", type, bt_addr_le_str(addr)); switch (type) { case BT_KEYS_SLAVE_LTK: bt_keys_foreach(&g_slave_ltks, cur, slave_ltk.next) { if (!bt_addr_le_cmp(&(*cur)->addr, addr)) { break; } } return *cur; case BT_KEYS_LTK: bt_keys_foreach(&g_ltks, cur, ltk.next) { if (!bt_addr_le_cmp(&(*cur)->addr, addr)) { break; } } return *cur; case BT_KEYS_IRK: bt_keys_foreach(&g_irks, cur, irk.next) { if (!bt_addr_le_cmp(&(*cur)->addr, addr)) { break; } } return *cur; case BT_KEYS_LOCAL_CSRK: bt_keys_foreach(&g_local_csrks, cur, local_csrk.next) { if (!bt_addr_le_cmp(&(*cur)->addr, addr)) { break; } } return *cur; case BT_KEYS_REMOTE_CSRK: bt_keys_foreach(&g_remote_csrks, cur, remote_csrk.next) { if (!bt_addr_le_cmp(&(*cur)->addr, addr)) { break; } } return *cur; default: return NULL; } } void bt_keys_add_type(FAR struct bt_keys_s *keys, int type) { if ((keys->keys & type) != 0) { return; } switch (type) { case BT_KEYS_SLAVE_LTK: keys->slave_ltk.next = g_slave_ltks; g_slave_ltks = keys; break; case BT_KEYS_LTK: keys->ltk.next = g_ltks; g_ltks = keys; break; case BT_KEYS_IRK: keys->irk.next = g_irks; g_irks = keys; break; case BT_KEYS_LOCAL_CSRK: keys->local_csrk.next = g_local_csrks; g_local_csrks = keys; break; case BT_KEYS_REMOTE_CSRK: keys->remote_csrk.next = g_remote_csrks; g_remote_csrks = keys; break; default: wlerr("ERROR: Unknown key type %d\n", type); return; } keys->keys |= type; } FAR struct bt_keys_s *bt_keys_get_type(int type, FAR const bt_addr_le_t *addr) { FAR struct bt_keys_s *keys; wlinfo("type %d %s\n", type, bt_addr_le_str(addr)); keys = bt_keys_find(type, addr); if (keys) { return keys; } keys = bt_keys_get_addr(addr); if (!keys) { return NULL; } bt_keys_add_type(keys, type); return keys; } FAR struct bt_keys_s *bt_keys_find_irk(FAR const bt_addr_le_t * addr) { FAR struct bt_keys_s **cur; wlinfo("%s\n", bt_addr_le_str(addr)); if (!bt_addr_le_is_rpa(addr)) { return NULL; } bt_keys_foreach(&g_irks, cur, irk.next) { FAR struct bt_irk_s *irk = &(*cur)->irk; if (!bt_addr_cmp((bt_addr_t *) addr->val, &irk->rpa)) { wlinfo("cached RPA %s for %s\n", bt_addr_str(&irk->rpa), bt_addr_le_str(&(*cur)->addr)); return *cur; } if (bt_smp_irk_matches(irk->val, (bt_addr_t *) addr->val)) { FAR struct bt_keys_s *match = *cur; wlinfo("RPA %s matches %s\n", bt_addr_str(&irk->rpa), bt_addr_le_str(&(*cur)->addr)); bt_addr_copy(&irk->rpa, (bt_addr_t *) addr->val); /* Move to the beginning of the list for faster future lookups. */ if (match != g_irks) { /* Remove match from list */ *cur = irk->next; /* Add match to the beginning */ irk->next = g_irks; g_irks = match; } return match; } } wlinfo("No IRK for %s\n", bt_addr_le_str(addr)); return NULL; }