1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 #include "securec.h"
20 #include "host/ble_store.h"
21 #include "ble_hs_priv.h"
22
23 struct ble_store_util_peer_set {
24 ble_addr_t *peer_id_addrs;
25 int num_peers;
26 int max_peers;
27 int status;
28 };
29
ble_store_util_iter_unique_peer(int obj_type,union ble_store_value * val,void * arg)30 static int ble_store_util_iter_unique_peer(int obj_type,
31 union ble_store_value *val,
32 void *arg)
33 {
34 struct ble_store_util_peer_set *set;
35 int i;
36 BLE_HS_DBG_ASSERT(obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC ||
37 obj_type == BLE_STORE_OBJ_TYPE_PEER_SEC);
38 set = arg;
39
40 /* Do nothing if this peer is a duplicate. */
41 for (i = 0; i < set->num_peers; i++) {
42 if (ble_addr_cmp(set->peer_id_addrs + i, &val->sec.peer_addr) == 0) {
43 return 0;
44 }
45 }
46
47 if (set->num_peers >= set->max_peers) {
48 /* Overflow; abort the iterate procedure. */
49 set->status = BLE_HS_ENOMEM;
50 return 1;
51 }
52
53 set->peer_id_addrs[set->num_peers] = val->sec.peer_addr;
54 set->num_peers++;
55 return 0;
56 }
57
58 /**
59 * Retrieves the set of peer addresses for which a bond has been established.
60 *
61 * @param out_peer_id_addrs On success, the set of bonded peer addresses
62 * gets written here.
63 * @param out_num_peers On success, the number of bonds gets written
64 * here.
65 * @param max_peers The capacity of the destination buffer.
66 *
67 * @return 0 on success;
68 * BLE_HS_ENOMEM if the destination buffer is too
69 * small;
70 * Other nonzero on error.
71 */
ble_store_util_bonded_peers(ble_addr_t * out_peer_id_addrs,int * out_num_peers,int max_peers)72 int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers, int max_peers)
73 {
74 struct ble_store_util_peer_set set = {
75 .peer_id_addrs = out_peer_id_addrs,
76 .num_peers = 0,
77 .max_peers = max_peers,
78 .status = 0,
79 };
80 int rc;
81 rc = ble_store_iterate(BLE_STORE_OBJ_TYPE_OUR_SEC,
82 ble_store_util_iter_unique_peer,
83 &set);
84 if (rc != 0) {
85 return rc;
86 }
87
88 if (set.status != 0) {
89 return set.status;
90 }
91
92 *out_num_peers = set.num_peers;
93 return 0;
94 }
95
96 /**
97 * Deletes all entries from the store that are attached to the specified peer
98 * address. This function deletes security entries and CCCD records.
99 *
100 * @param peer_id_addr Entries with this peer address get deleted.
101 *
102 * @return 0 on success;
103 * Other nonzero on error.
104 */
ble_store_util_delete_peer(const ble_addr_t * peer_id_addr)105 int ble_store_util_delete_peer(const ble_addr_t *peer_id_addr)
106 {
107 union ble_store_key key;
108 int rc;
109 memset_s(&key, sizeof(key), 0, sizeof key);
110 key.sec.peer_addr = *peer_id_addr;
111 rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_OUR_SEC, &key);
112 if (rc != 0) {
113 return rc;
114 }
115
116 rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_PEER_SEC, &key);
117 if (rc != 0) {
118 return rc;
119 }
120
121 memset_s(&key, sizeof(key), 0, sizeof key);
122 key.cccd.peer_addr = *peer_id_addr;
123 rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_CCCD, &key);
124 if (rc != 0) {
125 return rc;
126 }
127
128 rc = ble_store_flush();
129 if (!rc) {
130 return rc;
131 }
132
133 return 0;
134 }
135
136 /**
137 * Deletes all entries from the store that match the specified key.
138 *
139 * @param type The type of store entry to delete.
140 * @param key Entries matching this key get deleted.
141 *
142 * @return 0 on success;
143 * Other nonzero on error.
144 */
ble_store_util_delete_all(int type,const union ble_store_key * key)145 int ble_store_util_delete_all(int type, const union ble_store_key *key)
146 {
147 int rc;
148
149 do {
150 rc = ble_store_delete(type, key);
151 } while (rc == 0);
152
153 if (rc != BLE_HS_ENOENT) {
154 return rc;
155 }
156
157 return 0;
158 }
159
ble_store_util_iter_count(int obj_type,union ble_store_value * val,void * arg)160 static int ble_store_util_iter_count(int obj_type,
161 union ble_store_value *val,
162 void *arg)
163 {
164 int *count;
165 count = arg;
166 (*count)++;
167 return 0;
168 }
169
ble_store_util_count(int type,int * out_count)170 int ble_store_util_count(int type, int *out_count)
171 {
172 int rc;
173 *out_count = 0;
174 rc = ble_store_iterate(type,
175 ble_store_util_iter_count,
176 out_count);
177 if (rc != 0) {
178 return rc;
179 }
180
181 return 0;
182 }
183
ble_store_util_get_peer_by_index(int index,ble_addr_t * peer_id_addr)184 int ble_store_util_get_peer_by_index(int index, ble_addr_t *peer_id_addr)
185 {
186 ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
187 int num_peers;
188 int rc;
189 rc = ble_store_util_bonded_peers(peer_id_addrs, &num_peers,
190 sizeof peer_id_addrs / sizeof peer_id_addrs[0]);
191 if (rc != 0) {
192 return rc;
193 }
194
195 if (index > num_peers) {
196 return -1;
197 }
198
199 memcpy_s(peer_id_addr, sizeof(*peer_id_addr), &peer_id_addrs[index], sizeof(ble_addr_t));
200 return rc;
201 }
202
ble_store_util_delete_oldest_peer(ble_addr_t * peer_id_addr)203 int ble_store_util_delete_oldest_peer(ble_addr_t *peer_id_addr)
204 {
205 ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
206 int num_peers;
207 int rc;
208 rc = ble_store_util_bonded_peers(peer_id_addrs, &num_peers,
209 sizeof peer_id_addrs / sizeof peer_id_addrs[0]);
210 if (rc != 0) {
211 return rc;
212 }
213
214 if (num_peers == 0) {
215 return 0;
216 }
217
218 rc = ble_store_util_delete_peer(&peer_id_addrs[0]);
219 if (rc != 0) {
220 return rc;
221 }
222 if (peer_id_addr) {
223 memcpy_s(peer_id_addr, sizeof(*peer_id_addr), &peer_id_addrs[0], sizeof(ble_addr_t));
224 }
225 return 0;
226 }
227
228 /**
229 * Round-robin status callback. If a there is insufficient storage capacity
230 * for a new record, delete the oldest bond and proceed with the persist
231 * operation.
232 *
233 * Note: This is not the best behavior for an actual product because
234 * uninteresting peers could cause important bonds to be deleted. This is
235 * useful for demonstrations and sample apps.
236 */
ble_store_util_status_rr(struct ble_store_status_event * event,void * arg)237 int ble_store_util_status_rr(struct ble_store_status_event *event, void *arg)
238 {
239 switch (event->event_code) {
240 case BLE_STORE_EVENT_OVERFLOW:
241 switch (event->overflow.obj_type) {
242 case BLE_STORE_OBJ_TYPE_OUR_SEC:
243 case BLE_STORE_OBJ_TYPE_PEER_SEC:
244 case BLE_STORE_OBJ_TYPE_CCCD:
245 return ble_gap_unpair_oldest_peer();
246
247 default:
248 return BLE_HS_EUNKNOWN;
249 }
250
251 case BLE_STORE_EVENT_FULL:
252 /* Just proceed with the operation. If it results in an overflow,
253 * we'll delete a record when the overflow occurs.
254 */
255 return 0;
256
257 default:
258 return BLE_HS_EUNKNOWN;
259 }
260 }