| /* |
| * 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 "host/ble_store.h" |
| #include "ble_hs_priv.h" |
| |
| struct ble_store_util_peer_set { |
| ble_addr_t *peer_id_addrs; |
| int num_peers; |
| int max_peers; |
| int status; |
| }; |
| |
| static int |
| ble_store_util_iter_unique_peer(int obj_type, |
| union ble_store_value *val, |
| void *arg) |
| { |
| struct ble_store_util_peer_set *set; |
| int i; |
| |
| BLE_HS_DBG_ASSERT(obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC || |
| obj_type == BLE_STORE_OBJ_TYPE_PEER_SEC); |
| |
| set = arg; |
| |
| /* Do nothing if this peer is a duplicate. */ |
| for (i = 0; i < set->num_peers; i++) { |
| if (ble_addr_cmp(set->peer_id_addrs + i, &val->sec.peer_addr) == 0) { |
| return 0; |
| } |
| } |
| |
| if (set->num_peers >= set->max_peers) { |
| /* Overflow; abort the iterate procedure. */ |
| set->status = BLE_HS_ENOMEM; |
| return 1; |
| } |
| |
| set->peer_id_addrs[set->num_peers] = val->sec.peer_addr; |
| set->num_peers++; |
| |
| return 0; |
| } |
| |
| /** |
| * Retrieves the set of peer addresses for which a bond has been established. |
| * |
| * @param out_peer_id_addrs On success, the set of bonded peer addresses |
| * gets written here. |
| * @param out_num_peers On success, the number of bonds gets written |
| * here. |
| * @param max_peers The capacity of the destination buffer. |
| * |
| * @return 0 on success; |
| * BLE_HS_ENOMEM if the destination buffer is too |
| * small; |
| * Other nonzero on error. |
| */ |
| int |
| ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers, |
| int max_peers) |
| { |
| struct ble_store_util_peer_set set = { |
| .peer_id_addrs = out_peer_id_addrs, |
| .num_peers = 0, |
| .max_peers = max_peers, |
| .status = 0, |
| }; |
| int rc; |
| |
| rc = ble_store_iterate(BLE_STORE_OBJ_TYPE_OUR_SEC, |
| ble_store_util_iter_unique_peer, |
| &set); |
| if (rc != 0) { |
| return rc; |
| } |
| if (set.status != 0) { |
| return set.status; |
| } |
| |
| *out_num_peers = set.num_peers; |
| return 0; |
| } |
| |
| /** |
| * Deletes all entries from the store that are attached to the specified peer |
| * address. This function deletes security entries and CCCD records. |
| * |
| * @param peer_id_addr Entries with this peer address get deleted. |
| * |
| * @return 0 on success; |
| * Other nonzero on error. |
| */ |
| int |
| ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) |
| { |
| union ble_store_key key; |
| int rc; |
| |
| memset(&key, 0, sizeof key); |
| key.sec.peer_addr = *peer_id_addr; |
| |
| rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_OUR_SEC, &key); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_PEER_SEC, &key); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| memset(&key, 0, sizeof key); |
| key.cccd.peer_addr = *peer_id_addr; |
| |
| rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_CCCD, &key); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * Deletes all entries from the store that match the specified key. |
| * |
| * @param type The type of store entry to delete. |
| * @param key Entries matching this key get deleted. |
| * |
| * @return 0 on success; |
| * Other nonzero on error. |
| */ |
| int |
| ble_store_util_delete_all(int type, const union ble_store_key *key) |
| { |
| int rc; |
| |
| do { |
| rc = ble_store_delete(type, key); |
| } while (rc == 0); |
| |
| if (rc != BLE_HS_ENOENT) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| ble_store_util_iter_count(int obj_type, |
| union ble_store_value *val, |
| void *arg) |
| { |
| int *count; |
| |
| count = arg; |
| (*count)++; |
| |
| return 0; |
| } |
| |
| int |
| ble_store_util_count(int type, int *out_count) |
| { |
| int rc; |
| |
| *out_count = 0; |
| rc = ble_store_iterate(type, |
| ble_store_util_iter_count, |
| out_count); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| int |
| ble_store_util_delete_oldest_peer(void) |
| { |
| ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; |
| int num_peers; |
| int rc; |
| |
| rc = ble_store_util_bonded_peers( |
| peer_id_addrs, &num_peers, |
| sizeof peer_id_addrs / sizeof peer_id_addrs[0]); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| if (num_peers == 0) { |
| return 0; |
| } |
| |
| rc = ble_store_util_delete_peer(&peer_id_addrs[0]); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * Round-robin status callback. If a there is insufficient storage capacity |
| * for a new record, delete the oldest bond and proceed with the persist |
| * operation. |
| * |
| * Note: This is not the best behavior for an actual product because |
| * uninteresting peers could cause important bonds to be deleted. This is |
| * useful for demonstrations and sample apps. |
| */ |
| int |
| ble_store_util_status_rr(struct ble_store_status_event *event, void *arg) |
| { |
| switch (event->event_code) { |
| case BLE_STORE_EVENT_OVERFLOW: |
| switch (event->overflow.obj_type) { |
| case BLE_STORE_OBJ_TYPE_OUR_SEC: |
| case BLE_STORE_OBJ_TYPE_PEER_SEC: |
| case BLE_STORE_OBJ_TYPE_CCCD: |
| return ble_gap_unpair_oldest_peer(); |
| |
| default: |
| return BLE_HS_EUNKNOWN; |
| } |
| |
| case BLE_STORE_EVENT_FULL: |
| /* Just proceed with the operation. If it results in an overflow, |
| * we'll delete a record when the overflow occurs. |
| */ |
| return 0; |
| |
| default: |
| return BLE_HS_EUNKNOWN; |
| } |
| } |