BTstack for Nucleo F401RE/FRDM-KL46Z example program

Dependencies:   F401RE-USBHost mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sdp_util.c Source File

sdp_util.c

00001 /*
00002  * Copyright (C) 2009-2012 by Matthias Ringwald
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  * 4. Any redistribution, use, or modification is done solely for
00017  *    personal benefit and not for any commercial purpose or for
00018  *    monetary gain.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
00024  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * Please inquire about commercial licensing options at btstack@ringwald.ch
00034  *
00035  */
00036 
00037 /*
00038  *  sdp_util.c
00039  */
00040 
00041 #include <btstack/sdp_util.h>
00042 #include <btstack/utils.h>
00043 
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <string.h>
00047 #include <stdint.h>
00048 #include <inttypes.h>   // PRIx32
00049 
00050 // workaround for missing PRIx32 on mspgcc (16-bit MCU)
00051 #ifndef PRIx32
00052 #warning Using own: #define PRIx32 "lx"
00053 #define PRIx32 "lx"
00054 #endif
00055 
00056 // date element type names
00057 const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"};
00058 
00059 // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
00060 const uint8_t sdp_bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
00061     0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
00062 
00063 void sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID){
00064     memcpy(uuid, sdp_bluetooth_base_uuid, 16);
00065     net_store_32(uuid, 0, shortUUID);
00066 }
00067 
00068 // MARK: DataElement getter
00069 de_size_t de_get_size_type(uint8_t *header){
00070     return (de_size_t) (header[0] & 7);
00071 }
00072 
00073 de_type_t de_get_element_type(uint8_t *header){
00074     return (de_type_t) (header[0] >> 3);
00075 }
00076 
00077 int de_get_header_size(uint8_t * header){
00078     de_size_t de_size = de_get_size_type(header);
00079     if (de_size <= DE_SIZE_128) {
00080         return 1;
00081     }
00082     return 1 + (1 << (de_size-DE_SIZE_VAR_8));
00083 }
00084 
00085 int de_get_data_size(uint8_t * header){
00086     uint32_t result = 0;
00087     de_type_t de_type = de_get_element_type(header);
00088     de_size_t de_size = de_get_size_type(header);
00089     switch (de_size){
00090         case DE_SIZE_VAR_8:
00091             result = header[1];
00092             break;
00093         case DE_SIZE_VAR_16:
00094             result = READ_NET_16(header,1);
00095             break;
00096         case DE_SIZE_VAR_32:
00097             result = READ_NET_32(header,1);
00098             break;
00099         default:
00100         // case DE_SIZE_8:
00101         // case DE_SIZE_16:
00102         // case DE_SIZE_32:
00103         // case DE_SIZE_64:
00104         // case DE_SIZE_128:
00105             if (de_type == DE_NIL) return 0;
00106             return 1 << de_size;
00107     }
00108     return result;    
00109 }
00110 
00111 int de_get_len(uint8_t *header){
00112     return de_get_header_size(header) + de_get_data_size(header); 
00113 }
00114 
00115 // @returns: element is valid UUID
00116 int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
00117     de_type_t uuidType = de_get_element_type(element);
00118     de_size_t uuidSize = de_get_size_type(element);
00119     if (uuidType != DE_UUID) return 0;
00120     uint32_t shortUUID;
00121     switch (uuidSize){
00122         case DE_SIZE_16:
00123             shortUUID = READ_NET_16(element, 1);
00124             break;
00125         case DE_SIZE_32:
00126             shortUUID = READ_NET_32(element, 1);
00127             break;
00128         case DE_SIZE_128:
00129             memcpy(uuid128, element+1, 16);
00130             return 1;
00131         default:
00132             return 0;
00133     }
00134     sdp_normalize_uuid(uuid128, shortUUID);
00135     return 1;
00136 }
00137 
00138 // functions to create record
00139 static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){
00140     header[0] = (type << 3) | size; 
00141 }
00142 
00143 void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){
00144     header[0] = (type << 3) | size; 
00145     switch (size){
00146         case DE_SIZE_VAR_8:
00147             header[1] = len;
00148             break;
00149         case DE_SIZE_VAR_16:
00150             net_store_16(header, 1, len);
00151             break;
00152         case DE_SIZE_VAR_32:
00153             net_store_32(header, 1, len);
00154             break;
00155         default:
00156             break;
00157     }
00158 }
00159 
00160 // MARK: DataElement creation
00161 
00162 /* starts a new sequence in empty buffer - first call */
00163 void de_create_sequence(uint8_t *header){
00164     de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
00165 };
00166 
00167 /* starts a sub-sequence, @returns handle for sub-sequence */
00168 uint8_t * de_push_sequence(uint8_t *header){
00169     int element_len = de_get_len(header);
00170     de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
00171     return header + element_len;
00172 }
00173 
00174 /* closes the current sequence and updates the parent sequence */
00175 void de_pop_sequence(uint8_t * parent, uint8_t * child){
00176     int child_len = de_get_len(child);
00177     int data_size_parent = READ_NET_16(parent,1);
00178     net_store_16(parent, 1, data_size_parent + child_len);
00179 }
00180 
00181 /* adds a single number value and 16+32 bit UUID to the sequence */
00182 void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){
00183     int data_size   = READ_NET_16(seq,1);
00184     int element_size = 1;   // e.g. for DE_TYPE_NIL
00185     de_store_descriptor(seq+3+data_size, type, size); 
00186     switch (size){
00187         case DE_SIZE_8:
00188             if (type != DE_NIL){
00189                 seq[4+data_size] = value;
00190                 element_size = 2;
00191             }
00192             break;
00193         case DE_SIZE_16:
00194             net_store_16(seq, 4+data_size, value);
00195             element_size = 3;
00196             break;
00197         case DE_SIZE_32:
00198             net_store_32(seq, 4+data_size, value);
00199             element_size = 5;
00200             break;
00201         default:
00202             break;
00203     }
00204     net_store_16(seq, 1, data_size+element_size);
00205 }
00206 
00207 /* add a single block of data, e.g. as DE_STRING, DE_URL */
00208 void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){
00209     int data_size   = READ_NET_16(seq,1);
00210     if (size > 0xff) {
00211         // use 16-bit lengh information (3 byte header)
00212         de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size); 
00213         data_size += 3;
00214     } else {
00215         // use 8-bit lengh information (2 byte header)
00216         de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size); 
00217         data_size += 2;
00218     }
00219     memcpy( seq + 3 + data_size, data, size);
00220     data_size += size;
00221     net_store_16(seq, 1, data_size);
00222 }
00223 
00224 void de_add_uuid128(uint8_t * seq, uint8_t * uuid){
00225     int data_size   = READ_NET_16(seq,1);
00226     de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128); 
00227     memcpy( seq + 4 + data_size, uuid, 16);
00228     net_store_16(seq, 1, data_size+1+16);
00229 }
00230 
00231 void sdp_add_attribute(uint8_t *seq, uint16_t attributeID, uint8_t attributeValue){
00232 }
00233 
00234 // MARK: DataElementSequence traversal
00235 typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context);
00236 static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){
00237     de_type_t type = de_get_element_type(element);
00238     if (type != DE_DES) return;
00239     int pos = de_get_header_size(element);
00240     int end_pos = de_get_len(element);
00241     while (pos < end_pos){
00242         de_type_t elemType = de_get_element_type(element + pos);
00243         de_size_t elemSize = de_get_size_type(element + pos);
00244         uint8_t done = (*handler)(element + pos, elemType, elemSize, context); 
00245         if (done) break;
00246         pos += de_get_len(element + pos);
00247     }
00248 }
00249 
00250 // MARK: AttributeList traversal
00251 typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context);
00252 static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){
00253     de_type_t type = de_get_element_type(element);
00254     if (type != DE_DES) return;
00255     int pos = de_get_header_size(element);
00256     int end_pos = de_get_len(element);
00257     while (pos < end_pos){
00258         de_type_t idType = de_get_element_type(element + pos);
00259         de_size_t idSize = de_get_size_type(element + pos);
00260         if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type
00261         uint16_t attribute_id = READ_NET_16(element, pos + 1);
00262         pos += 3;
00263         if (pos >= end_pos) break; // array out of bounds
00264         de_type_t valueType = de_get_element_type(element + pos);
00265         de_size_t valueSize = de_get_size_type(element + pos);
00266         uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context); 
00267         if (done) break;
00268         pos += de_get_len(element + pos);
00269     }
00270 }
00271 
00272 // MARK: AttributeID in AttributeIDList 
00273 // attribute ID in AttributeIDList
00274 // context { result, attributeID }
00275 struct sdp_context_attributeID_search {
00276     int result;
00277     uint16_t attributeID;
00278 };
00279 static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
00280     struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context;
00281     if (type != DE_UINT) return 0;
00282     switch (size) {
00283         case DE_SIZE_16:
00284             if (READ_NET_16(element, 1) == context->attributeID) {
00285                 context->result = 1;
00286                 return 1;
00287             }
00288             break;
00289         case DE_SIZE_32:
00290             if (READ_NET_16(element, 1) <= context->attributeID
00291             &&  context->attributeID <= READ_NET_16(element, 3)) {
00292                 context->result = 1;
00293                 return 1;
00294             }
00295             break;
00296         default:
00297             break;
00298     }
00299     return 0;
00300 }
00301 int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){
00302     struct sdp_context_attributeID_search attributeID_search;
00303     attributeID_search.result = 0;
00304     attributeID_search.attributeID = attributeID;
00305     de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search);
00306     return attributeID_search.result;
00307 }
00308 
00309 // MARK: Append Attributes for AttributeIDList
00310 // pre: buffer contains DES with 2 byte length field
00311 struct sdp_context_append_attributes {
00312     uint8_t * buffer;
00313     uint16_t startOffset;     // offset of when to start copying
00314     uint16_t maxBytes;
00315     uint16_t usedBytes;
00316     uint8_t *attributeIDList;
00317 };
00318 
00319 static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
00320     struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context;
00321     if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
00322         // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute)
00323         uint16_t data_size = READ_NET_16(context->buffer, 1);
00324         int attribute_len = de_get_len(attributeValue);
00325         if (3 + data_size + (3 + attribute_len) <= context->maxBytes) {
00326             // copy Attribute
00327             de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID);   
00328             data_size += 3; // 3 bytes
00329             memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len);
00330             net_store_16(context->buffer,1,data_size+attribute_len);
00331         } else {
00332             // not enought space left -> continue with previous element
00333             return 1;
00334         }
00335     }
00336     return 0;
00337 }
00338 
00339 // maxBytes: maximal size of data element sequence
00340 uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){
00341     struct sdp_context_append_attributes context;
00342     context.buffer = buffer;
00343     context.maxBytes = maxBytes;
00344     context.usedBytes = 0;
00345     context.startOffset = startOffset;
00346     context.attributeIDList = attributeIDList;
00347     sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context);
00348     return context.usedBytes;
00349 }
00350 
00351 // MARK: Filter attributes that match attribute list from startOffset and a max nr bytes
00352 struct sdp_context_filter_attributes {
00353     uint8_t * buffer;
00354     uint16_t startOffset;     // offset of when to start copying
00355     uint16_t maxBytes;
00356     uint16_t usedBytes;
00357     uint8_t *attributeIDList;
00358     int      complete;
00359 };
00360 
00361 // copy data with given start offset and max bytes, returns OK if all data has been copied
00362 static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){
00363     int ok = 1;
00364     uint16_t remainder_len = len - context->startOffset;
00365     if (context->maxBytes < remainder_len){
00366         remainder_len = context->maxBytes;
00367         ok = 0;
00368     }
00369     memcpy(context->buffer, &data[context->startOffset], remainder_len);
00370     context->usedBytes += remainder_len;
00371     context->buffer    += remainder_len;
00372     context->maxBytes  -= remainder_len;
00373     context->startOffset = 0;
00374     return ok;
00375 }
00376 
00377 static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
00378     struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context;
00379 
00380     if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0;
00381 
00382     // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)}
00383 
00384     // handle Attribute ID
00385     if (context->startOffset >= 3){
00386         context->startOffset -= 3;
00387     } else {
00388         uint8_t idBuffer[3];
00389         de_store_descriptor(idBuffer, DE_UINT,  DE_SIZE_16);
00390         net_store_16(idBuffer,1,attributeID);
00391         
00392         int ok = spd_append_range(context, 3, idBuffer);
00393         if (!ok) {
00394             context->complete = 0;
00395             return 1;
00396         }
00397     }
00398     
00399     // handle Attribute Value
00400     int attribute_len = de_get_len(attributeValue);
00401     if (context->startOffset >= attribute_len) {
00402         context->startOffset -= attribute_len;
00403         return 0;
00404     }
00405     
00406     int ok = spd_append_range(context, attribute_len, attributeValue);
00407     if (!ok) {
00408         context->complete = 0;
00409         return 1;
00410     }
00411     return 0;
00412 }
00413 
00414 int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){
00415 
00416     struct sdp_context_filter_attributes context;
00417     context.buffer = buffer;
00418     context.maxBytes = maxBytes;
00419     context.usedBytes = 0;
00420     context.startOffset = startOffset;
00421     context.attributeIDList = attributeIDList;
00422     context.complete = 1;
00423 
00424     sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context);
00425 
00426     *usedBytes = context.usedBytes;
00427     return context.complete;
00428 }
00429 
00430 // MARK: Get sum of attributes matching attribute list
00431 struct sdp_context_get_filtered_size {
00432     uint8_t *attributeIDList;
00433     uint16_t size;
00434 };
00435 
00436 static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
00437     struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context;
00438     if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
00439         context->size += 3 + de_get_len(attributeValue);
00440     }
00441     return 0;
00442 }
00443 
00444 int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){
00445     struct sdp_context_get_filtered_size context;
00446     context.size = 0;
00447     context.attributeIDList = attributeIDList;
00448     sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context);
00449     return context.size;
00450 }
00451 
00452 // MARK: Get AttributeValue for AttributeID
00453 // find attribute (ELEMENT) by ID
00454 struct sdp_context_attribute_by_id {
00455     uint16_t  attributeID;
00456     uint8_t * attributeValue;
00457 };
00458 static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
00459     struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context;
00460     if (attributeID == context->attributeID) {
00461         context->attributeValue = attributeValue;
00462         return 1;
00463     }
00464     return 0;
00465 }
00466 
00467 uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){
00468     struct sdp_context_attribute_by_id context;
00469     context.attributeValue = NULL;
00470     context.attributeID = attributeID;
00471     sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context);
00472     return context.attributeValue;
00473 }
00474 
00475 // MARK: Set AttributeValue for AttributeID
00476 struct sdp_context_set_attribute_for_id {
00477     uint16_t  attributeID;
00478     uint32_t  attributeValue;
00479     uint8_t   attributeFound;
00480 };
00481 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){
00482     struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context;
00483     if (attributeID == context->attributeID) {
00484         context->attributeFound = 1;
00485         switch (size){
00486             case DE_SIZE_8:
00487                 if (attributeType != DE_NIL){
00488                     attributeValue[1] = context->attributeValue;
00489                 }
00490                 break;
00491             case DE_SIZE_16:
00492                 net_store_16(attributeValue, 1, context->attributeValue);
00493                 break;
00494             case DE_SIZE_32:
00495                 net_store_32(attributeValue, 1, context->attributeValue);
00496                 break;
00497                 // Might want to support STRINGS to, copy upto original length
00498             default:
00499                 break;
00500         }        
00501         return 1;
00502     }
00503     return 0;
00504 }
00505 uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){
00506     struct sdp_context_set_attribute_for_id context;
00507     context.attributeID = attributeID;
00508     context.attributeValue = value;
00509     context.attributeFound = 0;
00510     sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context);
00511     return context.attributeFound;
00512 }
00513 
00514 // MARK: ServiceRecord contains UUID
00515 // service record contains UUID
00516 // context { normalizedUUID }
00517 struct sdp_context_contains_uuid128 {
00518     uint8_t * uuid128;
00519     int result;
00520 };
00521 int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128);
00522 static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
00523     struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context;
00524     uint8_t normalizedUUID[16];
00525     if (type == DE_UUID){
00526         uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
00527         context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0;
00528     }
00529     if (type == DE_DES){
00530         context->result = sdp_record_contains_UUID128(element, context->uuid128);
00531     }
00532     return context->result;
00533 }
00534 int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){
00535     struct sdp_context_contains_uuid128 context;
00536     context.uuid128 = uuid128;
00537     context.result = 0;
00538     de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context);
00539     return context.result;
00540 }
00541     
00542 // MARK: ServiceRecord matches SearchServicePattern
00543 // if UUID in searchServicePattern is not found in record => false
00544 // context { result, record }
00545 struct sdp_context_match_pattern {
00546     uint8_t * record;
00547     int result;
00548 };
00549 int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){
00550     struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context;
00551     uint8_t normalizedUUID[16];
00552     uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
00553     if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){
00554         context->result = 0;
00555         return 1;
00556     }
00557     return 0;
00558 }
00559 int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){
00560     struct sdp_context_match_pattern context;
00561     context.record = record;
00562     context.result = 1;
00563     de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context);
00564     return context.result;
00565 }
00566 
00567 // MARK: Dump DataElement
00568 // context { indent }
00569 static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){
00570     int indent = *(int*) my_context;
00571     int i;
00572     for (i=0; i<indent;i++) printf("    ");
00573     int pos     = de_get_header_size(element);
00574     int end_pos = de_get_len(element);
00575     printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos);
00576     if (de_type == DE_DES) {
00577         printf("\n");
00578         indent++;
00579         de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent);
00580     } else if (de_type == DE_UUID && de_size == DE_SIZE_128) {
00581         printf(", value: ");
00582         printUUID(element+1);
00583         printf("\n");
00584     } else if (de_type == DE_STRING) {
00585         int len = 0;
00586         switch (de_size){
00587             case DE_SIZE_VAR_8:
00588                 len = element[1];
00589                 break;
00590             case DE_SIZE_VAR_16:
00591                 len = READ_NET_16(element, 1);
00592                 break;
00593             default:
00594                 break;
00595         }
00596         printf("len %u (0x%02x)\n", len, len);
00597         hexdump(&element[pos], len);
00598     } else {
00599         uint32_t value = 0;
00600         switch (de_size) {
00601             case DE_SIZE_8:
00602                 if (de_type != DE_NIL){
00603                     value = element[pos];
00604                 }
00605                 break;
00606             case DE_SIZE_16:
00607                 value = READ_NET_16(element,pos);
00608                 break;
00609             case DE_SIZE_32:
00610                 value = READ_NET_32(element,pos);
00611                 break;
00612             default:
00613                 break;
00614         }
00615         printf(", value: 0x%08" PRIx32 "\n", value);
00616     }
00617     return 0;
00618 }
00619 
00620 void de_dump_data_element(uint8_t * record){
00621     int indent = 0;
00622     // hack to get root DES, too.
00623     de_type_t type = de_get_element_type(record);
00624     de_size_t size = de_get_size_type(record);
00625     de_traversal_dump_data(record, type, size, (void*) &indent);
00626 }
00627 
00628 void sdp_create_spp_service(uint8_t *service, int service_id, const char *name){
00629     
00630     uint8_t* attribute;
00631     de_create_sequence(service);
00632     
00633     // 0x0000 "Service Record Handle"
00634     de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
00635     de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
00636     
00637     // 0x0001 "Service Class ID List"
00638     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
00639     attribute = de_push_sequence(service);
00640     {
00641         de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1101 );
00642     }
00643     de_pop_sequence(service, attribute);
00644     
00645     // 0x0004 "Protocol Descriptor List"
00646     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
00647     attribute = de_push_sequence(service);
00648     {
00649         uint8_t* l2cpProtocol = de_push_sequence(attribute);
00650         {
00651             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, 0x0100);
00652         }
00653         de_pop_sequence(attribute, l2cpProtocol);
00654         
00655         uint8_t* rfcomm = de_push_sequence(attribute);
00656         {
00657             de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, 0x0003);  // rfcomm_service
00658             de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  service_id);  // rfcomm channel
00659         }
00660         de_pop_sequence(attribute, rfcomm);
00661     }
00662     de_pop_sequence(service, attribute);
00663     
00664     // 0x0005 "Public Browse Group"
00665     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
00666     attribute = de_push_sequence(service);
00667     {
00668         de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1002 );
00669     }
00670     de_pop_sequence(service, attribute);
00671     
00672     // 0x0006
00673     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList);
00674     attribute = de_push_sequence(service);
00675     {
00676         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
00677         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
00678         de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
00679     }
00680     de_pop_sequence(service, attribute);
00681     
00682     // 0x0009 "Bluetooth Profile Descriptor List"
00683     de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
00684     attribute = de_push_sequence(service);
00685     {
00686         uint8_t *sppProfile = de_push_sequence(attribute);
00687         {
00688             de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, 0x1101);
00689             de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0100);
00690         }
00691         de_pop_sequence(attribute, sppProfile);
00692     }
00693     de_pop_sequence(service, attribute);
00694     
00695     // 0x0100 "ServiceName"
00696     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
00697     de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
00698 }