| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| #include <stdint.h> |
| #include <assert.h> |
| #include <string.h> |
| #include "syscfg/syscfg.h" |
| #include "os/os.h" |
| #include "nimble/ble.h" |
| #include "nimble/nimble_opt.h" |
| #include "ble/xcvr.h" |
| #include "controller/ble_ll_whitelist.h" |
| #include "controller/ble_ll_hci.h" |
| #include "controller/ble_ll_adv.h" |
| #include "controller/ble_ll_scan.h" |
| #include "controller/ble_hw.h" |
| |
| #if (MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) < BLE_HW_WHITE_LIST_SIZE) |
| #define BLE_LL_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) |
| #else |
| #define BLE_LL_WHITELIST_SIZE BLE_HW_WHITE_LIST_SIZE |
| #endif |
| |
| struct ble_ll_whitelist_entry |
| { |
| uint8_t wl_valid; |
| uint8_t wl_addr_type; |
| uint8_t wl_dev_addr[BLE_DEV_ADDR_LEN]; |
| }; |
| |
| struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE]; |
| |
| static int |
| ble_ll_whitelist_chg_allowed(void) |
| { |
| int rc; |
| |
| /* |
| * This command is not allowed if: |
| * -> advertising uses the whitelist and we are currently advertising. |
| * -> scanning uses the whitelist and is enabled. |
| * -> initiating uses whitelist and a LE create connection command is in |
| * progress |
| */ |
| rc = 1; |
| if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) { |
| rc = 0; |
| } |
| return rc; |
| } |
| |
| /** |
| * Clear the whitelist. |
| * |
| * @return int 0: success, BLE error code otherwise |
| */ |
| int |
| ble_ll_whitelist_clear(void) |
| { |
| int i; |
| struct ble_ll_whitelist_entry *wl; |
| |
| /* Check proper state */ |
| if (!ble_ll_whitelist_chg_allowed()) { |
| return BLE_ERR_CMD_DISALLOWED; |
| } |
| |
| /* Set the number of entries to 0 */ |
| wl = &g_ble_ll_whitelist[0]; |
| for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) { |
| wl->wl_valid = 0; |
| ++wl; |
| } |
| |
| #if (BLE_USES_HW_WHITELIST == 1) |
| ble_hw_whitelist_clear(); |
| #endif |
| |
| return BLE_ERR_SUCCESS; |
| } |
| |
| /** |
| * Read the size of the whitelist. This is the total number of whitelist |
| * entries allowed by the controller. |
| * |
| * @param rspbuf Pointer to response buffer |
| * |
| * @return int 0: success. |
| */ |
| int |
| ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen) |
| { |
| rspbuf[0] = BLE_LL_WHITELIST_SIZE; |
| *rsplen = 1; |
| return BLE_ERR_SUCCESS; |
| } |
| |
| /** |
| * Searches the whitelist to determine if the address is present in the |
| * whitelist. This is an internal API that only searches the link layer |
| * whitelist and does not care about the hardware whitelist |
| * |
| * @param addr Device or identity address to check. |
| * @param addr_type Public address (0) or random address (1) |
| * |
| * @return int 0: device is not on whitelist; otherwise the return value |
| * is the 'position' of the device in the whitelist (the index of the element |
| * plus 1). |
| */ |
| static int |
| ble_ll_whitelist_search(uint8_t *addr, uint8_t addr_type) |
| { |
| int i; |
| struct ble_ll_whitelist_entry *wl; |
| |
| wl = &g_ble_ll_whitelist[0]; |
| for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) { |
| if ((wl->wl_valid) && (wl->wl_addr_type == addr_type) && |
| (!memcmp(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN))) { |
| return i + 1; |
| } |
| ++wl; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * Is there a match between the device and a device on the whitelist. |
| * |
| * NOTE: This API uses the HW, if present, to determine if there was a match |
| * between a received address and an address in the whitelist. If the HW does |
| * not support whitelisting this API is the same as the whitelist search API |
| * |
| * @param addr |
| * @param addr_type Public address (0) or random address (1) |
| * @param is_ident True if addr is an identity address; false otherwise |
| * |
| * @return int |
| */ |
| int |
| ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident) |
| { |
| int rc; |
| #if (BLE_USES_HW_WHITELIST == 1) |
| /* |
| * XXX: This should be changed. This is HW specific: some HW may be able |
| * to both resolve a private address and perform a whitelist check. The |
| * current BLE hw cannot support this. |
| */ |
| if (is_ident) { |
| rc = ble_ll_whitelist_search(addr, addr_type); |
| } else { |
| rc = ble_hw_whitelist_match(); |
| } |
| #else |
| rc = ble_ll_whitelist_search(addr, addr_type); |
| #endif |
| return rc; |
| } |
| |
| /** |
| * Add a device to the whitelist |
| * |
| * @return int |
| */ |
| int |
| ble_ll_whitelist_add(uint8_t *addr, uint8_t addr_type) |
| { |
| int i; |
| int rc; |
| struct ble_ll_whitelist_entry *wl; |
| |
| /* Must be in proper state */ |
| if (!ble_ll_whitelist_chg_allowed()) { |
| return BLE_ERR_CMD_DISALLOWED; |
| } |
| |
| /* Check if we have any open entries */ |
| rc = BLE_ERR_SUCCESS; |
| if (!ble_ll_whitelist_search(addr, addr_type)) { |
| wl = &g_ble_ll_whitelist[0]; |
| for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) { |
| if (wl->wl_valid == 0) { |
| memcpy(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN); |
| wl->wl_addr_type = addr_type; |
| wl->wl_valid = 1; |
| break; |
| } |
| ++wl; |
| } |
| |
| if (i == BLE_LL_WHITELIST_SIZE) { |
| rc = BLE_ERR_MEM_CAPACITY; |
| } else { |
| #if (BLE_USES_HW_WHITELIST == 1) |
| rc = ble_hw_whitelist_add(addr, addr_type); |
| #endif |
| } |
| } |
| |
| return rc; |
| } |
| |
| /** |
| * Remove a device from the whitelist |
| * |
| * @param cmdbuf |
| * |
| * @return int 0: success, BLE error code otherwise |
| */ |
| int |
| ble_ll_whitelist_rmv(uint8_t *addr, uint8_t addr_type) |
| { |
| int position; |
| |
| /* Must be in proper state */ |
| if (!ble_ll_whitelist_chg_allowed()) { |
| return BLE_ERR_CMD_DISALLOWED; |
| } |
| |
| position = ble_ll_whitelist_search(addr, addr_type); |
| if (position) { |
| g_ble_ll_whitelist[position - 1].wl_valid = 0; |
| } |
| |
| #if (BLE_USES_HW_WHITELIST == 1) |
| ble_hw_whitelist_rmv(addr, addr_type); |
| #endif |
| |
| return BLE_ERR_SUCCESS; |
| } |
| |
| /** |
| * Enable whitelisting. |
| * |
| * Note: This function has no effect if we are not using HW whitelisting |
| */ |
| void |
| ble_ll_whitelist_enable(void) |
| { |
| #if (BLE_USES_HW_WHITELIST == 1) |
| ble_hw_whitelist_enable(); |
| #endif |
| } |
| |
| /** |
| * Disable whitelisting. |
| * |
| * Note: This function has no effect if we are not using HW whitelisting |
| */ |
| void |
| ble_ll_whitelist_disable(void) |
| { |
| #if (BLE_USES_HW_WHITELIST == 1) |
| ble_hw_whitelist_disable(); |
| #endif |
| } |