xref: /btstack/src/classic/sdp_util.c (revision 3deb3ec68039c68a16974dffc53343233662f909)
1*3deb3ec6SMatthias Ringwald /*
2*3deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*3deb3ec6SMatthias Ringwald  *
4*3deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*3deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*3deb3ec6SMatthias Ringwald  * are met:
7*3deb3ec6SMatthias Ringwald  *
8*3deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*3deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*3deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*3deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*3deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*3deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
16*3deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*3deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*3deb3ec6SMatthias Ringwald  *    monetary gain.
19*3deb3ec6SMatthias Ringwald  *
20*3deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*3deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*3deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*3deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*3deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*3deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*3deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*3deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*3deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*3deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*3deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*3deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
32*3deb3ec6SMatthias Ringwald  *
33*3deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
34*3deb3ec6SMatthias Ringwald  * [email protected]
35*3deb3ec6SMatthias Ringwald  *
36*3deb3ec6SMatthias Ringwald  */
37*3deb3ec6SMatthias Ringwald 
38*3deb3ec6SMatthias Ringwald /*
39*3deb3ec6SMatthias Ringwald  *  sdp_util.c
40*3deb3ec6SMatthias Ringwald  */
41*3deb3ec6SMatthias Ringwald 
42*3deb3ec6SMatthias Ringwald #include "sdp_util.h"
43*3deb3ec6SMatthias Ringwald #include "utils.h"
44*3deb3ec6SMatthias Ringwald #include "btstack-config.h"
45*3deb3ec6SMatthias Ringwald 
46*3deb3ec6SMatthias Ringwald #include <stdio.h>
47*3deb3ec6SMatthias Ringwald #include <stdlib.h>
48*3deb3ec6SMatthias Ringwald #include <string.h>
49*3deb3ec6SMatthias Ringwald #include <stdint.h>
50*3deb3ec6SMatthias Ringwald #include <inttypes.h>   // PRIx32
51*3deb3ec6SMatthias Ringwald 
52*3deb3ec6SMatthias Ringwald #ifdef SDP_DES_DUMP
53*3deb3ec6SMatthias Ringwald // workaround for missing PRIx32 on mspgcc (16-bit MCU)
54*3deb3ec6SMatthias Ringwald #ifndef PRIx32
55*3deb3ec6SMatthias Ringwald #warning Using own: #define PRIx32 "lx"
56*3deb3ec6SMatthias Ringwald #define PRIx32 "lx"
57*3deb3ec6SMatthias Ringwald #endif
58*3deb3ec6SMatthias Ringwald // date element type names
59*3deb3ec6SMatthias Ringwald const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"};
60*3deb3ec6SMatthias Ringwald #endif
61*3deb3ec6SMatthias Ringwald 
62*3deb3ec6SMatthias Ringwald // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
63*3deb3ec6SMatthias Ringwald const uint8_t sdp_bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
64*3deb3ec6SMatthias Ringwald     0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
65*3deb3ec6SMatthias Ringwald 
66*3deb3ec6SMatthias Ringwald void sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID){
67*3deb3ec6SMatthias Ringwald     memcpy(uuid, sdp_bluetooth_base_uuid, 16);
68*3deb3ec6SMatthias Ringwald     net_store_32(uuid, 0, shortUUID);
69*3deb3ec6SMatthias Ringwald }
70*3deb3ec6SMatthias Ringwald 
71*3deb3ec6SMatthias Ringwald int sdp_has_blueooth_base_uuid(uint8_t * uuid128){
72*3deb3ec6SMatthias Ringwald     return memcmp(&uuid128[4], &sdp_bluetooth_base_uuid[4], 12) == 0;
73*3deb3ec6SMatthias Ringwald }
74*3deb3ec6SMatthias Ringwald 
75*3deb3ec6SMatthias Ringwald // MARK: DataElement getter
76*3deb3ec6SMatthias Ringwald de_size_t de_get_size_type(uint8_t *header){
77*3deb3ec6SMatthias Ringwald     return (de_size_t) (header[0] & 7);
78*3deb3ec6SMatthias Ringwald }
79*3deb3ec6SMatthias Ringwald 
80*3deb3ec6SMatthias Ringwald de_type_t de_get_element_type(uint8_t *header){
81*3deb3ec6SMatthias Ringwald     return (de_type_t) (header[0] >> 3);
82*3deb3ec6SMatthias Ringwald }
83*3deb3ec6SMatthias Ringwald 
84*3deb3ec6SMatthias Ringwald int de_get_header_size(uint8_t * header){
85*3deb3ec6SMatthias Ringwald     de_size_t de_size = de_get_size_type(header);
86*3deb3ec6SMatthias Ringwald     if (de_size <= DE_SIZE_128) {
87*3deb3ec6SMatthias Ringwald         return 1;
88*3deb3ec6SMatthias Ringwald     }
89*3deb3ec6SMatthias Ringwald     return 1 + (1 << (de_size-DE_SIZE_VAR_8));
90*3deb3ec6SMatthias Ringwald }
91*3deb3ec6SMatthias Ringwald 
92*3deb3ec6SMatthias Ringwald int de_get_data_size(uint8_t * header){
93*3deb3ec6SMatthias Ringwald     uint32_t result = 0;
94*3deb3ec6SMatthias Ringwald     de_type_t de_type = de_get_element_type(header);
95*3deb3ec6SMatthias Ringwald     de_size_t de_size = de_get_size_type(header);
96*3deb3ec6SMatthias Ringwald     switch (de_size){
97*3deb3ec6SMatthias Ringwald         case DE_SIZE_VAR_8:
98*3deb3ec6SMatthias Ringwald             result = header[1];
99*3deb3ec6SMatthias Ringwald             break;
100*3deb3ec6SMatthias Ringwald         case DE_SIZE_VAR_16:
101*3deb3ec6SMatthias Ringwald             result = READ_NET_16(header,1);
102*3deb3ec6SMatthias Ringwald             break;
103*3deb3ec6SMatthias Ringwald         case DE_SIZE_VAR_32:
104*3deb3ec6SMatthias Ringwald             result = READ_NET_32(header,1);
105*3deb3ec6SMatthias Ringwald             break;
106*3deb3ec6SMatthias Ringwald         default:
107*3deb3ec6SMatthias Ringwald         // case DE_SIZE_8:
108*3deb3ec6SMatthias Ringwald         // case DE_SIZE_16:
109*3deb3ec6SMatthias Ringwald         // case DE_SIZE_32:
110*3deb3ec6SMatthias Ringwald         // case DE_SIZE_64:
111*3deb3ec6SMatthias Ringwald         // case DE_SIZE_128:
112*3deb3ec6SMatthias Ringwald             if (de_type == DE_NIL) return 0;
113*3deb3ec6SMatthias Ringwald             return 1 << de_size;
114*3deb3ec6SMatthias Ringwald     }
115*3deb3ec6SMatthias Ringwald     return result;
116*3deb3ec6SMatthias Ringwald }
117*3deb3ec6SMatthias Ringwald 
118*3deb3ec6SMatthias Ringwald int de_get_len(uint8_t *header){
119*3deb3ec6SMatthias Ringwald     return de_get_header_size(header) + de_get_data_size(header);
120*3deb3ec6SMatthias Ringwald }
121*3deb3ec6SMatthias Ringwald 
122*3deb3ec6SMatthias Ringwald // @returns OK, if UINT16 value was read
123*3deb3ec6SMatthias Ringwald int de_element_get_uint16(uint8_t * element, uint16_t * value){
124*3deb3ec6SMatthias Ringwald     if (de_get_size_type(element) != DE_SIZE_16) return 0;
125*3deb3ec6SMatthias Ringwald     *value = READ_NET_16(element, de_get_header_size(element));
126*3deb3ec6SMatthias Ringwald     return 1;
127*3deb3ec6SMatthias Ringwald }
128*3deb3ec6SMatthias Ringwald 
129*3deb3ec6SMatthias Ringwald // @returns: element is valid UUID
130*3deb3ec6SMatthias Ringwald int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
131*3deb3ec6SMatthias Ringwald     de_type_t uuidType = de_get_element_type(element);
132*3deb3ec6SMatthias Ringwald     de_size_t uuidSize = de_get_size_type(element);
133*3deb3ec6SMatthias Ringwald     if (uuidType != DE_UUID) return 0;
134*3deb3ec6SMatthias Ringwald     uint32_t shortUUID;
135*3deb3ec6SMatthias Ringwald     switch (uuidSize){
136*3deb3ec6SMatthias Ringwald         case DE_SIZE_16:
137*3deb3ec6SMatthias Ringwald             shortUUID = READ_NET_16(element, 1);
138*3deb3ec6SMatthias Ringwald             break;
139*3deb3ec6SMatthias Ringwald         case DE_SIZE_32:
140*3deb3ec6SMatthias Ringwald             shortUUID = READ_NET_32(element, 1);
141*3deb3ec6SMatthias Ringwald             break;
142*3deb3ec6SMatthias Ringwald         case DE_SIZE_128:
143*3deb3ec6SMatthias Ringwald             memcpy(uuid128, element+1, 16);
144*3deb3ec6SMatthias Ringwald             return 1;
145*3deb3ec6SMatthias Ringwald         default:
146*3deb3ec6SMatthias Ringwald             return 0;
147*3deb3ec6SMatthias Ringwald     }
148*3deb3ec6SMatthias Ringwald     sdp_normalize_uuid(uuid128, shortUUID);
149*3deb3ec6SMatthias Ringwald     return 1;
150*3deb3ec6SMatthias Ringwald }
151*3deb3ec6SMatthias Ringwald 
152*3deb3ec6SMatthias Ringwald // @returns 0 if no UUID16 or UUID32 is present, and UUID32 otherwise
153*3deb3ec6SMatthias Ringwald uint32_t de_get_uuid32(uint8_t * element){
154*3deb3ec6SMatthias Ringwald     uint8_t uuid128[16];
155*3deb3ec6SMatthias Ringwald     int validUuid128 = de_get_normalized_uuid(uuid128, element);
156*3deb3ec6SMatthias Ringwald     if (!validUuid128) return 0;
157*3deb3ec6SMatthias Ringwald     int hasBlueoothBaseUuid = sdp_has_blueooth_base_uuid(uuid128);
158*3deb3ec6SMatthias Ringwald     if (!hasBlueoothBaseUuid) return 0;
159*3deb3ec6SMatthias Ringwald     return READ_NET_32(uuid128, 0);
160*3deb3ec6SMatthias Ringwald }
161*3deb3ec6SMatthias Ringwald 
162*3deb3ec6SMatthias Ringwald // functions to create record
163*3deb3ec6SMatthias Ringwald static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){
164*3deb3ec6SMatthias Ringwald     header[0] = (type << 3) | size;
165*3deb3ec6SMatthias Ringwald }
166*3deb3ec6SMatthias Ringwald 
167*3deb3ec6SMatthias Ringwald void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){
168*3deb3ec6SMatthias Ringwald     header[0] = (type << 3) | size;
169*3deb3ec6SMatthias Ringwald     switch (size){
170*3deb3ec6SMatthias Ringwald         case DE_SIZE_VAR_8:
171*3deb3ec6SMatthias Ringwald             header[1] = len;
172*3deb3ec6SMatthias Ringwald             break;
173*3deb3ec6SMatthias Ringwald         case DE_SIZE_VAR_16:
174*3deb3ec6SMatthias Ringwald             net_store_16(header, 1, len);
175*3deb3ec6SMatthias Ringwald             break;
176*3deb3ec6SMatthias Ringwald         case DE_SIZE_VAR_32:
177*3deb3ec6SMatthias Ringwald             net_store_32(header, 1, len);
178*3deb3ec6SMatthias Ringwald             break;
179*3deb3ec6SMatthias Ringwald         default:
180*3deb3ec6SMatthias Ringwald             break;
181*3deb3ec6SMatthias Ringwald     }
182*3deb3ec6SMatthias Ringwald }
183*3deb3ec6SMatthias Ringwald 
184*3deb3ec6SMatthias Ringwald // MARK: DataElement creation
185*3deb3ec6SMatthias Ringwald 
186*3deb3ec6SMatthias Ringwald /* starts a new sequence in empty buffer - first call */
187*3deb3ec6SMatthias Ringwald void de_create_sequence(uint8_t *header){
188*3deb3ec6SMatthias Ringwald     de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
189*3deb3ec6SMatthias Ringwald };
190*3deb3ec6SMatthias Ringwald 
191*3deb3ec6SMatthias Ringwald /* starts a sub-sequence, @returns handle for sub-sequence */
192*3deb3ec6SMatthias Ringwald uint8_t * de_push_sequence(uint8_t *header){
193*3deb3ec6SMatthias Ringwald     int element_len = de_get_len(header);
194*3deb3ec6SMatthias Ringwald     de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
195*3deb3ec6SMatthias Ringwald     return header + element_len;
196*3deb3ec6SMatthias Ringwald }
197*3deb3ec6SMatthias Ringwald 
198*3deb3ec6SMatthias Ringwald /* closes the current sequence and updates the parent sequence */
199*3deb3ec6SMatthias Ringwald void de_pop_sequence(uint8_t * parent, uint8_t * child){
200*3deb3ec6SMatthias Ringwald     int child_len = de_get_len(child);
201*3deb3ec6SMatthias Ringwald     int data_size_parent = READ_NET_16(parent,1);
202*3deb3ec6SMatthias Ringwald     net_store_16(parent, 1, data_size_parent + child_len);
203*3deb3ec6SMatthias Ringwald }
204*3deb3ec6SMatthias Ringwald 
205*3deb3ec6SMatthias Ringwald /* adds a single number value and 16+32 bit UUID to the sequence */
206*3deb3ec6SMatthias Ringwald void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){
207*3deb3ec6SMatthias Ringwald     int data_size   = READ_NET_16(seq,1);
208*3deb3ec6SMatthias Ringwald     int element_size = 1;   // e.g. for DE_TYPE_NIL
209*3deb3ec6SMatthias Ringwald     de_store_descriptor(seq+3+data_size, type, size);
210*3deb3ec6SMatthias Ringwald     switch (size){
211*3deb3ec6SMatthias Ringwald         case DE_SIZE_8:
212*3deb3ec6SMatthias Ringwald             if (type != DE_NIL){
213*3deb3ec6SMatthias Ringwald                 seq[4+data_size] = value;
214*3deb3ec6SMatthias Ringwald                 element_size = 2;
215*3deb3ec6SMatthias Ringwald             }
216*3deb3ec6SMatthias Ringwald             break;
217*3deb3ec6SMatthias Ringwald         case DE_SIZE_16:
218*3deb3ec6SMatthias Ringwald             net_store_16(seq, 4+data_size, value);
219*3deb3ec6SMatthias Ringwald             element_size = 3;
220*3deb3ec6SMatthias Ringwald             break;
221*3deb3ec6SMatthias Ringwald         case DE_SIZE_32:
222*3deb3ec6SMatthias Ringwald             net_store_32(seq, 4+data_size, value);
223*3deb3ec6SMatthias Ringwald             element_size = 5;
224*3deb3ec6SMatthias Ringwald             break;
225*3deb3ec6SMatthias Ringwald         default:
226*3deb3ec6SMatthias Ringwald             break;
227*3deb3ec6SMatthias Ringwald     }
228*3deb3ec6SMatthias Ringwald     net_store_16(seq, 1, data_size+element_size);
229*3deb3ec6SMatthias Ringwald }
230*3deb3ec6SMatthias Ringwald 
231*3deb3ec6SMatthias Ringwald /* add a single block of data, e.g. as DE_STRING, DE_URL */
232*3deb3ec6SMatthias Ringwald void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){
233*3deb3ec6SMatthias Ringwald     int data_size   = READ_NET_16(seq,1);
234*3deb3ec6SMatthias Ringwald     if (size > 0xff) {
235*3deb3ec6SMatthias Ringwald         // use 16-bit lengh information (3 byte header)
236*3deb3ec6SMatthias Ringwald         de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size);
237*3deb3ec6SMatthias Ringwald         data_size += 3;
238*3deb3ec6SMatthias Ringwald     } else {
239*3deb3ec6SMatthias Ringwald         // use 8-bit lengh information (2 byte header)
240*3deb3ec6SMatthias Ringwald         de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size);
241*3deb3ec6SMatthias Ringwald         data_size += 2;
242*3deb3ec6SMatthias Ringwald     }
243*3deb3ec6SMatthias Ringwald     memcpy( seq + 3 + data_size, data, size);
244*3deb3ec6SMatthias Ringwald     data_size += size;
245*3deb3ec6SMatthias Ringwald     net_store_16(seq, 1, data_size);
246*3deb3ec6SMatthias Ringwald }
247*3deb3ec6SMatthias Ringwald 
248*3deb3ec6SMatthias Ringwald void de_add_uuid128(uint8_t * seq, uint8_t * uuid){
249*3deb3ec6SMatthias Ringwald     int data_size   = READ_NET_16(seq,1);
250*3deb3ec6SMatthias Ringwald     de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128);
251*3deb3ec6SMatthias Ringwald     memcpy( seq + 4 + data_size, uuid, 16);
252*3deb3ec6SMatthias Ringwald     net_store_16(seq, 1, data_size+1+16);
253*3deb3ec6SMatthias Ringwald }
254*3deb3ec6SMatthias Ringwald 
255*3deb3ec6SMatthias Ringwald // MARK: DES iterator
256*3deb3ec6SMatthias Ringwald int des_iterator_init(des_iterator_t * it, uint8_t * element){
257*3deb3ec6SMatthias Ringwald     de_type_t type = de_get_element_type(element);
258*3deb3ec6SMatthias Ringwald     if (type != DE_DES) return 0;
259*3deb3ec6SMatthias Ringwald 
260*3deb3ec6SMatthias Ringwald     it->element = element;
261*3deb3ec6SMatthias Ringwald     it->pos = de_get_header_size(element);
262*3deb3ec6SMatthias Ringwald     it->length = de_get_len(element);
263*3deb3ec6SMatthias Ringwald     // printf("des_iterator_init current pos %d, total len %d\n", it->pos, it->length);
264*3deb3ec6SMatthias Ringwald     return 1;
265*3deb3ec6SMatthias Ringwald }
266*3deb3ec6SMatthias Ringwald 
267*3deb3ec6SMatthias Ringwald de_type_t des_iterator_get_type (des_iterator_t * it){
268*3deb3ec6SMatthias Ringwald     return de_get_element_type(&it->element[it->pos]);
269*3deb3ec6SMatthias Ringwald }
270*3deb3ec6SMatthias Ringwald 
271*3deb3ec6SMatthias Ringwald uint16_t des_iterator_get_size (des_iterator_t * it){
272*3deb3ec6SMatthias Ringwald     int length = de_get_len(&it->element[it->pos]);
273*3deb3ec6SMatthias Ringwald     int header_size = de_get_header_size(&it->element[it->pos]);
274*3deb3ec6SMatthias Ringwald     return length - header_size;
275*3deb3ec6SMatthias Ringwald }
276*3deb3ec6SMatthias Ringwald 
277*3deb3ec6SMatthias Ringwald int des_iterator_has_more(des_iterator_t * it){
278*3deb3ec6SMatthias Ringwald     return it->pos < it->length;
279*3deb3ec6SMatthias Ringwald }
280*3deb3ec6SMatthias Ringwald 
281*3deb3ec6SMatthias Ringwald uint8_t * des_iterator_get_element(des_iterator_t * it){
282*3deb3ec6SMatthias Ringwald     if (!des_iterator_has_more(it)) return NULL;
283*3deb3ec6SMatthias Ringwald     return &it->element[it->pos];
284*3deb3ec6SMatthias Ringwald }
285*3deb3ec6SMatthias Ringwald 
286*3deb3ec6SMatthias Ringwald void des_iterator_next(des_iterator_t * it){
287*3deb3ec6SMatthias Ringwald     int element_len = de_get_len(&it->element[it->pos]);
288*3deb3ec6SMatthias Ringwald     // printf("des_iterator_next element size %d, current pos %d, total len %d\n", element_len, it->pos, it->length);
289*3deb3ec6SMatthias Ringwald     it->pos += element_len;
290*3deb3ec6SMatthias Ringwald }
291*3deb3ec6SMatthias Ringwald 
292*3deb3ec6SMatthias Ringwald // MARK: DataElementSequence traversal
293*3deb3ec6SMatthias Ringwald typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context);
294*3deb3ec6SMatthias Ringwald static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){
295*3deb3ec6SMatthias Ringwald     de_type_t type = de_get_element_type(element);
296*3deb3ec6SMatthias Ringwald     if (type != DE_DES) return;
297*3deb3ec6SMatthias Ringwald     int pos = de_get_header_size(element);
298*3deb3ec6SMatthias Ringwald     int end_pos = de_get_len(element);
299*3deb3ec6SMatthias Ringwald     while (pos < end_pos){
300*3deb3ec6SMatthias Ringwald         de_type_t elemType = de_get_element_type(element + pos);
301*3deb3ec6SMatthias Ringwald         de_size_t elemSize = de_get_size_type(element + pos);
302*3deb3ec6SMatthias Ringwald         uint8_t done = (*handler)(element + pos, elemType, elemSize, context);
303*3deb3ec6SMatthias Ringwald         if (done) break;
304*3deb3ec6SMatthias Ringwald         pos += de_get_len(element + pos);
305*3deb3ec6SMatthias Ringwald     }
306*3deb3ec6SMatthias Ringwald }
307*3deb3ec6SMatthias Ringwald 
308*3deb3ec6SMatthias Ringwald // MARK: AttributeList traversal
309*3deb3ec6SMatthias Ringwald typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context);
310*3deb3ec6SMatthias Ringwald static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){
311*3deb3ec6SMatthias Ringwald     de_type_t type = de_get_element_type(element);
312*3deb3ec6SMatthias Ringwald     if (type != DE_DES) return;
313*3deb3ec6SMatthias Ringwald     int pos = de_get_header_size(element);
314*3deb3ec6SMatthias Ringwald     int end_pos = de_get_len(element);
315*3deb3ec6SMatthias Ringwald     while (pos < end_pos){
316*3deb3ec6SMatthias Ringwald         de_type_t idType = de_get_element_type(element + pos);
317*3deb3ec6SMatthias Ringwald         de_size_t idSize = de_get_size_type(element + pos);
318*3deb3ec6SMatthias Ringwald         if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type
319*3deb3ec6SMatthias Ringwald         uint16_t attribute_id = READ_NET_16(element, pos + 1);
320*3deb3ec6SMatthias Ringwald         pos += 3;
321*3deb3ec6SMatthias Ringwald         if (pos >= end_pos) break; // array out of bounds
322*3deb3ec6SMatthias Ringwald         de_type_t valueType = de_get_element_type(element + pos);
323*3deb3ec6SMatthias Ringwald         de_size_t valueSize = de_get_size_type(element + pos);
324*3deb3ec6SMatthias Ringwald         uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context);
325*3deb3ec6SMatthias Ringwald         if (done) break;
326*3deb3ec6SMatthias Ringwald         pos += de_get_len(element + pos);
327*3deb3ec6SMatthias Ringwald     }
328*3deb3ec6SMatthias Ringwald }
329*3deb3ec6SMatthias Ringwald 
330*3deb3ec6SMatthias Ringwald // MARK: AttributeID in AttributeIDList
331*3deb3ec6SMatthias Ringwald // attribute ID in AttributeIDList
332*3deb3ec6SMatthias Ringwald // context { result, attributeID }
333*3deb3ec6SMatthias Ringwald struct sdp_context_attributeID_search {
334*3deb3ec6SMatthias Ringwald     int result;
335*3deb3ec6SMatthias Ringwald     uint16_t attributeID;
336*3deb3ec6SMatthias Ringwald };
337*3deb3ec6SMatthias Ringwald static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
338*3deb3ec6SMatthias Ringwald     struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context;
339*3deb3ec6SMatthias Ringwald     if (type != DE_UINT) return 0;
340*3deb3ec6SMatthias Ringwald     switch (size) {
341*3deb3ec6SMatthias Ringwald         case DE_SIZE_16:
342*3deb3ec6SMatthias Ringwald             if (READ_NET_16(element, 1) == context->attributeID) {
343*3deb3ec6SMatthias Ringwald                 context->result = 1;
344*3deb3ec6SMatthias Ringwald                 return 1;
345*3deb3ec6SMatthias Ringwald             }
346*3deb3ec6SMatthias Ringwald             break;
347*3deb3ec6SMatthias Ringwald         case DE_SIZE_32:
348*3deb3ec6SMatthias Ringwald             if (READ_NET_16(element, 1) <= context->attributeID
349*3deb3ec6SMatthias Ringwald             &&  context->attributeID <= READ_NET_16(element, 3)) {
350*3deb3ec6SMatthias Ringwald                 context->result = 1;
351*3deb3ec6SMatthias Ringwald                 return 1;
352*3deb3ec6SMatthias Ringwald             }
353*3deb3ec6SMatthias Ringwald             break;
354*3deb3ec6SMatthias Ringwald         default:
355*3deb3ec6SMatthias Ringwald             break;
356*3deb3ec6SMatthias Ringwald     }
357*3deb3ec6SMatthias Ringwald     return 0;
358*3deb3ec6SMatthias Ringwald }
359*3deb3ec6SMatthias Ringwald 
360*3deb3ec6SMatthias Ringwald int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){
361*3deb3ec6SMatthias Ringwald     struct sdp_context_attributeID_search attributeID_search;
362*3deb3ec6SMatthias Ringwald     attributeID_search.result = 0;
363*3deb3ec6SMatthias Ringwald     attributeID_search.attributeID = attributeID;
364*3deb3ec6SMatthias Ringwald     de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search);
365*3deb3ec6SMatthias Ringwald     return attributeID_search.result;
366*3deb3ec6SMatthias Ringwald }
367*3deb3ec6SMatthias Ringwald 
368*3deb3ec6SMatthias Ringwald // MARK: Append Attributes for AttributeIDList
369*3deb3ec6SMatthias Ringwald // pre: buffer contains DES with 2 byte length field
370*3deb3ec6SMatthias Ringwald struct sdp_context_append_attributes {
371*3deb3ec6SMatthias Ringwald     uint8_t * buffer;
372*3deb3ec6SMatthias Ringwald     uint16_t startOffset;     // offset of when to start copying
373*3deb3ec6SMatthias Ringwald     uint16_t maxBytes;
374*3deb3ec6SMatthias Ringwald     uint16_t usedBytes;
375*3deb3ec6SMatthias Ringwald     uint8_t *attributeIDList;
376*3deb3ec6SMatthias Ringwald };
377*3deb3ec6SMatthias Ringwald 
378*3deb3ec6SMatthias Ringwald static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
379*3deb3ec6SMatthias Ringwald     struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context;
380*3deb3ec6SMatthias Ringwald     if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
381*3deb3ec6SMatthias Ringwald         // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute)
382*3deb3ec6SMatthias Ringwald         uint16_t data_size = READ_NET_16(context->buffer, 1);
383*3deb3ec6SMatthias Ringwald         int attribute_len = de_get_len(attributeValue);
384*3deb3ec6SMatthias Ringwald         if (3 + data_size + (3 + attribute_len) <= context->maxBytes) {
385*3deb3ec6SMatthias Ringwald             // copy Attribute
386*3deb3ec6SMatthias Ringwald             de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID);
387*3deb3ec6SMatthias Ringwald             data_size += 3; // 3 bytes
388*3deb3ec6SMatthias Ringwald             memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len);
389*3deb3ec6SMatthias Ringwald             net_store_16(context->buffer,1,data_size+attribute_len);
390*3deb3ec6SMatthias Ringwald         } else {
391*3deb3ec6SMatthias Ringwald             // not enought space left -> continue with previous element
392*3deb3ec6SMatthias Ringwald             return 1;
393*3deb3ec6SMatthias Ringwald         }
394*3deb3ec6SMatthias Ringwald     }
395*3deb3ec6SMatthias Ringwald     return 0;
396*3deb3ec6SMatthias Ringwald }
397*3deb3ec6SMatthias Ringwald 
398*3deb3ec6SMatthias Ringwald // maxBytes: maximal size of data element sequence
399*3deb3ec6SMatthias Ringwald uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){
400*3deb3ec6SMatthias Ringwald     struct sdp_context_append_attributes context;
401*3deb3ec6SMatthias Ringwald     context.buffer = buffer;
402*3deb3ec6SMatthias Ringwald     context.maxBytes = maxBytes;
403*3deb3ec6SMatthias Ringwald     context.usedBytes = 0;
404*3deb3ec6SMatthias Ringwald     context.startOffset = startOffset;
405*3deb3ec6SMatthias Ringwald     context.attributeIDList = attributeIDList;
406*3deb3ec6SMatthias Ringwald     sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context);
407*3deb3ec6SMatthias Ringwald     return context.usedBytes;
408*3deb3ec6SMatthias Ringwald }
409*3deb3ec6SMatthias Ringwald 
410*3deb3ec6SMatthias Ringwald // MARK: Filter attributes that match attribute list from startOffset and a max nr bytes
411*3deb3ec6SMatthias Ringwald struct sdp_context_filter_attributes {
412*3deb3ec6SMatthias Ringwald     uint8_t * buffer;
413*3deb3ec6SMatthias Ringwald     uint16_t startOffset;     // offset of when to start copying
414*3deb3ec6SMatthias Ringwald     uint16_t maxBytes;
415*3deb3ec6SMatthias Ringwald     uint16_t usedBytes;
416*3deb3ec6SMatthias Ringwald     uint8_t *attributeIDList;
417*3deb3ec6SMatthias Ringwald     int      complete;
418*3deb3ec6SMatthias Ringwald };
419*3deb3ec6SMatthias Ringwald 
420*3deb3ec6SMatthias Ringwald // copy data with given start offset and max bytes, returns OK if all data has been copied
421*3deb3ec6SMatthias Ringwald static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){
422*3deb3ec6SMatthias Ringwald     int ok = 1;
423*3deb3ec6SMatthias Ringwald     uint16_t remainder_len = len - context->startOffset;
424*3deb3ec6SMatthias Ringwald     if (context->maxBytes < remainder_len){
425*3deb3ec6SMatthias Ringwald         remainder_len = context->maxBytes;
426*3deb3ec6SMatthias Ringwald         ok = 0;
427*3deb3ec6SMatthias Ringwald     }
428*3deb3ec6SMatthias Ringwald     memcpy(context->buffer, &data[context->startOffset], remainder_len);
429*3deb3ec6SMatthias Ringwald     context->usedBytes += remainder_len;
430*3deb3ec6SMatthias Ringwald     context->buffer    += remainder_len;
431*3deb3ec6SMatthias Ringwald     context->maxBytes  -= remainder_len;
432*3deb3ec6SMatthias Ringwald     context->startOffset = 0;
433*3deb3ec6SMatthias Ringwald     return ok;
434*3deb3ec6SMatthias Ringwald }
435*3deb3ec6SMatthias Ringwald 
436*3deb3ec6SMatthias Ringwald static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
437*3deb3ec6SMatthias Ringwald     struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context;
438*3deb3ec6SMatthias Ringwald 
439*3deb3ec6SMatthias Ringwald     if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0;
440*3deb3ec6SMatthias Ringwald 
441*3deb3ec6SMatthias Ringwald     // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)}
442*3deb3ec6SMatthias Ringwald 
443*3deb3ec6SMatthias Ringwald     // handle Attribute ID
444*3deb3ec6SMatthias Ringwald     if (context->startOffset >= 3){
445*3deb3ec6SMatthias Ringwald         context->startOffset -= 3;
446*3deb3ec6SMatthias Ringwald     } else {
447*3deb3ec6SMatthias Ringwald         uint8_t idBuffer[3];
448*3deb3ec6SMatthias Ringwald         de_store_descriptor(idBuffer, DE_UINT,  DE_SIZE_16);
449*3deb3ec6SMatthias Ringwald         net_store_16(idBuffer,1,attributeID);
450*3deb3ec6SMatthias Ringwald 
451*3deb3ec6SMatthias Ringwald         int ok = spd_append_range(context, 3, idBuffer);
452*3deb3ec6SMatthias Ringwald         if (!ok) {
453*3deb3ec6SMatthias Ringwald             context->complete = 0;
454*3deb3ec6SMatthias Ringwald             return 1;
455*3deb3ec6SMatthias Ringwald         }
456*3deb3ec6SMatthias Ringwald     }
457*3deb3ec6SMatthias Ringwald 
458*3deb3ec6SMatthias Ringwald     // handle Attribute Value
459*3deb3ec6SMatthias Ringwald     int attribute_len = de_get_len(attributeValue);
460*3deb3ec6SMatthias Ringwald     if (context->startOffset >= attribute_len) {
461*3deb3ec6SMatthias Ringwald         context->startOffset -= attribute_len;
462*3deb3ec6SMatthias Ringwald         return 0;
463*3deb3ec6SMatthias Ringwald     }
464*3deb3ec6SMatthias Ringwald 
465*3deb3ec6SMatthias Ringwald     int ok = spd_append_range(context, attribute_len, attributeValue);
466*3deb3ec6SMatthias Ringwald     if (!ok) {
467*3deb3ec6SMatthias Ringwald         context->complete = 0;
468*3deb3ec6SMatthias Ringwald         return 1;
469*3deb3ec6SMatthias Ringwald     }
470*3deb3ec6SMatthias Ringwald     return 0;
471*3deb3ec6SMatthias Ringwald }
472*3deb3ec6SMatthias Ringwald 
473*3deb3ec6SMatthias Ringwald int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){
474*3deb3ec6SMatthias Ringwald 
475*3deb3ec6SMatthias Ringwald     struct sdp_context_filter_attributes context;
476*3deb3ec6SMatthias Ringwald     context.buffer = buffer;
477*3deb3ec6SMatthias Ringwald     context.maxBytes = maxBytes;
478*3deb3ec6SMatthias Ringwald     context.usedBytes = 0;
479*3deb3ec6SMatthias Ringwald     context.startOffset = startOffset;
480*3deb3ec6SMatthias Ringwald     context.attributeIDList = attributeIDList;
481*3deb3ec6SMatthias Ringwald     context.complete = 1;
482*3deb3ec6SMatthias Ringwald 
483*3deb3ec6SMatthias Ringwald     sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context);
484*3deb3ec6SMatthias Ringwald 
485*3deb3ec6SMatthias Ringwald     *usedBytes = context.usedBytes;
486*3deb3ec6SMatthias Ringwald     return context.complete;
487*3deb3ec6SMatthias Ringwald }
488*3deb3ec6SMatthias Ringwald 
489*3deb3ec6SMatthias Ringwald // MARK: Get sum of attributes matching attribute list
490*3deb3ec6SMatthias Ringwald struct sdp_context_get_filtered_size {
491*3deb3ec6SMatthias Ringwald     uint8_t *attributeIDList;
492*3deb3ec6SMatthias Ringwald     uint16_t size;
493*3deb3ec6SMatthias Ringwald };
494*3deb3ec6SMatthias Ringwald 
495*3deb3ec6SMatthias Ringwald static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
496*3deb3ec6SMatthias Ringwald     struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context;
497*3deb3ec6SMatthias Ringwald     if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
498*3deb3ec6SMatthias Ringwald         context->size += 3 + de_get_len(attributeValue);
499*3deb3ec6SMatthias Ringwald     }
500*3deb3ec6SMatthias Ringwald     return 0;
501*3deb3ec6SMatthias Ringwald }
502*3deb3ec6SMatthias Ringwald 
503*3deb3ec6SMatthias Ringwald int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){
504*3deb3ec6SMatthias Ringwald     struct sdp_context_get_filtered_size context;
505*3deb3ec6SMatthias Ringwald     context.size = 0;
506*3deb3ec6SMatthias Ringwald     context.attributeIDList = attributeIDList;
507*3deb3ec6SMatthias Ringwald     sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context);
508*3deb3ec6SMatthias Ringwald     return context.size;
509*3deb3ec6SMatthias Ringwald }
510*3deb3ec6SMatthias Ringwald 
511*3deb3ec6SMatthias Ringwald // MARK: Get AttributeValue for AttributeID
512*3deb3ec6SMatthias Ringwald // find attribute (ELEMENT) by ID
513*3deb3ec6SMatthias Ringwald struct sdp_context_attribute_by_id {
514*3deb3ec6SMatthias Ringwald     uint16_t  attributeID;
515*3deb3ec6SMatthias Ringwald     uint8_t * attributeValue;
516*3deb3ec6SMatthias Ringwald };
517*3deb3ec6SMatthias Ringwald static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
518*3deb3ec6SMatthias Ringwald     struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context;
519*3deb3ec6SMatthias Ringwald     if (attributeID == context->attributeID) {
520*3deb3ec6SMatthias Ringwald         context->attributeValue = attributeValue;
521*3deb3ec6SMatthias Ringwald         return 1;
522*3deb3ec6SMatthias Ringwald     }
523*3deb3ec6SMatthias Ringwald     return 0;
524*3deb3ec6SMatthias Ringwald }
525*3deb3ec6SMatthias Ringwald 
526*3deb3ec6SMatthias Ringwald uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){
527*3deb3ec6SMatthias Ringwald     struct sdp_context_attribute_by_id context;
528*3deb3ec6SMatthias Ringwald     context.attributeValue = NULL;
529*3deb3ec6SMatthias Ringwald     context.attributeID = attributeID;
530*3deb3ec6SMatthias Ringwald     sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context);
531*3deb3ec6SMatthias Ringwald     return context.attributeValue;
532*3deb3ec6SMatthias Ringwald }
533*3deb3ec6SMatthias Ringwald 
534*3deb3ec6SMatthias Ringwald // MARK: Set AttributeValue for AttributeID
535*3deb3ec6SMatthias Ringwald struct sdp_context_set_attribute_for_id {
536*3deb3ec6SMatthias Ringwald     uint16_t  attributeID;
537*3deb3ec6SMatthias Ringwald     uint32_t  attributeValue;
538*3deb3ec6SMatthias Ringwald     uint8_t   attributeFound;
539*3deb3ec6SMatthias Ringwald };
540*3deb3ec6SMatthias Ringwald static int sdp_traversal_set_attribute_for_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
541*3deb3ec6SMatthias Ringwald     struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context;
542*3deb3ec6SMatthias Ringwald     if (attributeID == context->attributeID) {
543*3deb3ec6SMatthias Ringwald         context->attributeFound = 1;
544*3deb3ec6SMatthias Ringwald         switch (size){
545*3deb3ec6SMatthias Ringwald             case DE_SIZE_8:
546*3deb3ec6SMatthias Ringwald                 if (attributeType != DE_NIL){
547*3deb3ec6SMatthias Ringwald                     attributeValue[1] = context->attributeValue;
548*3deb3ec6SMatthias Ringwald                 }
549*3deb3ec6SMatthias Ringwald                 break;
550*3deb3ec6SMatthias Ringwald             case DE_SIZE_16:
551*3deb3ec6SMatthias Ringwald                 net_store_16(attributeValue, 1, context->attributeValue);
552*3deb3ec6SMatthias Ringwald                 break;
553*3deb3ec6SMatthias Ringwald             case DE_SIZE_32:
554*3deb3ec6SMatthias Ringwald                 net_store_32(attributeValue, 1, context->attributeValue);
555*3deb3ec6SMatthias Ringwald                 break;
556*3deb3ec6SMatthias Ringwald                 // Might want to support STRINGS to, copy upto original length
557*3deb3ec6SMatthias Ringwald             default:
558*3deb3ec6SMatthias Ringwald                 break;
559*3deb3ec6SMatthias Ringwald         }
560*3deb3ec6SMatthias Ringwald         return 1;
561*3deb3ec6SMatthias Ringwald     }
562*3deb3ec6SMatthias Ringwald     return 0;
563*3deb3ec6SMatthias Ringwald }
564*3deb3ec6SMatthias Ringwald uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){
565*3deb3ec6SMatthias Ringwald     struct sdp_context_set_attribute_for_id context;
566*3deb3ec6SMatthias Ringwald     context.attributeID = attributeID;
567*3deb3ec6SMatthias Ringwald     context.attributeValue = value;
568*3deb3ec6SMatthias Ringwald     context.attributeFound = 0;
569*3deb3ec6SMatthias Ringwald     sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context);
570*3deb3ec6SMatthias Ringwald     return context.attributeFound;
571*3deb3ec6SMatthias Ringwald }
572*3deb3ec6SMatthias Ringwald 
573*3deb3ec6SMatthias Ringwald // MARK: ServiceRecord contains UUID
574*3deb3ec6SMatthias Ringwald // service record contains UUID
575*3deb3ec6SMatthias Ringwald // context { normalizedUUID }
576*3deb3ec6SMatthias Ringwald struct sdp_context_contains_uuid128 {
577*3deb3ec6SMatthias Ringwald     uint8_t * uuid128;
578*3deb3ec6SMatthias Ringwald     int result;
579*3deb3ec6SMatthias Ringwald };
580*3deb3ec6SMatthias Ringwald int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128);
581*3deb3ec6SMatthias Ringwald static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
582*3deb3ec6SMatthias Ringwald     struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context;
583*3deb3ec6SMatthias Ringwald     uint8_t normalizedUUID[16];
584*3deb3ec6SMatthias Ringwald     if (type == DE_UUID){
585*3deb3ec6SMatthias Ringwald         uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
586*3deb3ec6SMatthias Ringwald         context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0;
587*3deb3ec6SMatthias Ringwald     }
588*3deb3ec6SMatthias Ringwald     if (type == DE_DES){
589*3deb3ec6SMatthias Ringwald         context->result = sdp_record_contains_UUID128(element, context->uuid128);
590*3deb3ec6SMatthias Ringwald     }
591*3deb3ec6SMatthias Ringwald     return context->result;
592*3deb3ec6SMatthias Ringwald }
593*3deb3ec6SMatthias Ringwald int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){
594*3deb3ec6SMatthias Ringwald     struct sdp_context_contains_uuid128 context;
595*3deb3ec6SMatthias Ringwald     context.uuid128 = uuid128;
596*3deb3ec6SMatthias Ringwald     context.result = 0;
597*3deb3ec6SMatthias Ringwald     de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context);
598*3deb3ec6SMatthias Ringwald     return context.result;
599*3deb3ec6SMatthias Ringwald }
600*3deb3ec6SMatthias Ringwald 
601*3deb3ec6SMatthias Ringwald // MARK: ServiceRecord matches SearchServicePattern
602*3deb3ec6SMatthias Ringwald // if UUID in searchServicePattern is not found in record => false
603*3deb3ec6SMatthias Ringwald // context { result, record }
604*3deb3ec6SMatthias Ringwald struct sdp_context_match_pattern {
605*3deb3ec6SMatthias Ringwald     uint8_t * record;
606*3deb3ec6SMatthias Ringwald     int result;
607*3deb3ec6SMatthias Ringwald };
608*3deb3ec6SMatthias Ringwald 
609*3deb3ec6SMatthias Ringwald int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){
610*3deb3ec6SMatthias Ringwald     struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context;
611*3deb3ec6SMatthias Ringwald     uint8_t normalizedUUID[16];
612*3deb3ec6SMatthias Ringwald     uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
613*3deb3ec6SMatthias Ringwald     if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){
614*3deb3ec6SMatthias Ringwald         context->result = 0;
615*3deb3ec6SMatthias Ringwald         return 1;
616*3deb3ec6SMatthias Ringwald     }
617*3deb3ec6SMatthias Ringwald     return 0;
618*3deb3ec6SMatthias Ringwald }
619*3deb3ec6SMatthias Ringwald int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){
620*3deb3ec6SMatthias Ringwald     struct sdp_context_match_pattern context;
621*3deb3ec6SMatthias Ringwald     context.record = record;
622*3deb3ec6SMatthias Ringwald     context.result = 1;
623*3deb3ec6SMatthias Ringwald     de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context);
624*3deb3ec6SMatthias Ringwald     return context.result;
625*3deb3ec6SMatthias Ringwald }
626*3deb3ec6SMatthias Ringwald 
627*3deb3ec6SMatthias Ringwald // MARK: Dump DataElement
628*3deb3ec6SMatthias Ringwald // context { indent }
629*3deb3ec6SMatthias Ringwald #ifdef SDP_DES_DUMP
630*3deb3ec6SMatthias Ringwald static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){
631*3deb3ec6SMatthias Ringwald     int indent = *(int*) my_context;
632*3deb3ec6SMatthias Ringwald     int i;
633*3deb3ec6SMatthias Ringwald     for (i=0; i<indent;i++) printf("    ");
634*3deb3ec6SMatthias Ringwald     int pos     = de_get_header_size(element);
635*3deb3ec6SMatthias Ringwald     int end_pos = de_get_len(element);
636*3deb3ec6SMatthias Ringwald     printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos);
637*3deb3ec6SMatthias Ringwald     if (de_type == DE_DES) {
638*3deb3ec6SMatthias Ringwald 		printf("\n");
639*3deb3ec6SMatthias Ringwald         indent++;
640*3deb3ec6SMatthias Ringwald         de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent);
641*3deb3ec6SMatthias Ringwald     } else if (de_type == DE_UUID && de_size == DE_SIZE_128) {
642*3deb3ec6SMatthias Ringwald         printf(", value: ");
643*3deb3ec6SMatthias Ringwald         printUUID128(element+1);
644*3deb3ec6SMatthias Ringwald         printf("\n");
645*3deb3ec6SMatthias Ringwald     } else if (de_type == DE_STRING) {
646*3deb3ec6SMatthias Ringwald         int len = 0;
647*3deb3ec6SMatthias Ringwald         switch (de_size){
648*3deb3ec6SMatthias Ringwald             case DE_SIZE_VAR_8:
649*3deb3ec6SMatthias Ringwald                 len = element[1];
650*3deb3ec6SMatthias Ringwald                 break;
651*3deb3ec6SMatthias Ringwald             case DE_SIZE_VAR_16:
652*3deb3ec6SMatthias Ringwald                 len = READ_NET_16(element, 1);
653*3deb3ec6SMatthias Ringwald                 break;
654*3deb3ec6SMatthias Ringwald             default:
655*3deb3ec6SMatthias Ringwald                 break;
656*3deb3ec6SMatthias Ringwald         }
657*3deb3ec6SMatthias Ringwald         printf("len %u (0x%02x)\n", len, len);
658*3deb3ec6SMatthias Ringwald         printf_hexdump(&element[pos], len);
659*3deb3ec6SMatthias Ringwald     } else {
660*3deb3ec6SMatthias Ringwald         uint32_t value = 0;
661*3deb3ec6SMatthias Ringwald         switch (de_size) {
662*3deb3ec6SMatthias Ringwald             case DE_SIZE_8:
663*3deb3ec6SMatthias Ringwald                 if (de_type != DE_NIL){
664*3deb3ec6SMatthias Ringwald                     value = element[pos];
665*3deb3ec6SMatthias Ringwald                 }
666*3deb3ec6SMatthias Ringwald                 break;
667*3deb3ec6SMatthias Ringwald             case DE_SIZE_16:
668*3deb3ec6SMatthias Ringwald 				value = READ_NET_16(element,pos);
669*3deb3ec6SMatthias Ringwald                 break;
670*3deb3ec6SMatthias Ringwald             case DE_SIZE_32:
671*3deb3ec6SMatthias Ringwald 				value = READ_NET_32(element,pos);
672*3deb3ec6SMatthias Ringwald                 break;
673*3deb3ec6SMatthias Ringwald             default:
674*3deb3ec6SMatthias Ringwald                 break;
675*3deb3ec6SMatthias Ringwald         }
676*3deb3ec6SMatthias Ringwald         printf(", value: 0x%08" PRIx32 "\n", value);
677*3deb3ec6SMatthias Ringwald     }
678*3deb3ec6SMatthias Ringwald     return 0;
679*3deb3ec6SMatthias Ringwald }
680*3deb3ec6SMatthias Ringwald #endif
681*3deb3ec6SMatthias Ringwald 
682*3deb3ec6SMatthias Ringwald void de_dump_data_element(uint8_t * record){
683*3deb3ec6SMatthias Ringwald #ifdef SDP_DES_DUMP
684*3deb3ec6SMatthias Ringwald     int indent = 0;
685*3deb3ec6SMatthias Ringwald     // hack to get root DES, too.
686*3deb3ec6SMatthias Ringwald     de_type_t type = de_get_element_type(record);
687*3deb3ec6SMatthias Ringwald     de_size_t size = de_get_size_type(record);
688*3deb3ec6SMatthias Ringwald     de_traversal_dump_data(record, type, size, (void*) &indent);
689*3deb3ec6SMatthias Ringwald #endif
690*3deb3ec6SMatthias Ringwald }
691*3deb3ec6SMatthias Ringwald 
692*3deb3ec6SMatthias Ringwald void sdp_create_spp_service(uint8_t *service, int service_id, const char *name){
693*3deb3ec6SMatthias Ringwald 
694*3deb3ec6SMatthias Ringwald 	uint8_t* attribute;
695*3deb3ec6SMatthias Ringwald 	de_create_sequence(service);
696*3deb3ec6SMatthias Ringwald 
697*3deb3ec6SMatthias Ringwald     // 0x0000 "Service Record Handle"
698*3deb3ec6SMatthias Ringwald 	de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
699*3deb3ec6SMatthias Ringwald 	de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
700*3deb3ec6SMatthias Ringwald 
701*3deb3ec6SMatthias Ringwald 	// 0x0001 "Service Class ID List"
702*3deb3ec6SMatthias Ringwald 	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
703*3deb3ec6SMatthias Ringwald 	attribute = de_push_sequence(service);
704*3deb3ec6SMatthias Ringwald 	{
705*3deb3ec6SMatthias Ringwald 		de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1101 );
706*3deb3ec6SMatthias Ringwald 	}
707*3deb3ec6SMatthias Ringwald 	de_pop_sequence(service, attribute);
708*3deb3ec6SMatthias Ringwald 
709*3deb3ec6SMatthias Ringwald 	// 0x0004 "Protocol Descriptor List"
710*3deb3ec6SMatthias Ringwald 	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
711*3deb3ec6SMatthias Ringwald 	attribute = de_push_sequence(service);
712*3deb3ec6SMatthias Ringwald 	{
713*3deb3ec6SMatthias Ringwald 		uint8_t* l2cpProtocol = de_push_sequence(attribute);
714*3deb3ec6SMatthias Ringwald 		{
715*3deb3ec6SMatthias Ringwald 			de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol);
716*3deb3ec6SMatthias Ringwald 		}
717*3deb3ec6SMatthias Ringwald 		de_pop_sequence(attribute, l2cpProtocol);
718*3deb3ec6SMatthias Ringwald 
719*3deb3ec6SMatthias Ringwald 		uint8_t* rfcomm = de_push_sequence(attribute);
720*3deb3ec6SMatthias Ringwald 		{
721*3deb3ec6SMatthias Ringwald 			de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol);  // rfcomm_service
722*3deb3ec6SMatthias Ringwald 			de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  service_id);  // rfcomm channel
723*3deb3ec6SMatthias Ringwald 		}
724*3deb3ec6SMatthias Ringwald 		de_pop_sequence(attribute, rfcomm);
725*3deb3ec6SMatthias Ringwald 	}
726*3deb3ec6SMatthias Ringwald 	de_pop_sequence(service, attribute);
727*3deb3ec6SMatthias Ringwald 
728*3deb3ec6SMatthias Ringwald 	// 0x0005 "Public Browse Group"
729*3deb3ec6SMatthias Ringwald 	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
730*3deb3ec6SMatthias Ringwald 	attribute = de_push_sequence(service);
731*3deb3ec6SMatthias Ringwald 	{
732*3deb3ec6SMatthias Ringwald 		de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1002 );
733*3deb3ec6SMatthias Ringwald 	}
734*3deb3ec6SMatthias Ringwald 	de_pop_sequence(service, attribute);
735*3deb3ec6SMatthias Ringwald 
736*3deb3ec6SMatthias Ringwald 	// 0x0006
737*3deb3ec6SMatthias Ringwald 	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList);
738*3deb3ec6SMatthias Ringwald 	attribute = de_push_sequence(service);
739*3deb3ec6SMatthias Ringwald 	{
740*3deb3ec6SMatthias Ringwald 		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
741*3deb3ec6SMatthias Ringwald 		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
742*3deb3ec6SMatthias Ringwald 		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
743*3deb3ec6SMatthias Ringwald 	}
744*3deb3ec6SMatthias Ringwald 	de_pop_sequence(service, attribute);
745*3deb3ec6SMatthias Ringwald 
746*3deb3ec6SMatthias Ringwald 	// 0x0009 "Bluetooth Profile Descriptor List"
747*3deb3ec6SMatthias Ringwald 	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
748*3deb3ec6SMatthias Ringwald 	attribute = de_push_sequence(service);
749*3deb3ec6SMatthias Ringwald 	{
750*3deb3ec6SMatthias Ringwald 		uint8_t *sppProfile = de_push_sequence(attribute);
751*3deb3ec6SMatthias Ringwald 		{
752*3deb3ec6SMatthias Ringwald 			de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, 0x1101);
753*3deb3ec6SMatthias Ringwald 			de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0102);
754*3deb3ec6SMatthias Ringwald 		}
755*3deb3ec6SMatthias Ringwald 		de_pop_sequence(attribute, sppProfile);
756*3deb3ec6SMatthias Ringwald 	}
757*3deb3ec6SMatthias Ringwald 	de_pop_sequence(service, attribute);
758*3deb3ec6SMatthias Ringwald 
759*3deb3ec6SMatthias Ringwald 	// 0x0100 "ServiceName"
760*3deb3ec6SMatthias Ringwald 	de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
761*3deb3ec6SMatthias Ringwald 	de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
762*3deb3ec6SMatthias Ringwald }
763