• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }