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
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
30 static int
ble_store_util_iter_unique_peer(int obj_type,union ble_store_value * val,void * arg)31 ble_store_util_iter_unique_peer(int obj_type,
32 union ble_store_value *val,
33 void *arg)
34 {
35 struct ble_store_util_peer_set *set;
36 int i;
37
38 BLE_HS_DBG_ASSERT(obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC ||
39 obj_type == BLE_STORE_OBJ_TYPE_PEER_SEC);
40
41 set = arg;
42
43 /* Do nothing if this peer is a duplicate. */
44 for (i = 0; i < set->num_peers; i++) {
45 if (ble_addr_cmp(set->peer_id_addrs + i, &val->sec.peer_addr) == 0) {
46 return 0;
47 }
48 }
49
50 if (set->num_peers >= set->max_peers) {
51 /* Overflow; abort the iterate procedure. */
52 set->status = BLE_HS_ENOMEM;
53 return 1;
54 }
55
56 set->peer_id_addrs[set->num_peers] = val->sec.peer_addr;
57 set->num_peers++;
58
59 return 0;
60 }
61
62 /**
63 * Retrieves the set of peer addresses for which a bond has been established.
64 *
65 * @param out_peer_id_addrs On success, the set of bonded peer addresses
66 * gets written here.
67 * @param out_num_peers On success, the number of bonds gets written
68 * here.
69 * @param max_peers The capacity of the destination buffer.
70 *
71 * @return 0 on success;
72 * BLE_HS_ENOMEM if the destination buffer is too
73 * small;
74 * Other nonzero on error.
75 */
76 int
ble_store_util_bonded_peers(ble_addr_t * out_peer_id_addrs,int * out_num_peers,int max_peers)77 ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers,
78 int max_peers)
79 {
80 struct ble_store_util_peer_set set = {
81 .peer_id_addrs = out_peer_id_addrs,
82 .num_peers = 0,
83 .max_peers = max_peers,
84 .status = 0,
85 };
86 int rc;
87
88 rc = ble_store_iterate(BLE_STORE_OBJ_TYPE_OUR_SEC,
89 ble_store_util_iter_unique_peer,
90 &set);
91 if (rc != 0) {
92 return rc;
93 }
94 if (set.status != 0) {
95 return set.status;
96 }
97
98 *out_num_peers = set.num_peers;
99 return 0;
100 }
101
102 /**
103 * Deletes all entries from the store that are attached to the specified peer
104 * address. This function deletes security entries and CCCD records.
105 *
106 * @param peer_id_addr Entries with this peer address get deleted.
107 *
108 * @return 0 on success;
109 * Other nonzero on error.
110 */
111 int
ble_store_util_delete_peer(const ble_addr_t * peer_id_addr)112 ble_store_util_delete_peer(const ble_addr_t *peer_id_addr)
113 {
114 union ble_store_key key;
115 int rc;
116
117 memset(&key, 0, sizeof key);
118 key.sec.peer_addr = *peer_id_addr;
119
120 rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_OUR_SEC, &key);
121 if (rc != 0) {
122 return rc;
123 }
124
125 rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_PEER_SEC, &key);
126 if (rc != 0) {
127 return rc;
128 }
129
130 memset(&key, 0, sizeof key);
131 key.cccd.peer_addr = *peer_id_addr;
132
133 rc = ble_store_util_delete_all(BLE_STORE_OBJ_TYPE_CCCD, &key);
134 if (rc != 0) {
135 return rc;
136 }
137
138 return 0;
139 }
140
141 /**
142 * Deletes all entries from the store that match the specified key.
143 *
144 * @param type The type of store entry to delete.
145 * @param key Entries matching this key get deleted.
146 *
147 * @return 0 on success;
148 * Other nonzero on error.
149 */
150 int
ble_store_util_delete_all(int type,const union ble_store_key * key)151 ble_store_util_delete_all(int type, const union ble_store_key *key)
152 {
153 int rc;
154
155 do {
156 rc = ble_store_delete(type, key);
157 } while (rc == 0);
158
159 if (rc != BLE_HS_ENOENT) {
160 return rc;
161 }
162
163 return 0;
164 }
165
166 static int
ble_store_util_iter_count(int obj_type,union ble_store_value * val,void * arg)167 ble_store_util_iter_count(int obj_type,
168 union ble_store_value *val,
169 void *arg)
170 {
171 int *count;
172
173 count = arg;
174 (*count)++;
175
176 return 0;
177 }
178
179 int
ble_store_util_count(int type,int * out_count)180 ble_store_util_count(int type, int *out_count)
181 {
182 int rc;
183
184 *out_count = 0;
185 rc = ble_store_iterate(type,
186 ble_store_util_iter_count,
187 out_count);
188 if (rc != 0) {
189 return rc;
190 }
191
192 return 0;
193 }
194
195 int
ble_store_util_delete_oldest_peer(void)196 ble_store_util_delete_oldest_peer(void)
197 {
198 ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
199 int num_peers;
200 int rc;
201
202 rc = ble_store_util_bonded_peers(
203 peer_id_addrs, &num_peers,
204 sizeof peer_id_addrs / sizeof peer_id_addrs[0]);
205 if (rc != 0) {
206 return rc;
207 }
208
209 if (num_peers == 0) {
210 return 0;
211 }
212
213 rc = ble_store_util_delete_peer(&peer_id_addrs[0]);
214 if (rc != 0) {
215 return rc;
216 }
217
218 return 0;
219 }
220
221 /**
222 * Round-robin status callback. If a there is insufficient storage capacity
223 * for a new record, delete the oldest bond and proceed with the persist
224 * operation.
225 *
226 * Note: This is not the best behavior for an actual product because
227 * uninteresting peers could cause important bonds to be deleted. This is
228 * useful for demonstrations and sample apps.
229 */
230 int
ble_store_util_status_rr(struct ble_store_status_event * event,void * arg)231 ble_store_util_status_rr(struct ble_store_status_event *event, void *arg)
232 {
233 switch (event->event_code) {
234 case BLE_STORE_EVENT_OVERFLOW:
235 switch (event->overflow.obj_type) {
236 case BLE_STORE_OBJ_TYPE_OUR_SEC:
237 case BLE_STORE_OBJ_TYPE_PEER_SEC:
238 case BLE_STORE_OBJ_TYPE_CCCD:
239 return ble_gap_unpair_oldest_peer();
240
241 default:
242 return BLE_HS_EUNKNOWN;
243 }
244
245 case BLE_STORE_EVENT_FULL:
246 /* Just proceed with the operation. If it results in an overflow,
247 * we'll delete a record when the overflow occurs.
248 */
249 return 0;
250
251 default:
252 return BLE_HS_EUNKNOWN;
253 }
254 }
255