BTstack Bluetooth stack

Dependencies:   mbed USBHost

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sdp.c Source File

sdp.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  * Implementation of the Service Discovery Protocol Server 
00039  */
00040 
00041 #include "sdp.h"
00042 
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 
00047 #include <btstack/sdp_util.h>
00048 
00049 #include "hci_dump.h"
00050 #include "l2cap.h"
00051 
00052 #include "debug.h"
00053 
00054 // max reserved ServiceRecordHandle
00055 #define maxReservedServiceRecordHandle 0xffff
00056 
00057 // max SDP response
00058 #define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
00059 
00060 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
00061 
00062 // registered service records
00063 static linked_list_t sdp_service_records = NULL;
00064 
00065 // our handles start after the reserved range
00066 static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2;
00067 
00068 static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE];
00069 
00070 static void (*app_packet_handler)(void * connection, uint8_t packet_type,
00071                                   uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
00072 
00073 static uint16_t l2cap_cid = 0;
00074 static uint16_t sdp_response_size = 0;
00075 
00076 void sdp_init(){
00077     // register with l2cap psm sevices - max MTU
00078     l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff);
00079 }
00080 
00081 // register packet handler
00082 void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
00083                                                  uint16_t channel, uint8_t *packet, uint16_t size)){
00084     app_packet_handler = handler;
00085     l2cap_cid = 0;
00086 }
00087 
00088 uint32_t sdp_get_service_record_handle(uint8_t * record){
00089     uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
00090     if (!serviceRecordHandleAttribute) return 0;
00091     if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
00092     if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
00093     return READ_NET_32(serviceRecordHandleAttribute, 1); 
00094 }
00095 
00096 // data: event(8), len(8), status(8), service_record_handle(32)
00097 static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) {
00098     if (!app_packet_handler) return;
00099     uint8_t event[7];
00100     event[0] = SDP_SERVICE_REGISTERED;
00101     event[1] = sizeof(event) - 2;
00102     event[2] = status;
00103     bt_store_32(event, 3, handle);
00104     hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
00105     (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
00106 }
00107 
00108 service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
00109     linked_item_t *it;
00110     for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
00111         service_record_item_t * item = (service_record_item_t *) it;
00112         if (item->service_record_handle == handle){
00113             return item;
00114         }
00115     }
00116     return NULL;
00117 }
00118 
00119 // get next free, unregistered service record handle
00120 uint32_t sdp_create_service_record_handle(void){
00121     uint32_t handle = 0;
00122     do {
00123         handle = sdp_next_service_record_handle++;
00124         if (sdp_get_record_for_handle(handle)) handle = 0;
00125     } while (handle == 0);
00126     return handle;
00127 }
00128 
00129 #ifdef EMBEDDED
00130 
00131 // register service record internally - this special version doesn't copy the record, it should not be freeed
00132 // pre: AttributeIDs are in ascending order
00133 // pre: ServiceRecordHandle is first attribute and valid
00134 // pre: record
00135 // @returns ServiceRecordHandle or 0 if registration failed
00136 uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){
00137     // get user record handle
00138     uint32_t record_handle = record_item->service_record_handle;
00139     // get actual record
00140     uint8_t *record = record_item->service_record;
00141     
00142     // check for ServiceRecordHandle attribute, returns pointer or null
00143     uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
00144     if (!req_record_handle) {
00145         log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n");
00146         return 0;
00147     }
00148     
00149     // validate service record handle is not in reserved range
00150     if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
00151     
00152     // check if already in use
00153     if (record_handle) {
00154         if (sdp_get_record_for_handle(record_handle)) {
00155             record_handle = 0;
00156         }
00157     }
00158     
00159     // create new handle if needed
00160     if (!record_handle){
00161         record_handle = sdp_create_service_record_handle();
00162         // Write the handle back into the record too
00163         record_item->service_record_handle = record_handle;
00164         sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle);
00165     }
00166     
00167     // add to linked list
00168     linked_list_add(&sdp_service_records, (linked_item_t *) record_item);
00169     
00170     sdp_emit_service_registered(connection, 0, record_item->service_record_handle);
00171     
00172     return record_handle;
00173 }
00174 
00175 #else
00176 
00177 // AttributeIDList used to remove ServiceRecordHandle
00178 static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
00179 
00180 // register service record internally - the normal version creates a copy of the record
00181 // pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
00182 // @returns ServiceRecordHandle or 0 if registration failed
00183 uint32_t sdp_register_service_internal(void *connection, uint8_t * record){
00184 
00185     // dump for now
00186     // printf("Register service record\n");
00187     // de_dump_data_element(record);
00188     
00189     // get user record handle
00190     uint32_t record_handle = sdp_get_service_record_handle(record);
00191 
00192     // validate service record handle is not in reserved range
00193     if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
00194     
00195     // check if already in use
00196     if (record_handle) {
00197         if (sdp_get_record_for_handle(record_handle)) {
00198             record_handle = 0;
00199         }
00200     }
00201     
00202     // create new handle if needed
00203     if (!record_handle){
00204         record_handle = sdp_create_service_record_handle();
00205     }
00206     
00207     // calculate size of new service record: DES (2 byte len) 
00208     // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
00209     uint16_t recordSize =  3 + (3 + 5) + de_get_data_size(record);
00210         
00211     // alloc memory for new service_record_item
00212     service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t));
00213     if (!newRecordItem) {
00214         sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED);
00215         return 0;
00216     }
00217     // link new service item to client connection
00218     newRecordItem->connection = connection;
00219     
00220     // set new handle
00221     newRecordItem->service_record_handle = record_handle;
00222 
00223     // create updated service record
00224     uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record);
00225     
00226     // create DES for new record
00227     de_create_sequence(newRecord);
00228     
00229     // set service record handle
00230     de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
00231     de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
00232     
00233     // add other attributes
00234     sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
00235     
00236     // dump for now
00237     // de_dump_data_element(newRecord);
00238     // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord));
00239     
00240     // add to linked list
00241     linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem);
00242     
00243     sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle);
00244 
00245     return record_handle;
00246 }
00247 
00248 #endif
00249 
00250 // unregister service record internally
00251 // 
00252 // makes sure one client cannot remove service records of other clients
00253 //
00254 void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){
00255     service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle);
00256     if (record_item && record_item->connection == connection) {
00257         linked_list_remove(&sdp_service_records, (linked_item_t *) record_item);
00258     }
00259 }
00260 
00261 // remove all service record for a client connection
00262 void sdp_unregister_services_for_connection(void *connection){
00263     linked_item_t *it = (linked_item_t *) &sdp_service_records;
00264     while (it->next){
00265         service_record_item_t *record_item = (service_record_item_t *) it->next;
00266         if (record_item->connection == connection){
00267             it->next = it->next->next;
00268 #ifndef EMBEDDED
00269             free(record_item);
00270 #endif
00271         } else {
00272             it = it->next;
00273         }
00274     }
00275 }
00276 
00277 // PDU
00278 // PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, ..
00279 
00280 int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){
00281     sdp_response_buffer[0] = SDP_ErrorResponse;
00282     net_store_16(sdp_response_buffer, 1, transaction_id);
00283     net_store_16(sdp_response_buffer, 3, 2);
00284     net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax
00285     return 7;
00286 }
00287 
00288 int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){
00289     
00290     // get request details
00291     uint16_t  transaction_id = READ_NET_16(packet, 1);
00292     // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
00293     uint8_t * serviceSearchPattern = &packet[5];
00294     uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
00295     uint16_t  maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
00296     uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2];
00297     
00298     // calc maxumumServiceRecordCount based on remote MTU
00299     uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4;
00300     
00301     // continuation state contains index of next service record to examine
00302     int      continuation = 0;
00303     uint16_t continuation_index = 0;
00304     if (continuationState[0] == 2){
00305         continuation_index = READ_NET_16(continuationState, 1);
00306     }
00307     
00308     // get and limit total count
00309     linked_item_t *it;
00310     uint16_t total_service_count   = 0;
00311     for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
00312         service_record_item_t * item = (service_record_item_t *) it;
00313         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
00314         total_service_count++;
00315     }
00316     if (total_service_count > maximumServiceRecordCount){
00317         total_service_count = maximumServiceRecordCount;
00318     }
00319     
00320     // ServiceRecordHandleList at 9
00321     uint16_t pos = 9;
00322     uint16_t current_service_count  = 0;
00323     uint16_t current_service_index  = 0;
00324     uint16_t matching_service_count = 0;
00325     for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){
00326         service_record_item_t * item = (service_record_item_t *) it;
00327 
00328         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
00329         matching_service_count++;
00330         
00331         if (current_service_index < continuation_index) continue;
00332 
00333         net_store_32(sdp_response_buffer, pos, item->service_record_handle);
00334         pos += 4;
00335         current_service_count++;
00336         
00337         if (matching_service_count >= total_service_count) break;
00338 
00339         if (current_service_count >= maxNrServiceRecordsPerResponse){
00340             continuation = 1;
00341             continuation_index = current_service_index + 1;
00342             break;
00343         }
00344     }
00345     
00346     // Store continuation state
00347     if (continuation) {
00348         sdp_response_buffer[pos++] = 2;
00349         net_store_16(sdp_response_buffer, pos, continuation_index);
00350         pos += 2;
00351     } else {
00352         sdp_response_buffer[pos++] = 0;
00353     }
00354 
00355     // header
00356     sdp_response_buffer[0] = SDP_ServiceSearchResponse;
00357     net_store_16(sdp_response_buffer, 1, transaction_id);
00358     net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
00359     net_store_16(sdp_response_buffer, 5, total_service_count);
00360     net_store_16(sdp_response_buffer, 7, current_service_count);
00361     
00362     return pos;
00363 }
00364 
00365 int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
00366     
00367     // get request details
00368     uint16_t  transaction_id = READ_NET_16(packet, 1);
00369     // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
00370     uint32_t  serviceRecordHandle = READ_NET_32(packet, 5);
00371     uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 9);
00372     uint8_t * attributeIDList = &packet[11];
00373     uint16_t  attributeIDListLen = de_get_len(attributeIDList);
00374     uint8_t * continuationState = &packet[11+attributeIDListLen];
00375     
00376     // calc maximumAttributeByteCount based on remote MTU
00377     uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3);
00378     if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
00379         maximumAttributeByteCount = maximumAttributeByteCount2;
00380     }
00381     
00382     // continuation state contains the offset into the complete response
00383     uint16_t continuation_offset = 0;
00384     if (continuationState[0] == 2){
00385         continuation_offset = READ_NET_16(continuationState, 1);
00386     }
00387     
00388     // get service record
00389     service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle);
00390     if (!item){
00391         // service record handle doesn't exist
00392         return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
00393     }
00394     
00395     
00396     // AttributeList - starts at offset 7
00397     uint16_t pos = 7;
00398     
00399     if (continuation_offset == 0){
00400         
00401         // get size of this record
00402         uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
00403         
00404         // store DES
00405         de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
00406         maximumAttributeByteCount -= 3;
00407         pos += 3;
00408     }
00409 
00410     // copy maximumAttributeByteCount from record
00411     uint16_t bytes_used;
00412     int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
00413     pos += bytes_used;
00414     
00415     uint16_t attributeListByteCount = pos - 7;
00416 
00417     if (complete) {
00418         sdp_response_buffer[pos++] = 0;
00419     } else {
00420         continuation_offset += bytes_used;
00421         sdp_response_buffer[pos++] = 2;
00422         net_store_16(sdp_response_buffer, pos, continuation_offset);
00423         pos += 2;
00424     }
00425 
00426     // header
00427     sdp_response_buffer[0] = SDP_ServiceAttributeResponse;
00428     net_store_16(sdp_response_buffer, 1, transaction_id);
00429     net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
00430     net_store_16(sdp_response_buffer, 5, attributeListByteCount); 
00431     
00432     return pos;
00433 }
00434 
00435 static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){
00436     uint16_t total_response_size = 0;
00437     linked_item_t *it;
00438     for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
00439         service_record_item_t * item = (service_record_item_t *) it;
00440         
00441         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
00442         
00443         // for all service records that match
00444         total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList);
00445     }
00446     return total_response_size;
00447 }
00448 
00449 int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){
00450     
00451     // SDP header before attribute sevice list: 7
00452     // Continuation, worst case: 5
00453     
00454     // get request details
00455     uint16_t  transaction_id = READ_NET_16(packet, 1);
00456     // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
00457     uint8_t * serviceSearchPattern = &packet[5];
00458     uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
00459     uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
00460     uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2];
00461     uint16_t  attributeIDListLen = de_get_len(attributeIDList);
00462     uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen];
00463     
00464     // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block
00465     uint16_t maximumAttributeByteCount2 = remote_mtu - 12;
00466     if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
00467         maximumAttributeByteCount = maximumAttributeByteCount2;
00468     }
00469     
00470     // continuation state contains: index of next service record to examine
00471     // continuation state contains: byte offset into this service record
00472     uint16_t continuation_service_index = 0;
00473     uint16_t continuation_offset = 0;
00474     if (continuationState[0] == 4){
00475         continuation_service_index = READ_NET_16(continuationState, 1);
00476         continuation_offset = READ_NET_16(continuationState, 3);
00477     }
00478 
00479     // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount);
00480     
00481     // AttributeLists - starts at offset 7
00482     uint16_t pos = 7;
00483     
00484     // add DES with total size for first request
00485     if (continuation_service_index == 0 && continuation_offset == 0){
00486         uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList);
00487         de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size);
00488         // log_info("total response size %u\n", total_response_size);
00489         pos += 3;
00490         maximumAttributeByteCount -= 3;
00491     }
00492     
00493     // create attribute list
00494     int      first_answer = 1;
00495     int      continuation = 0;
00496     uint16_t current_service_index = 0;
00497     linked_item_t *it = (linked_item_t *) sdp_service_records;
00498     for ( ; it ; it = it->next, ++current_service_index){
00499         service_record_item_t * item = (service_record_item_t *) it;
00500         
00501         if (current_service_index < continuation_service_index ) continue;
00502         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
00503 
00504         if (continuation_offset == 0){
00505             
00506             // get size of this record
00507             uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
00508             
00509             // stop if complete record doesn't fits into response but we already have a partial response
00510             if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) {
00511                 continuation = 1;
00512                 break;
00513             }
00514             
00515             // store DES
00516             de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
00517             pos += 3;
00518             maximumAttributeByteCount -= 3;
00519         }
00520         
00521         first_answer = 0;
00522     
00523         // copy maximumAttributeByteCount from record
00524         uint16_t bytes_used;
00525         int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
00526         pos += bytes_used;
00527         maximumAttributeByteCount -= bytes_used;
00528         
00529         if (complete) {
00530             continuation_offset = 0;
00531             continue;
00532         }
00533         
00534         continuation = 1;
00535         continuation_offset += bytes_used;
00536         break;
00537     }
00538     
00539     uint16_t attributeListsByteCount = pos - 7;
00540     
00541     // Continuation State
00542     if (continuation){
00543         sdp_response_buffer[pos++] = 4;
00544         net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index);
00545         pos += 2;
00546         net_store_16(sdp_response_buffer, pos, continuation_offset);
00547         pos += 2;
00548     } else {
00549         // complete
00550         sdp_response_buffer[pos++] = 0;
00551     }
00552         
00553     // create SDP header
00554     sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse;
00555     net_store_16(sdp_response_buffer, 1, transaction_id);
00556     net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
00557     net_store_16(sdp_response_buffer, 5, attributeListsByteCount);
00558     
00559     return pos;
00560 }
00561 
00562 static void sdp_try_respond(void){
00563     if (!sdp_response_size ) return;
00564     if (!l2cap_cid) return;
00565     if (!l2cap_can_send_packet_now(l2cap_cid)) return;
00566     
00567     // update state before sending packet (avoid getting called when new l2cap credit gets emitted)
00568     uint16_t size = sdp_response_size;
00569     sdp_response_size = 0;
00570     l2cap_send_internal(l2cap_cid, sdp_response_buffer, size);
00571 }
00572 
00573 // we assume that we don't get two requests in a row
00574 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
00575     uint16_t transaction_id;
00576     SDP_PDU_ID_t pdu_id;
00577     uint16_t remote_mtu;
00578     // uint16_t param_len;
00579     
00580     switch (packet_type) {
00581             
00582         case L2CAP_DATA_PACKET:
00583             pdu_id = (SDP_PDU_ID_t) packet[0];
00584             transaction_id = READ_NET_16(packet, 1);
00585             // param_len = READ_NET_16(packet, 3);
00586             remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel);
00587             // account for our buffer
00588             if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){
00589                 remote_mtu = SDP_RESPONSE_BUFFER_SIZE;
00590             }
00591             
00592             // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu);
00593             switch (pdu_id){
00594                     
00595                 case SDP_ServiceSearchRequest:
00596                     sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu);
00597                     break;
00598                                         
00599                 case SDP_ServiceAttributeRequest:
00600                     sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu);
00601                     break;
00602                     
00603                 case SDP_ServiceSearchAttributeRequest:
00604                     sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu);
00605                     break;
00606                     
00607                 default:
00608                     sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax
00609                     break;
00610             }
00611             
00612             sdp_try_respond();
00613             
00614             break;
00615             
00616         case HCI_EVENT_PACKET:
00617             
00618             switch (packet[0]) {
00619 
00620                 case L2CAP_EVENT_INCOMING_CONNECTION:
00621                     if (l2cap_cid) {
00622                         // CONNECTION REJECTED DUE TO LIMITED RESOURCES 
00623                         l2cap_decline_connection_internal(channel, 0x0d);
00624                         break;
00625                     }
00626                     // accept
00627                     l2cap_cid = channel;
00628                     sdp_response_size = 0;
00629                     l2cap_accept_connection_internal(channel);
00630                     break;
00631                     
00632                 case L2CAP_EVENT_CHANNEL_OPENED:
00633                     if (packet[2]) {
00634                         // open failed -> reset
00635                         l2cap_cid = 0;
00636                     }
00637                     break;
00638 
00639                 case L2CAP_EVENT_CREDITS:
00640                 case DAEMON_EVENT_HCI_PACKET_SENT:
00641                     sdp_try_respond();
00642                     break;
00643                 
00644                 case L2CAP_EVENT_CHANNEL_CLOSED:
00645                     if (channel == l2cap_cid){
00646                         // reset
00647                         l2cap_cid = 0;
00648                     }
00649                     break;
00650                                         
00651                 default:
00652                     // other event
00653                     break;
00654             }
00655             break;
00656             
00657         default:
00658             // other packet type
00659             break;
00660     }
00661 }
00662