xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_hs_adv.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero 
20*042d53a7SEvalZero #include <string.h>
21*042d53a7SEvalZero #include <errno.h>
22*042d53a7SEvalZero #include "nimble/ble.h"
23*042d53a7SEvalZero #include "host/ble_hs_adv.h"
24*042d53a7SEvalZero #include "ble_hs_priv.h"
25*042d53a7SEvalZero 
26*042d53a7SEvalZero struct find_field_data {
27*042d53a7SEvalZero     uint8_t type;
28*042d53a7SEvalZero     const struct ble_hs_adv_field *field;
29*042d53a7SEvalZero };
30*042d53a7SEvalZero 
31*042d53a7SEvalZero static ble_uuid16_t ble_hs_adv_uuids16[BLE_HS_ADV_MAX_FIELD_SZ / 2];
32*042d53a7SEvalZero static ble_uuid32_t ble_hs_adv_uuids32[BLE_HS_ADV_MAX_FIELD_SZ / 4];
33*042d53a7SEvalZero static ble_uuid128_t ble_hs_adv_uuids128[BLE_HS_ADV_MAX_FIELD_SZ / 16];
34*042d53a7SEvalZero 
35*042d53a7SEvalZero static int
ble_hs_adv_set_hdr(uint8_t type,uint8_t data_len,uint8_t max_len,uint8_t * dst,uint8_t * dst_len,struct os_mbuf * om)36*042d53a7SEvalZero ble_hs_adv_set_hdr(uint8_t type, uint8_t data_len, uint8_t max_len,
37*042d53a7SEvalZero                    uint8_t *dst, uint8_t *dst_len, struct os_mbuf *om)
38*042d53a7SEvalZero {
39*042d53a7SEvalZero     int rc;
40*042d53a7SEvalZero 
41*042d53a7SEvalZero     if (om ) {
42*042d53a7SEvalZero         data_len++;
43*042d53a7SEvalZero         rc = os_mbuf_append(om, &data_len, sizeof(data_len));
44*042d53a7SEvalZero         if (rc) {
45*042d53a7SEvalZero             return rc;
46*042d53a7SEvalZero         }
47*042d53a7SEvalZero 
48*042d53a7SEvalZero         return os_mbuf_append(om, &type, sizeof(type));
49*042d53a7SEvalZero     }
50*042d53a7SEvalZero 
51*042d53a7SEvalZero 
52*042d53a7SEvalZero     if (*dst_len + 2 + data_len > max_len) {
53*042d53a7SEvalZero         return BLE_HS_EMSGSIZE;
54*042d53a7SEvalZero     }
55*042d53a7SEvalZero 
56*042d53a7SEvalZero     dst[*dst_len] = data_len + 1;
57*042d53a7SEvalZero     dst[*dst_len + 1] = type;
58*042d53a7SEvalZero 
59*042d53a7SEvalZero     *dst_len += 2;
60*042d53a7SEvalZero 
61*042d53a7SEvalZero     return 0;
62*042d53a7SEvalZero }
63*042d53a7SEvalZero 
64*042d53a7SEvalZero static int
ble_hs_adv_set_flat_mbuf(uint8_t type,int data_len,const void * data,uint8_t * dst,uint8_t * dst_len,uint8_t max_len,struct os_mbuf * om)65*042d53a7SEvalZero ble_hs_adv_set_flat_mbuf(uint8_t type, int data_len, const void *data,
66*042d53a7SEvalZero                     uint8_t *dst, uint8_t *dst_len, uint8_t max_len,
67*042d53a7SEvalZero                     struct os_mbuf *om)
68*042d53a7SEvalZero {
69*042d53a7SEvalZero     int rc;
70*042d53a7SEvalZero 
71*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(data_len > 0);
72*042d53a7SEvalZero 
73*042d53a7SEvalZero     rc = ble_hs_adv_set_hdr(type, data_len, max_len, dst, dst_len, om);
74*042d53a7SEvalZero     if (rc != 0) {
75*042d53a7SEvalZero         return rc;
76*042d53a7SEvalZero     }
77*042d53a7SEvalZero 
78*042d53a7SEvalZero     if (om) {
79*042d53a7SEvalZero         return os_mbuf_append(om, data, data_len);
80*042d53a7SEvalZero     }
81*042d53a7SEvalZero 
82*042d53a7SEvalZero     memcpy(dst + *dst_len, data, data_len);
83*042d53a7SEvalZero     *dst_len += data_len;
84*042d53a7SEvalZero 
85*042d53a7SEvalZero     return 0;
86*042d53a7SEvalZero }
87*042d53a7SEvalZero 
88*042d53a7SEvalZero int
ble_hs_adv_set_flat(uint8_t type,int data_len,const void * data,uint8_t * dst,uint8_t * dst_len,uint8_t max_len)89*042d53a7SEvalZero ble_hs_adv_set_flat(uint8_t type, int data_len, const void *data,
90*042d53a7SEvalZero                     uint8_t *dst, uint8_t *dst_len, uint8_t max_len)
91*042d53a7SEvalZero {
92*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE
93*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
94*042d53a7SEvalZero #endif
95*042d53a7SEvalZero 
96*042d53a7SEvalZero     return ble_hs_adv_set_flat_mbuf(type, data_len, data, dst, dst_len, max_len,
97*042d53a7SEvalZero                                     NULL);
98*042d53a7SEvalZero }
99*042d53a7SEvalZero 
100*042d53a7SEvalZero static int
ble_hs_adv_set_array_uuid16(uint8_t type,uint8_t num_elems,const ble_uuid16_t * elems,uint8_t * dst,uint8_t * dst_len,uint8_t max_len,struct os_mbuf * om)101*042d53a7SEvalZero ble_hs_adv_set_array_uuid16(uint8_t type, uint8_t num_elems,
102*042d53a7SEvalZero                             const ble_uuid16_t *elems, uint8_t *dst,
103*042d53a7SEvalZero                             uint8_t *dst_len, uint8_t max_len,
104*042d53a7SEvalZero                             struct os_mbuf *om)
105*042d53a7SEvalZero {
106*042d53a7SEvalZero     int rc;
107*042d53a7SEvalZero     int i;
108*042d53a7SEvalZero 
109*042d53a7SEvalZero     rc = ble_hs_adv_set_hdr(type, num_elems * 2, max_len, dst,
110*042d53a7SEvalZero                             dst_len, om);
111*042d53a7SEvalZero     if (rc != 0) {
112*042d53a7SEvalZero         return rc;
113*042d53a7SEvalZero     }
114*042d53a7SEvalZero 
115*042d53a7SEvalZero     for (i = 0; i < num_elems; i++) {
116*042d53a7SEvalZero         if (om) {
117*042d53a7SEvalZero             rc = ble_uuid_to_mbuf(&elems[i].u, om);
118*042d53a7SEvalZero             if (rc) {
119*042d53a7SEvalZero                 return rc;
120*042d53a7SEvalZero             }
121*042d53a7SEvalZero         } else {
122*042d53a7SEvalZero             ble_uuid_flat(&elems[i].u, dst + *dst_len);
123*042d53a7SEvalZero             *dst_len += 2;
124*042d53a7SEvalZero         }
125*042d53a7SEvalZero     }
126*042d53a7SEvalZero 
127*042d53a7SEvalZero     return 0;
128*042d53a7SEvalZero }
129*042d53a7SEvalZero 
130*042d53a7SEvalZero static int
ble_hs_adv_set_array_uuid32(uint8_t type,uint8_t num_elems,const ble_uuid32_t * elems,uint8_t * dst,uint8_t * dst_len,uint8_t max_len,struct os_mbuf * om)131*042d53a7SEvalZero ble_hs_adv_set_array_uuid32(uint8_t type, uint8_t num_elems,
132*042d53a7SEvalZero                             const ble_uuid32_t *elems, uint8_t *dst,
133*042d53a7SEvalZero                             uint8_t *dst_len, uint8_t max_len,
134*042d53a7SEvalZero                             struct os_mbuf *om)
135*042d53a7SEvalZero {
136*042d53a7SEvalZero     uint32_t uuid_le;
137*042d53a7SEvalZero     int rc;
138*042d53a7SEvalZero     int i;
139*042d53a7SEvalZero 
140*042d53a7SEvalZero     rc = ble_hs_adv_set_hdr(type, num_elems * 4, max_len, dst,
141*042d53a7SEvalZero                             dst_len, om);
142*042d53a7SEvalZero     if (rc != 0) {
143*042d53a7SEvalZero         return rc;
144*042d53a7SEvalZero     }
145*042d53a7SEvalZero 
146*042d53a7SEvalZero     for (i = 0; i < num_elems; i++) {
147*042d53a7SEvalZero         /* We cannot use ble_uuid_flat here since it converts 32-bit UUIDs to
148*042d53a7SEvalZero          * 128-bit as ATT requires. In AD, 32-bit UUID shall be written as an
149*042d53a7SEvalZero          * actual 32-bit value.
150*042d53a7SEvalZero          */
151*042d53a7SEvalZero         if (om) {
152*042d53a7SEvalZero             uuid_le = htole32(elems[i].value);
153*042d53a7SEvalZero             rc = os_mbuf_append(om, &uuid_le, sizeof(uuid_le));
154*042d53a7SEvalZero             if (rc) {
155*042d53a7SEvalZero                 return rc;
156*042d53a7SEvalZero             }
157*042d53a7SEvalZero         } else {
158*042d53a7SEvalZero             put_le32(dst + *dst_len, elems[i].value);
159*042d53a7SEvalZero             *dst_len += 4;
160*042d53a7SEvalZero         }
161*042d53a7SEvalZero     }
162*042d53a7SEvalZero 
163*042d53a7SEvalZero     return 0;
164*042d53a7SEvalZero }
165*042d53a7SEvalZero 
166*042d53a7SEvalZero static int
ble_hs_adv_set_array_uuid128(uint8_t type,uint8_t num_elems,const ble_uuid128_t * elems,uint8_t * dst,uint8_t * dst_len,uint8_t max_len,struct os_mbuf * om)167*042d53a7SEvalZero ble_hs_adv_set_array_uuid128(uint8_t type, uint8_t num_elems,
168*042d53a7SEvalZero                              const ble_uuid128_t *elems, uint8_t *dst,
169*042d53a7SEvalZero                              uint8_t *dst_len, uint8_t max_len,
170*042d53a7SEvalZero                              struct os_mbuf *om)
171*042d53a7SEvalZero {
172*042d53a7SEvalZero     int rc;
173*042d53a7SEvalZero     int i;
174*042d53a7SEvalZero 
175*042d53a7SEvalZero     rc = ble_hs_adv_set_hdr(type, num_elems * 16, max_len, dst,
176*042d53a7SEvalZero                             dst_len, om);
177*042d53a7SEvalZero     if (rc != 0) {
178*042d53a7SEvalZero         return rc;
179*042d53a7SEvalZero     }
180*042d53a7SEvalZero 
181*042d53a7SEvalZero     for (i = 0; i < num_elems; i++) {
182*042d53a7SEvalZero         if (om) {
183*042d53a7SEvalZero             rc = ble_uuid_to_mbuf(&elems[i].u, om);
184*042d53a7SEvalZero             if (rc) {
185*042d53a7SEvalZero                 return rc;
186*042d53a7SEvalZero             }
187*042d53a7SEvalZero         } else {
188*042d53a7SEvalZero             ble_uuid_flat(&elems[i].u, dst + *dst_len);
189*042d53a7SEvalZero             *dst_len += 16;
190*042d53a7SEvalZero         }
191*042d53a7SEvalZero     }
192*042d53a7SEvalZero 
193*042d53a7SEvalZero     return 0;
194*042d53a7SEvalZero }
195*042d53a7SEvalZero 
196*042d53a7SEvalZero static int
ble_hs_adv_set_array16(uint8_t type,uint8_t num_elems,const uint16_t * elems,uint8_t * dst,uint8_t * dst_len,uint8_t max_len,struct os_mbuf * om)197*042d53a7SEvalZero ble_hs_adv_set_array16(uint8_t type, uint8_t num_elems, const uint16_t *elems,
198*042d53a7SEvalZero                        uint8_t *dst, uint8_t *dst_len, uint8_t max_len,
199*042d53a7SEvalZero                        struct os_mbuf *om)
200*042d53a7SEvalZero {
201*042d53a7SEvalZero     uint16_t tmp;
202*042d53a7SEvalZero     int rc;
203*042d53a7SEvalZero     int i;
204*042d53a7SEvalZero 
205*042d53a7SEvalZero     rc = ble_hs_adv_set_hdr(type, num_elems * sizeof *elems, max_len, dst,
206*042d53a7SEvalZero                             dst_len, om);
207*042d53a7SEvalZero     if (rc != 0) {
208*042d53a7SEvalZero         return rc;
209*042d53a7SEvalZero     }
210*042d53a7SEvalZero 
211*042d53a7SEvalZero     for (i = 0; i < num_elems; i++) {
212*042d53a7SEvalZero         if (om) {
213*042d53a7SEvalZero             tmp = htole16(elems[i]);
214*042d53a7SEvalZero             rc = os_mbuf_append(om, &tmp, sizeof(tmp));
215*042d53a7SEvalZero             if (rc) {
216*042d53a7SEvalZero                 return rc;
217*042d53a7SEvalZero             }
218*042d53a7SEvalZero         } else {
219*042d53a7SEvalZero             put_le16(dst + *dst_len, elems[i]);
220*042d53a7SEvalZero             *dst_len += sizeof elems[i];
221*042d53a7SEvalZero         }
222*042d53a7SEvalZero     }
223*042d53a7SEvalZero 
224*042d53a7SEvalZero     return 0;
225*042d53a7SEvalZero }
226*042d53a7SEvalZero 
227*042d53a7SEvalZero static int
adv_set_fields(const struct ble_hs_adv_fields * adv_fields,uint8_t * dst,uint8_t * dst_len,uint8_t max_len,struct os_mbuf * om)228*042d53a7SEvalZero adv_set_fields(const struct ble_hs_adv_fields *adv_fields,
229*042d53a7SEvalZero                       uint8_t *dst, uint8_t *dst_len, uint8_t max_len,
230*042d53a7SEvalZero                       struct os_mbuf *om)
231*042d53a7SEvalZero {
232*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE
233*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
234*042d53a7SEvalZero #endif
235*042d53a7SEvalZero 
236*042d53a7SEvalZero     uint8_t type;
237*042d53a7SEvalZero     int8_t tx_pwr_lvl;
238*042d53a7SEvalZero     int rc;
239*042d53a7SEvalZero 
240*042d53a7SEvalZero     if (dst_len) {
241*042d53a7SEvalZero         *dst_len = 0;
242*042d53a7SEvalZero     }
243*042d53a7SEvalZero 
244*042d53a7SEvalZero     /*** 0x01 - Flags. */
245*042d53a7SEvalZero     /* The application has two options concerning the flags field:
246*042d53a7SEvalZero      * 1. Don't include it in advertisements (flags == 0).
247*042d53a7SEvalZero      * 2. Explicitly specify the value (flags != 0).
248*042d53a7SEvalZero      *
249*042d53a7SEvalZero      * Note: The CSS prohibits advertising a flags value of 0, so this method
250*042d53a7SEvalZero      * of specifying option 1 vs. 2 is sound.
251*042d53a7SEvalZero      */
252*042d53a7SEvalZero     if (adv_fields->flags != 0) {
253*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_FLAGS, 1,
254*042d53a7SEvalZero                                       &adv_fields->flags, dst, dst_len,
255*042d53a7SEvalZero                                       max_len, om);
256*042d53a7SEvalZero 
257*042d53a7SEvalZero         if (rc != 0) {
258*042d53a7SEvalZero             return rc;
259*042d53a7SEvalZero         }
260*042d53a7SEvalZero     }
261*042d53a7SEvalZero 
262*042d53a7SEvalZero     /*** 0x02,0x03 - 16-bit service class UUIDs. */
263*042d53a7SEvalZero     if (adv_fields->uuids16 != NULL && adv_fields->num_uuids16) {
264*042d53a7SEvalZero         if (adv_fields->uuids16_is_complete) {
265*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_COMP_UUIDS16;
266*042d53a7SEvalZero         } else {
267*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
268*042d53a7SEvalZero         }
269*042d53a7SEvalZero 
270*042d53a7SEvalZero         rc = ble_hs_adv_set_array_uuid16(type, adv_fields->num_uuids16,
271*042d53a7SEvalZero                                          adv_fields->uuids16, dst, dst_len,
272*042d53a7SEvalZero                                          max_len, om);
273*042d53a7SEvalZero         if (rc != 0) {
274*042d53a7SEvalZero             return rc;
275*042d53a7SEvalZero         }
276*042d53a7SEvalZero     }
277*042d53a7SEvalZero 
278*042d53a7SEvalZero     /*** 0x04,0x05 - 32-bit service class UUIDs. */
279*042d53a7SEvalZero     if (adv_fields->uuids32 != NULL && adv_fields->num_uuids32) {
280*042d53a7SEvalZero         if (adv_fields->uuids32_is_complete) {
281*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_COMP_UUIDS32;
282*042d53a7SEvalZero         } else {
283*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_INCOMP_UUIDS32;
284*042d53a7SEvalZero         }
285*042d53a7SEvalZero 
286*042d53a7SEvalZero         rc = ble_hs_adv_set_array_uuid32(type, adv_fields->num_uuids32,
287*042d53a7SEvalZero                                          adv_fields->uuids32, dst, dst_len,
288*042d53a7SEvalZero                                          max_len, om);
289*042d53a7SEvalZero         if (rc != 0) {
290*042d53a7SEvalZero             return rc;
291*042d53a7SEvalZero         }
292*042d53a7SEvalZero     }
293*042d53a7SEvalZero 
294*042d53a7SEvalZero     /*** 0x06,0x07 - 128-bit service class UUIDs. */
295*042d53a7SEvalZero     if (adv_fields->uuids128 != NULL && adv_fields->num_uuids128 > 0) {
296*042d53a7SEvalZero         if (adv_fields->uuids128_is_complete) {
297*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_COMP_UUIDS128;
298*042d53a7SEvalZero         } else {
299*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_INCOMP_UUIDS128;
300*042d53a7SEvalZero         }
301*042d53a7SEvalZero 
302*042d53a7SEvalZero         rc = ble_hs_adv_set_array_uuid128(type, adv_fields->num_uuids128,
303*042d53a7SEvalZero                                           adv_fields->uuids128, dst, dst_len,
304*042d53a7SEvalZero                                           max_len, om);
305*042d53a7SEvalZero         if (rc != 0) {
306*042d53a7SEvalZero             return rc;
307*042d53a7SEvalZero         }
308*042d53a7SEvalZero     }
309*042d53a7SEvalZero 
310*042d53a7SEvalZero     /*** 0x08,0x09 - Local name. */
311*042d53a7SEvalZero     if (adv_fields->name != NULL && adv_fields->name_len > 0) {
312*042d53a7SEvalZero         if (adv_fields->name_is_complete) {
313*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_COMP_NAME;
314*042d53a7SEvalZero         } else {
315*042d53a7SEvalZero             type = BLE_HS_ADV_TYPE_INCOMP_NAME;
316*042d53a7SEvalZero         }
317*042d53a7SEvalZero 
318*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(type, adv_fields->name_len,
319*042d53a7SEvalZero                                       adv_fields->name, dst, dst_len, max_len,
320*042d53a7SEvalZero                                       om);
321*042d53a7SEvalZero         if (rc != 0) {
322*042d53a7SEvalZero             return rc;
323*042d53a7SEvalZero         }
324*042d53a7SEvalZero     }
325*042d53a7SEvalZero 
326*042d53a7SEvalZero     /*** 0x0a - Tx power level. */
327*042d53a7SEvalZero     if (adv_fields->tx_pwr_lvl_is_present) {
328*042d53a7SEvalZero         /* Read the power level from the controller if requested; otherwise use
329*042d53a7SEvalZero          * the explicitly specified value.
330*042d53a7SEvalZero          */
331*042d53a7SEvalZero         if (adv_fields->tx_pwr_lvl == BLE_HS_ADV_TX_PWR_LVL_AUTO) {
332*042d53a7SEvalZero             rc = ble_hs_hci_util_read_adv_tx_pwr(&tx_pwr_lvl);
333*042d53a7SEvalZero             if (rc != 0) {
334*042d53a7SEvalZero                 return rc;
335*042d53a7SEvalZero             }
336*042d53a7SEvalZero         } else {
337*042d53a7SEvalZero             tx_pwr_lvl = adv_fields->tx_pwr_lvl;
338*042d53a7SEvalZero         }
339*042d53a7SEvalZero 
340*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_TX_PWR_LVL, 1,
341*042d53a7SEvalZero                                       &tx_pwr_lvl, dst, dst_len, max_len, om);
342*042d53a7SEvalZero         if (rc != 0) {
343*042d53a7SEvalZero             return rc;
344*042d53a7SEvalZero         }
345*042d53a7SEvalZero     }
346*042d53a7SEvalZero 
347*042d53a7SEvalZero     /*** 0x12 - Slave connection interval range. */
348*042d53a7SEvalZero     if (adv_fields->slave_itvl_range != NULL) {
349*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE,
350*042d53a7SEvalZero                                       BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN,
351*042d53a7SEvalZero                                       adv_fields->slave_itvl_range, dst,
352*042d53a7SEvalZero                                       dst_len, max_len, om);
353*042d53a7SEvalZero         if (rc != 0) {
354*042d53a7SEvalZero             return rc;
355*042d53a7SEvalZero         }
356*042d53a7SEvalZero     }
357*042d53a7SEvalZero 
358*042d53a7SEvalZero     /*** 0x16 - Service data - 16-bit UUID. */
359*042d53a7SEvalZero     if (adv_fields->svc_data_uuid16 != NULL) {
360*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_SVC_DATA_UUID16,
361*042d53a7SEvalZero                                       adv_fields->svc_data_uuid16_len,
362*042d53a7SEvalZero                                       adv_fields->svc_data_uuid16, dst, dst_len,
363*042d53a7SEvalZero                                       max_len, om);
364*042d53a7SEvalZero         if (rc != 0) {
365*042d53a7SEvalZero             return rc;
366*042d53a7SEvalZero         }
367*042d53a7SEvalZero     }
368*042d53a7SEvalZero 
369*042d53a7SEvalZero     /*** 0x17 - Public target address. */
370*042d53a7SEvalZero     if (adv_fields->public_tgt_addr != NULL &&
371*042d53a7SEvalZero         adv_fields->num_public_tgt_addrs != 0) {
372*042d53a7SEvalZero 
373*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR,
374*042d53a7SEvalZero                                  BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN *
375*042d53a7SEvalZero                                      adv_fields->num_public_tgt_addrs,
376*042d53a7SEvalZero                                  adv_fields->public_tgt_addr, dst, dst_len,
377*042d53a7SEvalZero                                  max_len, om);
378*042d53a7SEvalZero         if (rc != 0) {
379*042d53a7SEvalZero             return rc;
380*042d53a7SEvalZero         }
381*042d53a7SEvalZero     }
382*042d53a7SEvalZero 
383*042d53a7SEvalZero     /*** 0x19 - Appearance. */
384*042d53a7SEvalZero     if (adv_fields->appearance_is_present) {
385*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_APPEARANCE,
386*042d53a7SEvalZero                                       BLE_HS_ADV_APPEARANCE_LEN,
387*042d53a7SEvalZero                                       &adv_fields->appearance, dst, dst_len,
388*042d53a7SEvalZero                                       max_len, om);
389*042d53a7SEvalZero         if (rc != 0) {
390*042d53a7SEvalZero             return rc;
391*042d53a7SEvalZero         }
392*042d53a7SEvalZero     }
393*042d53a7SEvalZero 
394*042d53a7SEvalZero     /*** 0x1a - Advertising interval. */
395*042d53a7SEvalZero     if (adv_fields->adv_itvl_is_present) {
396*042d53a7SEvalZero         rc = ble_hs_adv_set_array16(BLE_HS_ADV_TYPE_ADV_ITVL, 1,
397*042d53a7SEvalZero                                     &adv_fields->adv_itvl, dst, dst_len,
398*042d53a7SEvalZero                                     max_len, om);
399*042d53a7SEvalZero         if (rc != 0) {
400*042d53a7SEvalZero             return rc;
401*042d53a7SEvalZero         }
402*042d53a7SEvalZero     }
403*042d53a7SEvalZero 
404*042d53a7SEvalZero     /*** 0x20 - Service data - 32-bit UUID. */
405*042d53a7SEvalZero     if (adv_fields->svc_data_uuid32 != NULL) {
406*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_SVC_DATA_UUID32,
407*042d53a7SEvalZero                                      adv_fields->svc_data_uuid32_len,
408*042d53a7SEvalZero                                      adv_fields->svc_data_uuid32, dst, dst_len,
409*042d53a7SEvalZero                                      max_len, om);
410*042d53a7SEvalZero         if (rc != 0) {
411*042d53a7SEvalZero             return rc;
412*042d53a7SEvalZero         }
413*042d53a7SEvalZero     }
414*042d53a7SEvalZero 
415*042d53a7SEvalZero     /*** 0x21 - Service data - 128-bit UUID. */
416*042d53a7SEvalZero     if (adv_fields->svc_data_uuid128 != NULL) {
417*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_SVC_DATA_UUID128,
418*042d53a7SEvalZero                                       adv_fields->svc_data_uuid128_len,
419*042d53a7SEvalZero                                       adv_fields->svc_data_uuid128, dst,
420*042d53a7SEvalZero                                       dst_len, max_len, om);
421*042d53a7SEvalZero         if (rc != 0) {
422*042d53a7SEvalZero             return rc;
423*042d53a7SEvalZero         }
424*042d53a7SEvalZero     }
425*042d53a7SEvalZero 
426*042d53a7SEvalZero     /*** 0x24 - URI. */
427*042d53a7SEvalZero     if (adv_fields->uri != NULL) {
428*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_URI, adv_fields->uri_len,
429*042d53a7SEvalZero                                       adv_fields->uri, dst, dst_len, max_len,
430*042d53a7SEvalZero                                       om);
431*042d53a7SEvalZero         if (rc != 0) {
432*042d53a7SEvalZero             return rc;
433*042d53a7SEvalZero         }
434*042d53a7SEvalZero     }
435*042d53a7SEvalZero 
436*042d53a7SEvalZero     /*** 0xff - Manufacturer specific data. */
437*042d53a7SEvalZero     if (adv_fields->mfg_data != NULL) {
438*042d53a7SEvalZero         rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_MFG_DATA,
439*042d53a7SEvalZero                                       adv_fields->mfg_data_len,
440*042d53a7SEvalZero                                       adv_fields->mfg_data,
441*042d53a7SEvalZero                                       dst, dst_len, max_len, om);
442*042d53a7SEvalZero         if (rc != 0) {
443*042d53a7SEvalZero             return rc;
444*042d53a7SEvalZero         }
445*042d53a7SEvalZero     }
446*042d53a7SEvalZero 
447*042d53a7SEvalZero     return 0;
448*042d53a7SEvalZero }
449*042d53a7SEvalZero 
450*042d53a7SEvalZero /**
451*042d53a7SEvalZero  * Converts a high-level set of fields to a byte buffer.
452*042d53a7SEvalZero  *
453*042d53a7SEvalZero  * @return                      0 on success; nonzero on failure.
454*042d53a7SEvalZero  */
455*042d53a7SEvalZero int
ble_hs_adv_set_fields(const struct ble_hs_adv_fields * adv_fields,uint8_t * dst,uint8_t * dst_len,uint8_t max_len)456*042d53a7SEvalZero ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields,
457*042d53a7SEvalZero                       uint8_t *dst, uint8_t *dst_len, uint8_t max_len)
458*042d53a7SEvalZero {
459*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE
460*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
461*042d53a7SEvalZero #endif
462*042d53a7SEvalZero 
463*042d53a7SEvalZero     return adv_set_fields(adv_fields, dst, dst_len, max_len, NULL);
464*042d53a7SEvalZero }
465*042d53a7SEvalZero 
466*042d53a7SEvalZero int
ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields * adv_fields,struct os_mbuf * om)467*042d53a7SEvalZero ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields *adv_fields,
468*042d53a7SEvalZero                            struct os_mbuf *om)
469*042d53a7SEvalZero {
470*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE
471*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
472*042d53a7SEvalZero #endif
473*042d53a7SEvalZero     return adv_set_fields(adv_fields, NULL, NULL, 0, om);
474*042d53a7SEvalZero }
475*042d53a7SEvalZero 
476*042d53a7SEvalZero static int
ble_hs_adv_parse_uuids16(struct ble_hs_adv_fields * adv_fields,const uint8_t * data,uint8_t data_len)477*042d53a7SEvalZero ble_hs_adv_parse_uuids16(struct ble_hs_adv_fields *adv_fields,
478*042d53a7SEvalZero                          const uint8_t *data, uint8_t data_len)
479*042d53a7SEvalZero {
480*042d53a7SEvalZero     ble_uuid_any_t uuid;
481*042d53a7SEvalZero     int i;
482*042d53a7SEvalZero 
483*042d53a7SEvalZero     if (data_len % 2 != 0) {
484*042d53a7SEvalZero         return BLE_HS_EBADDATA;
485*042d53a7SEvalZero     }
486*042d53a7SEvalZero 
487*042d53a7SEvalZero     adv_fields->uuids16 = ble_hs_adv_uuids16;
488*042d53a7SEvalZero     adv_fields->num_uuids16 = data_len / 2;
489*042d53a7SEvalZero 
490*042d53a7SEvalZero     for (i = 0; i < adv_fields->num_uuids16; i++) {
491*042d53a7SEvalZero         ble_uuid_init_from_buf(&uuid, data + i * 2, 2);
492*042d53a7SEvalZero         adv_fields->uuids16[i] = uuid.u16;
493*042d53a7SEvalZero     }
494*042d53a7SEvalZero 
495*042d53a7SEvalZero     return 0;
496*042d53a7SEvalZero }
497*042d53a7SEvalZero 
498*042d53a7SEvalZero static int
ble_hs_adv_parse_uuids32(struct ble_hs_adv_fields * adv_fields,const uint8_t * data,uint8_t data_len)499*042d53a7SEvalZero ble_hs_adv_parse_uuids32(struct ble_hs_adv_fields *adv_fields,
500*042d53a7SEvalZero                          const uint8_t *data, uint8_t data_len)
501*042d53a7SEvalZero {
502*042d53a7SEvalZero     ble_uuid_any_t uuid;
503*042d53a7SEvalZero     int i;
504*042d53a7SEvalZero 
505*042d53a7SEvalZero     if (data_len % 4 != 0) {
506*042d53a7SEvalZero         return BLE_HS_EBADDATA;
507*042d53a7SEvalZero     }
508*042d53a7SEvalZero 
509*042d53a7SEvalZero     adv_fields->uuids32 = ble_hs_adv_uuids32;
510*042d53a7SEvalZero     adv_fields->num_uuids32 = data_len / 4;
511*042d53a7SEvalZero 
512*042d53a7SEvalZero     for (i = 0; i < adv_fields->num_uuids32; i++) {
513*042d53a7SEvalZero         ble_uuid_init_from_buf(&uuid, data + i * 4, 4);
514*042d53a7SEvalZero         adv_fields->uuids32[i] = uuid.u32;
515*042d53a7SEvalZero     }
516*042d53a7SEvalZero 
517*042d53a7SEvalZero     return 0;
518*042d53a7SEvalZero }
519*042d53a7SEvalZero 
520*042d53a7SEvalZero static int
ble_hs_adv_parse_uuids128(struct ble_hs_adv_fields * adv_fields,const uint8_t * data,uint8_t data_len)521*042d53a7SEvalZero ble_hs_adv_parse_uuids128(struct ble_hs_adv_fields *adv_fields,
522*042d53a7SEvalZero                           const uint8_t *data, uint8_t data_len)
523*042d53a7SEvalZero {
524*042d53a7SEvalZero     ble_uuid_any_t uuid;
525*042d53a7SEvalZero     int i;
526*042d53a7SEvalZero 
527*042d53a7SEvalZero     if (data_len % 16 != 0) {
528*042d53a7SEvalZero         return BLE_HS_EBADDATA;
529*042d53a7SEvalZero     }
530*042d53a7SEvalZero 
531*042d53a7SEvalZero     adv_fields->uuids128 = ble_hs_adv_uuids128;
532*042d53a7SEvalZero     adv_fields->num_uuids128 = data_len / 16;
533*042d53a7SEvalZero 
534*042d53a7SEvalZero     for (i = 0; i < adv_fields->num_uuids128; i++) {
535*042d53a7SEvalZero         ble_uuid_init_from_buf(&uuid, data + i * 16, 16);
536*042d53a7SEvalZero         adv_fields->uuids128[i] = uuid.u128;
537*042d53a7SEvalZero     }
538*042d53a7SEvalZero 
539*042d53a7SEvalZero     return 0;
540*042d53a7SEvalZero }
541*042d53a7SEvalZero 
542*042d53a7SEvalZero static int
ble_hs_adv_parse_one_field(struct ble_hs_adv_fields * adv_fields,uint8_t * total_len,uint8_t * src,uint8_t src_len)543*042d53a7SEvalZero ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields,
544*042d53a7SEvalZero                            uint8_t *total_len, uint8_t *src, uint8_t src_len)
545*042d53a7SEvalZero {
546*042d53a7SEvalZero     uint8_t data_len;
547*042d53a7SEvalZero     uint8_t type;
548*042d53a7SEvalZero     uint8_t *data;
549*042d53a7SEvalZero     int rc;
550*042d53a7SEvalZero 
551*042d53a7SEvalZero     if (src_len < 1) {
552*042d53a7SEvalZero         return BLE_HS_EMSGSIZE;
553*042d53a7SEvalZero     }
554*042d53a7SEvalZero     *total_len = src[0] + 1;
555*042d53a7SEvalZero 
556*042d53a7SEvalZero     if (src_len < *total_len) {
557*042d53a7SEvalZero         return BLE_HS_EMSGSIZE;
558*042d53a7SEvalZero     }
559*042d53a7SEvalZero 
560*042d53a7SEvalZero     type = src[1];
561*042d53a7SEvalZero     data = src + 2;
562*042d53a7SEvalZero     data_len = *total_len - 2;
563*042d53a7SEvalZero 
564*042d53a7SEvalZero     if (data_len > BLE_HS_ADV_MAX_FIELD_SZ) {
565*042d53a7SEvalZero         return BLE_HS_EBADDATA;
566*042d53a7SEvalZero     }
567*042d53a7SEvalZero 
568*042d53a7SEvalZero     switch (type) {
569*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_FLAGS:
570*042d53a7SEvalZero         if (data_len != BLE_HS_ADV_FLAGS_LEN) {
571*042d53a7SEvalZero             return BLE_HS_EBADDATA;
572*042d53a7SEvalZero         }
573*042d53a7SEvalZero         adv_fields->flags = *data;
574*042d53a7SEvalZero         break;
575*042d53a7SEvalZero 
576*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_INCOMP_UUIDS16:
577*042d53a7SEvalZero         rc = ble_hs_adv_parse_uuids16(adv_fields, data, data_len);
578*042d53a7SEvalZero         if (rc != 0) {
579*042d53a7SEvalZero             return rc;
580*042d53a7SEvalZero         }
581*042d53a7SEvalZero         adv_fields->uuids16_is_complete = 0;
582*042d53a7SEvalZero         break;
583*042d53a7SEvalZero 
584*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_COMP_UUIDS16:
585*042d53a7SEvalZero         rc = ble_hs_adv_parse_uuids16(adv_fields, data, data_len);
586*042d53a7SEvalZero         if (rc != 0) {
587*042d53a7SEvalZero             return rc;
588*042d53a7SEvalZero         }
589*042d53a7SEvalZero         adv_fields->uuids16_is_complete = 1;
590*042d53a7SEvalZero         break;
591*042d53a7SEvalZero 
592*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_INCOMP_UUIDS32:
593*042d53a7SEvalZero         rc = ble_hs_adv_parse_uuids32(adv_fields, data, data_len);
594*042d53a7SEvalZero         if (rc != 0) {
595*042d53a7SEvalZero             return rc;
596*042d53a7SEvalZero         }
597*042d53a7SEvalZero         adv_fields->uuids16_is_complete = 0;
598*042d53a7SEvalZero         break;
599*042d53a7SEvalZero 
600*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_COMP_UUIDS32:
601*042d53a7SEvalZero         rc = ble_hs_adv_parse_uuids32(adv_fields, data, data_len);
602*042d53a7SEvalZero         if (rc != 0) {
603*042d53a7SEvalZero             return rc;
604*042d53a7SEvalZero         }
605*042d53a7SEvalZero         adv_fields->uuids16_is_complete = 1;
606*042d53a7SEvalZero         break;
607*042d53a7SEvalZero 
608*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_INCOMP_UUIDS128:
609*042d53a7SEvalZero         rc = ble_hs_adv_parse_uuids128(adv_fields, data, data_len);
610*042d53a7SEvalZero         if (rc != 0) {
611*042d53a7SEvalZero             return rc;
612*042d53a7SEvalZero         }
613*042d53a7SEvalZero         adv_fields->uuids128_is_complete = 0;
614*042d53a7SEvalZero         break;
615*042d53a7SEvalZero 
616*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_COMP_UUIDS128:
617*042d53a7SEvalZero         rc = ble_hs_adv_parse_uuids128(adv_fields, data, data_len);
618*042d53a7SEvalZero         if (rc != 0) {
619*042d53a7SEvalZero             return rc;
620*042d53a7SEvalZero         }
621*042d53a7SEvalZero         adv_fields->uuids128_is_complete = 1;
622*042d53a7SEvalZero         break;
623*042d53a7SEvalZero 
624*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_INCOMP_NAME:
625*042d53a7SEvalZero         adv_fields->name = data;
626*042d53a7SEvalZero         adv_fields->name_len = data_len;
627*042d53a7SEvalZero         adv_fields->name_is_complete = 0;
628*042d53a7SEvalZero         break;
629*042d53a7SEvalZero 
630*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_COMP_NAME:
631*042d53a7SEvalZero         adv_fields->name = data;
632*042d53a7SEvalZero         adv_fields->name_len = data_len;
633*042d53a7SEvalZero         adv_fields->name_is_complete = 1;
634*042d53a7SEvalZero         break;
635*042d53a7SEvalZero 
636*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_TX_PWR_LVL:
637*042d53a7SEvalZero         if (data_len != BLE_HS_ADV_TX_PWR_LVL_LEN) {
638*042d53a7SEvalZero             return BLE_HS_EBADDATA;
639*042d53a7SEvalZero         }
640*042d53a7SEvalZero         adv_fields->tx_pwr_lvl = *data;
641*042d53a7SEvalZero         adv_fields->tx_pwr_lvl_is_present = 1;
642*042d53a7SEvalZero         break;
643*042d53a7SEvalZero 
644*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE:
645*042d53a7SEvalZero         if (data_len != BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN) {
646*042d53a7SEvalZero             return BLE_HS_EBADDATA;
647*042d53a7SEvalZero         }
648*042d53a7SEvalZero         adv_fields->slave_itvl_range = data;
649*042d53a7SEvalZero         break;
650*042d53a7SEvalZero 
651*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_SVC_DATA_UUID16:
652*042d53a7SEvalZero         if (data_len < BLE_HS_ADV_SVC_DATA_UUID16_MIN_LEN) {
653*042d53a7SEvalZero             return BLE_HS_EBADDATA;
654*042d53a7SEvalZero         }
655*042d53a7SEvalZero         adv_fields->svc_data_uuid16 = data;
656*042d53a7SEvalZero         adv_fields->svc_data_uuid16_len = data_len;
657*042d53a7SEvalZero         break;
658*042d53a7SEvalZero 
659*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR:
660*042d53a7SEvalZero         if (data_len % BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN != 0) {
661*042d53a7SEvalZero             return BLE_HS_EBADDATA;
662*042d53a7SEvalZero         }
663*042d53a7SEvalZero         adv_fields->public_tgt_addr = data;
664*042d53a7SEvalZero         adv_fields->num_public_tgt_addrs =
665*042d53a7SEvalZero             data_len / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
666*042d53a7SEvalZero         break;
667*042d53a7SEvalZero 
668*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_APPEARANCE:
669*042d53a7SEvalZero         if (data_len != BLE_HS_ADV_APPEARANCE_LEN) {
670*042d53a7SEvalZero             return BLE_HS_EBADDATA;
671*042d53a7SEvalZero         }
672*042d53a7SEvalZero         adv_fields->appearance = get_le16(data);
673*042d53a7SEvalZero         adv_fields->appearance_is_present = 1;
674*042d53a7SEvalZero         break;
675*042d53a7SEvalZero 
676*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_ADV_ITVL:
677*042d53a7SEvalZero         if (data_len != BLE_HS_ADV_ADV_ITVL_LEN) {
678*042d53a7SEvalZero             return BLE_HS_EBADDATA;
679*042d53a7SEvalZero         }
680*042d53a7SEvalZero         adv_fields->adv_itvl = get_le16(data);
681*042d53a7SEvalZero         adv_fields->adv_itvl_is_present = 1;
682*042d53a7SEvalZero         break;
683*042d53a7SEvalZero 
684*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_SVC_DATA_UUID32:
685*042d53a7SEvalZero         if (data_len < BLE_HS_ADV_SVC_DATA_UUID32_MIN_LEN) {
686*042d53a7SEvalZero             return BLE_HS_EBADDATA;
687*042d53a7SEvalZero         }
688*042d53a7SEvalZero         adv_fields->svc_data_uuid32 = data;
689*042d53a7SEvalZero         adv_fields->svc_data_uuid32_len = data_len;
690*042d53a7SEvalZero         break;
691*042d53a7SEvalZero 
692*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_SVC_DATA_UUID128:
693*042d53a7SEvalZero         if (data_len < BLE_HS_ADV_SVC_DATA_UUID128_MIN_LEN) {
694*042d53a7SEvalZero             return BLE_HS_EBADDATA;
695*042d53a7SEvalZero         }
696*042d53a7SEvalZero         adv_fields->svc_data_uuid128 = data;
697*042d53a7SEvalZero         adv_fields->svc_data_uuid128_len = data_len;
698*042d53a7SEvalZero         break;
699*042d53a7SEvalZero 
700*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_URI:
701*042d53a7SEvalZero         adv_fields->uri = data;
702*042d53a7SEvalZero         adv_fields->uri_len = data_len;
703*042d53a7SEvalZero         break;
704*042d53a7SEvalZero 
705*042d53a7SEvalZero     case BLE_HS_ADV_TYPE_MFG_DATA:
706*042d53a7SEvalZero         adv_fields->mfg_data = data;
707*042d53a7SEvalZero         adv_fields->mfg_data_len = data_len;
708*042d53a7SEvalZero         break;
709*042d53a7SEvalZero 
710*042d53a7SEvalZero     default:
711*042d53a7SEvalZero         break;
712*042d53a7SEvalZero     }
713*042d53a7SEvalZero 
714*042d53a7SEvalZero     return 0;
715*042d53a7SEvalZero }
716*042d53a7SEvalZero 
717*042d53a7SEvalZero int
ble_hs_adv_parse_fields(struct ble_hs_adv_fields * adv_fields,uint8_t * src,uint8_t src_len)718*042d53a7SEvalZero ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields, uint8_t *src,
719*042d53a7SEvalZero                         uint8_t src_len)
720*042d53a7SEvalZero {
721*042d53a7SEvalZero     uint8_t field_len;
722*042d53a7SEvalZero     int rc;
723*042d53a7SEvalZero 
724*042d53a7SEvalZero     memset(adv_fields, 0, sizeof *adv_fields);
725*042d53a7SEvalZero 
726*042d53a7SEvalZero     while (src_len > 0) {
727*042d53a7SEvalZero         rc = ble_hs_adv_parse_one_field(adv_fields, &field_len, src, src_len);
728*042d53a7SEvalZero         if (rc != 0) {
729*042d53a7SEvalZero             return rc;
730*042d53a7SEvalZero         }
731*042d53a7SEvalZero 
732*042d53a7SEvalZero         src += field_len;
733*042d53a7SEvalZero         src_len -= field_len;
734*042d53a7SEvalZero     }
735*042d53a7SEvalZero 
736*042d53a7SEvalZero     return 0;
737*042d53a7SEvalZero }
738*042d53a7SEvalZero 
739*042d53a7SEvalZero int
ble_hs_adv_parse(const uint8_t * data,uint8_t length,ble_hs_adv_parse_func_t func,void * user_data)740*042d53a7SEvalZero ble_hs_adv_parse(const uint8_t *data, uint8_t length,
741*042d53a7SEvalZero                  ble_hs_adv_parse_func_t func, void *user_data)
742*042d53a7SEvalZero {
743*042d53a7SEvalZero     const struct ble_hs_adv_field *field;
744*042d53a7SEvalZero 
745*042d53a7SEvalZero     while (length > 1) {
746*042d53a7SEvalZero         field = (const void *) data;
747*042d53a7SEvalZero 
748*042d53a7SEvalZero         if (field->length >= length) {
749*042d53a7SEvalZero             return BLE_HS_EBADDATA;
750*042d53a7SEvalZero         }
751*042d53a7SEvalZero 
752*042d53a7SEvalZero         if (func(field, user_data) == 0) {
753*042d53a7SEvalZero             return 0;
754*042d53a7SEvalZero         }
755*042d53a7SEvalZero 
756*042d53a7SEvalZero         length -= 1 + field->length;
757*042d53a7SEvalZero         data += 1 + field->length;
758*042d53a7SEvalZero     }
759*042d53a7SEvalZero 
760*042d53a7SEvalZero     return 0;
761*042d53a7SEvalZero }
762*042d53a7SEvalZero 
763*042d53a7SEvalZero static int
find_field_func(const struct ble_hs_adv_field * field,void * user_data)764*042d53a7SEvalZero find_field_func(const struct ble_hs_adv_field *field, void *user_data)
765*042d53a7SEvalZero {
766*042d53a7SEvalZero     struct find_field_data *ffd = user_data;
767*042d53a7SEvalZero 
768*042d53a7SEvalZero     if (field->type != ffd->type) {
769*042d53a7SEvalZero         return BLE_HS_EAGAIN;
770*042d53a7SEvalZero     }
771*042d53a7SEvalZero 
772*042d53a7SEvalZero     ffd->field = field;
773*042d53a7SEvalZero 
774*042d53a7SEvalZero     return 0;
775*042d53a7SEvalZero }
776*042d53a7SEvalZero 
777*042d53a7SEvalZero int
ble_hs_adv_find_field(uint8_t type,const uint8_t * data,uint8_t length,const struct ble_hs_adv_field ** out)778*042d53a7SEvalZero ble_hs_adv_find_field(uint8_t type, const uint8_t *data, uint8_t length,
779*042d53a7SEvalZero                       const struct ble_hs_adv_field **out)
780*042d53a7SEvalZero {
781*042d53a7SEvalZero     int rc;
782*042d53a7SEvalZero     struct find_field_data ffd = {
783*042d53a7SEvalZero             .type = type,
784*042d53a7SEvalZero             .field = NULL,
785*042d53a7SEvalZero     };
786*042d53a7SEvalZero 
787*042d53a7SEvalZero     rc = ble_hs_adv_parse(data, length, find_field_func, &ffd);
788*042d53a7SEvalZero     if (rc != 0) {
789*042d53a7SEvalZero         return rc;
790*042d53a7SEvalZero     }
791*042d53a7SEvalZero 
792*042d53a7SEvalZero     if (!ffd.field) {
793*042d53a7SEvalZero         return BLE_HS_ENOENT;
794*042d53a7SEvalZero     }
795*042d53a7SEvalZero 
796*042d53a7SEvalZero     *out = ffd.field;
797*042d53a7SEvalZero 
798*042d53a7SEvalZero     return 0;
799*042d53a7SEvalZero }
800