うおーるぼっとをWiiリモコンでコントロールする新しいプログラムです。 以前のものより、Wiiリモコンが早く繋がる様になりました。 It is a program which controls A with the Wii remote. ※ A Bluetooth dongle and a Wii remote control are needed.

Dependencies:   USBHost mbed FATFileSystem mbed-rtos

Committer:
jksoft
Date:
Mon Jun 10 16:01:50 2013 +0000
Revision:
0:fccb789424fc
1.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jksoft 0:fccb789424fc 1 /*
jksoft 0:fccb789424fc 2 * Copyright (C) 2009-2012 by Matthias Ringwald
jksoft 0:fccb789424fc 3 *
jksoft 0:fccb789424fc 4 * Redistribution and use in source and binary forms, with or without
jksoft 0:fccb789424fc 5 * modification, are permitted provided that the following conditions
jksoft 0:fccb789424fc 6 * are met:
jksoft 0:fccb789424fc 7 *
jksoft 0:fccb789424fc 8 * 1. Redistributions of source code must retain the above copyright
jksoft 0:fccb789424fc 9 * notice, this list of conditions and the following disclaimer.
jksoft 0:fccb789424fc 10 * 2. Redistributions in binary form must reproduce the above copyright
jksoft 0:fccb789424fc 11 * notice, this list of conditions and the following disclaimer in the
jksoft 0:fccb789424fc 12 * documentation and/or other materials provided with the distribution.
jksoft 0:fccb789424fc 13 * 3. Neither the name of the copyright holders nor the names of
jksoft 0:fccb789424fc 14 * contributors may be used to endorse or promote products derived
jksoft 0:fccb789424fc 15 * from this software without specific prior written permission.
jksoft 0:fccb789424fc 16 * 4. Any redistribution, use, or modification is done solely for
jksoft 0:fccb789424fc 17 * personal benefit and not for any commercial purpose or for
jksoft 0:fccb789424fc 18 * monetary gain.
jksoft 0:fccb789424fc 19 *
jksoft 0:fccb789424fc 20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
jksoft 0:fccb789424fc 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
jksoft 0:fccb789424fc 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
jksoft 0:fccb789424fc 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
jksoft 0:fccb789424fc 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
jksoft 0:fccb789424fc 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
jksoft 0:fccb789424fc 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
jksoft 0:fccb789424fc 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
jksoft 0:fccb789424fc 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
jksoft 0:fccb789424fc 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
jksoft 0:fccb789424fc 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
jksoft 0:fccb789424fc 31 * SUCH DAMAGE.
jksoft 0:fccb789424fc 32 *
jksoft 0:fccb789424fc 33 * Please inquire about commercial licensing options at btstack@ringwald.ch
jksoft 0:fccb789424fc 34 *
jksoft 0:fccb789424fc 35 */
jksoft 0:fccb789424fc 36
jksoft 0:fccb789424fc 37 /*
jksoft 0:fccb789424fc 38 * Implementation of the Service Discovery Protocol Server
jksoft 0:fccb789424fc 39 */
jksoft 0:fccb789424fc 40
jksoft 0:fccb789424fc 41 #include "sdp.h"
jksoft 0:fccb789424fc 42
jksoft 0:fccb789424fc 43
jksoft 0:fccb789424fc 44 #include <stdio.h>
jksoft 0:fccb789424fc 45 #include <string.h>
jksoft 0:fccb789424fc 46
jksoft 0:fccb789424fc 47 #include <btstack/sdp_util.h>
jksoft 0:fccb789424fc 48
jksoft 0:fccb789424fc 49 #include "hci_dump.h"
jksoft 0:fccb789424fc 50 #include "l2cap.h"
jksoft 0:fccb789424fc 51
jksoft 0:fccb789424fc 52 #include "debug.h"
jksoft 0:fccb789424fc 53
jksoft 0:fccb789424fc 54 // max reserved ServiceRecordHandle
jksoft 0:fccb789424fc 55 #define maxReservedServiceRecordHandle 0xffff
jksoft 0:fccb789424fc 56
jksoft 0:fccb789424fc 57 // max SDP response
jksoft 0:fccb789424fc 58 #define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
jksoft 0:fccb789424fc 59
jksoft 0:fccb789424fc 60 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
jksoft 0:fccb789424fc 61
jksoft 0:fccb789424fc 62 // registered service records
jksoft 0:fccb789424fc 63 static linked_list_t sdp_service_records = NULL;
jksoft 0:fccb789424fc 64
jksoft 0:fccb789424fc 65 // our handles start after the reserved range
jksoft 0:fccb789424fc 66 static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2;
jksoft 0:fccb789424fc 67
jksoft 0:fccb789424fc 68 static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE];
jksoft 0:fccb789424fc 69
jksoft 0:fccb789424fc 70 static void (*app_packet_handler)(void * connection, uint8_t packet_type,
jksoft 0:fccb789424fc 71 uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
jksoft 0:fccb789424fc 72
jksoft 0:fccb789424fc 73 static uint16_t l2cap_cid = 0;
jksoft 0:fccb789424fc 74 static uint16_t sdp_response_size = 0;
jksoft 0:fccb789424fc 75
jksoft 0:fccb789424fc 76 void sdp_init(){
jksoft 0:fccb789424fc 77 // register with l2cap psm sevices - max MTU
jksoft 0:fccb789424fc 78 l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff);
jksoft 0:fccb789424fc 79 }
jksoft 0:fccb789424fc 80
jksoft 0:fccb789424fc 81 // register packet handler
jksoft 0:fccb789424fc 82 void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
jksoft 0:fccb789424fc 83 uint16_t channel, uint8_t *packet, uint16_t size)){
jksoft 0:fccb789424fc 84 app_packet_handler = handler;
jksoft 0:fccb789424fc 85 l2cap_cid = 0;
jksoft 0:fccb789424fc 86 }
jksoft 0:fccb789424fc 87
jksoft 0:fccb789424fc 88 uint32_t sdp_get_service_record_handle(uint8_t * record){
jksoft 0:fccb789424fc 89 uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
jksoft 0:fccb789424fc 90 if (!serviceRecordHandleAttribute) return 0;
jksoft 0:fccb789424fc 91 if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
jksoft 0:fccb789424fc 92 if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
jksoft 0:fccb789424fc 93 return READ_NET_32(serviceRecordHandleAttribute, 1);
jksoft 0:fccb789424fc 94 }
jksoft 0:fccb789424fc 95
jksoft 0:fccb789424fc 96 // data: event(8), len(8), status(8), service_record_handle(32)
jksoft 0:fccb789424fc 97 static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) {
jksoft 0:fccb789424fc 98 if (!app_packet_handler) return;
jksoft 0:fccb789424fc 99 uint8_t event[7];
jksoft 0:fccb789424fc 100 event[0] = SDP_SERVICE_REGISTERED;
jksoft 0:fccb789424fc 101 event[1] = sizeof(event) - 2;
jksoft 0:fccb789424fc 102 event[2] = status;
jksoft 0:fccb789424fc 103 bt_store_32(event, 3, handle);
jksoft 0:fccb789424fc 104 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:fccb789424fc 105 (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
jksoft 0:fccb789424fc 106 }
jksoft 0:fccb789424fc 107
jksoft 0:fccb789424fc 108 service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
jksoft 0:fccb789424fc 109 linked_item_t *it;
jksoft 0:fccb789424fc 110 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
jksoft 0:fccb789424fc 111 service_record_item_t * item = (service_record_item_t *) it;
jksoft 0:fccb789424fc 112 if (item->service_record_handle == handle){
jksoft 0:fccb789424fc 113 return item;
jksoft 0:fccb789424fc 114 }
jksoft 0:fccb789424fc 115 }
jksoft 0:fccb789424fc 116 return NULL;
jksoft 0:fccb789424fc 117 }
jksoft 0:fccb789424fc 118
jksoft 0:fccb789424fc 119 // get next free, unregistered service record handle
jksoft 0:fccb789424fc 120 uint32_t sdp_create_service_record_handle(void){
jksoft 0:fccb789424fc 121 uint32_t handle = 0;
jksoft 0:fccb789424fc 122 do {
jksoft 0:fccb789424fc 123 handle = sdp_next_service_record_handle++;
jksoft 0:fccb789424fc 124 if (sdp_get_record_for_handle(handle)) handle = 0;
jksoft 0:fccb789424fc 125 } while (handle == 0);
jksoft 0:fccb789424fc 126 return handle;
jksoft 0:fccb789424fc 127 }
jksoft 0:fccb789424fc 128
jksoft 0:fccb789424fc 129 #ifdef EMBEDDED
jksoft 0:fccb789424fc 130
jksoft 0:fccb789424fc 131 // register service record internally - this special version doesn't copy the record, it should not be freeed
jksoft 0:fccb789424fc 132 // pre: AttributeIDs are in ascending order
jksoft 0:fccb789424fc 133 // pre: ServiceRecordHandle is first attribute and valid
jksoft 0:fccb789424fc 134 // pre: record
jksoft 0:fccb789424fc 135 // @returns ServiceRecordHandle or 0 if registration failed
jksoft 0:fccb789424fc 136 uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){
jksoft 0:fccb789424fc 137 // get user record handle
jksoft 0:fccb789424fc 138 uint32_t record_handle = record_item->service_record_handle;
jksoft 0:fccb789424fc 139 // get actual record
jksoft 0:fccb789424fc 140 uint8_t *record = record_item->service_record;
jksoft 0:fccb789424fc 141
jksoft 0:fccb789424fc 142 // check for ServiceRecordHandle attribute, returns pointer or null
jksoft 0:fccb789424fc 143 uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
jksoft 0:fccb789424fc 144 if (!req_record_handle) {
jksoft 0:fccb789424fc 145 log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n");
jksoft 0:fccb789424fc 146 return 0;
jksoft 0:fccb789424fc 147 }
jksoft 0:fccb789424fc 148
jksoft 0:fccb789424fc 149 // validate service record handle is not in reserved range
jksoft 0:fccb789424fc 150 if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
jksoft 0:fccb789424fc 151
jksoft 0:fccb789424fc 152 // check if already in use
jksoft 0:fccb789424fc 153 if (record_handle) {
jksoft 0:fccb789424fc 154 if (sdp_get_record_for_handle(record_handle)) {
jksoft 0:fccb789424fc 155 record_handle = 0;
jksoft 0:fccb789424fc 156 }
jksoft 0:fccb789424fc 157 }
jksoft 0:fccb789424fc 158
jksoft 0:fccb789424fc 159 // create new handle if needed
jksoft 0:fccb789424fc 160 if (!record_handle){
jksoft 0:fccb789424fc 161 record_handle = sdp_create_service_record_handle();
jksoft 0:fccb789424fc 162 // Write the handle back into the record too
jksoft 0:fccb789424fc 163 record_item->service_record_handle = record_handle;
jksoft 0:fccb789424fc 164 sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle);
jksoft 0:fccb789424fc 165 }
jksoft 0:fccb789424fc 166
jksoft 0:fccb789424fc 167 // add to linked list
jksoft 0:fccb789424fc 168 linked_list_add(&sdp_service_records, (linked_item_t *) record_item);
jksoft 0:fccb789424fc 169
jksoft 0:fccb789424fc 170 sdp_emit_service_registered(connection, 0, record_item->service_record_handle);
jksoft 0:fccb789424fc 171
jksoft 0:fccb789424fc 172 return record_handle;
jksoft 0:fccb789424fc 173 }
jksoft 0:fccb789424fc 174
jksoft 0:fccb789424fc 175 #else
jksoft 0:fccb789424fc 176
jksoft 0:fccb789424fc 177 // AttributeIDList used to remove ServiceRecordHandle
jksoft 0:fccb789424fc 178 static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
jksoft 0:fccb789424fc 179
jksoft 0:fccb789424fc 180 // register service record internally - the normal version creates a copy of the record
jksoft 0:fccb789424fc 181 // pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
jksoft 0:fccb789424fc 182 // @returns ServiceRecordHandle or 0 if registration failed
jksoft 0:fccb789424fc 183 uint32_t sdp_register_service_internal(void *connection, uint8_t * record){
jksoft 0:fccb789424fc 184
jksoft 0:fccb789424fc 185 // dump for now
jksoft 0:fccb789424fc 186 // printf("Register service record\n");
jksoft 0:fccb789424fc 187 // de_dump_data_element(record);
jksoft 0:fccb789424fc 188
jksoft 0:fccb789424fc 189 // get user record handle
jksoft 0:fccb789424fc 190 uint32_t record_handle = sdp_get_service_record_handle(record);
jksoft 0:fccb789424fc 191
jksoft 0:fccb789424fc 192 // validate service record handle is not in reserved range
jksoft 0:fccb789424fc 193 if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
jksoft 0:fccb789424fc 194
jksoft 0:fccb789424fc 195 // check if already in use
jksoft 0:fccb789424fc 196 if (record_handle) {
jksoft 0:fccb789424fc 197 if (sdp_get_record_for_handle(record_handle)) {
jksoft 0:fccb789424fc 198 record_handle = 0;
jksoft 0:fccb789424fc 199 }
jksoft 0:fccb789424fc 200 }
jksoft 0:fccb789424fc 201
jksoft 0:fccb789424fc 202 // create new handle if needed
jksoft 0:fccb789424fc 203 if (!record_handle){
jksoft 0:fccb789424fc 204 record_handle = sdp_create_service_record_handle();
jksoft 0:fccb789424fc 205 }
jksoft 0:fccb789424fc 206
jksoft 0:fccb789424fc 207 // calculate size of new service record: DES (2 byte len)
jksoft 0:fccb789424fc 208 // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
jksoft 0:fccb789424fc 209 uint16_t recordSize = 3 + (3 + 5) + de_get_data_size(record);
jksoft 0:fccb789424fc 210
jksoft 0:fccb789424fc 211 // alloc memory for new service_record_item
jksoft 0:fccb789424fc 212 service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t));
jksoft 0:fccb789424fc 213 if (!newRecordItem) {
jksoft 0:fccb789424fc 214 sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED);
jksoft 0:fccb789424fc 215 return 0;
jksoft 0:fccb789424fc 216 }
jksoft 0:fccb789424fc 217 // link new service item to client connection
jksoft 0:fccb789424fc 218 newRecordItem->connection = connection;
jksoft 0:fccb789424fc 219
jksoft 0:fccb789424fc 220 // set new handle
jksoft 0:fccb789424fc 221 newRecordItem->service_record_handle = record_handle;
jksoft 0:fccb789424fc 222
jksoft 0:fccb789424fc 223 // create updated service record
jksoft 0:fccb789424fc 224 uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record);
jksoft 0:fccb789424fc 225
jksoft 0:fccb789424fc 226 // create DES for new record
jksoft 0:fccb789424fc 227 de_create_sequence(newRecord);
jksoft 0:fccb789424fc 228
jksoft 0:fccb789424fc 229 // set service record handle
jksoft 0:fccb789424fc 230 de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
jksoft 0:fccb789424fc 231 de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
jksoft 0:fccb789424fc 232
jksoft 0:fccb789424fc 233 // add other attributes
jksoft 0:fccb789424fc 234 sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
jksoft 0:fccb789424fc 235
jksoft 0:fccb789424fc 236 // dump for now
jksoft 0:fccb789424fc 237 // de_dump_data_element(newRecord);
jksoft 0:fccb789424fc 238 // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord));
jksoft 0:fccb789424fc 239
jksoft 0:fccb789424fc 240 // add to linked list
jksoft 0:fccb789424fc 241 linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem);
jksoft 0:fccb789424fc 242
jksoft 0:fccb789424fc 243 sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle);
jksoft 0:fccb789424fc 244
jksoft 0:fccb789424fc 245 return record_handle;
jksoft 0:fccb789424fc 246 }
jksoft 0:fccb789424fc 247
jksoft 0:fccb789424fc 248 #endif
jksoft 0:fccb789424fc 249
jksoft 0:fccb789424fc 250 // unregister service record internally
jksoft 0:fccb789424fc 251 //
jksoft 0:fccb789424fc 252 // makes sure one client cannot remove service records of other clients
jksoft 0:fccb789424fc 253 //
jksoft 0:fccb789424fc 254 void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){
jksoft 0:fccb789424fc 255 service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle);
jksoft 0:fccb789424fc 256 if (record_item && record_item->connection == connection) {
jksoft 0:fccb789424fc 257 linked_list_remove(&sdp_service_records, (linked_item_t *) record_item);
jksoft 0:fccb789424fc 258 }
jksoft 0:fccb789424fc 259 }
jksoft 0:fccb789424fc 260
jksoft 0:fccb789424fc 261 // remove all service record for a client connection
jksoft 0:fccb789424fc 262 void sdp_unregister_services_for_connection(void *connection){
jksoft 0:fccb789424fc 263 linked_item_t *it = (linked_item_t *) &sdp_service_records;
jksoft 0:fccb789424fc 264 while (it->next){
jksoft 0:fccb789424fc 265 service_record_item_t *record_item = (service_record_item_t *) it->next;
jksoft 0:fccb789424fc 266 if (record_item->connection == connection){
jksoft 0:fccb789424fc 267 it->next = it->next->next;
jksoft 0:fccb789424fc 268 #ifndef EMBEDDED
jksoft 0:fccb789424fc 269 free(record_item);
jksoft 0:fccb789424fc 270 #endif
jksoft 0:fccb789424fc 271 } else {
jksoft 0:fccb789424fc 272 it = it->next;
jksoft 0:fccb789424fc 273 }
jksoft 0:fccb789424fc 274 }
jksoft 0:fccb789424fc 275 }
jksoft 0:fccb789424fc 276
jksoft 0:fccb789424fc 277 // PDU
jksoft 0:fccb789424fc 278 // PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, ..
jksoft 0:fccb789424fc 279
jksoft 0:fccb789424fc 280 int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){
jksoft 0:fccb789424fc 281 sdp_response_buffer[0] = SDP_ErrorResponse;
jksoft 0:fccb789424fc 282 net_store_16(sdp_response_buffer, 1, transaction_id);
jksoft 0:fccb789424fc 283 net_store_16(sdp_response_buffer, 3, 2);
jksoft 0:fccb789424fc 284 net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax
jksoft 0:fccb789424fc 285 return 7;
jksoft 0:fccb789424fc 286 }
jksoft 0:fccb789424fc 287
jksoft 0:fccb789424fc 288 int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){
jksoft 0:fccb789424fc 289
jksoft 0:fccb789424fc 290 // get request details
jksoft 0:fccb789424fc 291 uint16_t transaction_id = READ_NET_16(packet, 1);
jksoft 0:fccb789424fc 292 // not used yet - uint16_t param_len = READ_NET_16(packet, 3);
jksoft 0:fccb789424fc 293 uint8_t * serviceSearchPattern = &packet[5];
jksoft 0:fccb789424fc 294 uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern);
jksoft 0:fccb789424fc 295 uint16_t maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
jksoft 0:fccb789424fc 296 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2];
jksoft 0:fccb789424fc 297
jksoft 0:fccb789424fc 298 // calc maxumumServiceRecordCount based on remote MTU
jksoft 0:fccb789424fc 299 uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4;
jksoft 0:fccb789424fc 300
jksoft 0:fccb789424fc 301 // continuation state contains index of next service record to examine
jksoft 0:fccb789424fc 302 int continuation = 0;
jksoft 0:fccb789424fc 303 uint16_t continuation_index = 0;
jksoft 0:fccb789424fc 304 if (continuationState[0] == 2){
jksoft 0:fccb789424fc 305 continuation_index = READ_NET_16(continuationState, 1);
jksoft 0:fccb789424fc 306 }
jksoft 0:fccb789424fc 307
jksoft 0:fccb789424fc 308 // get and limit total count
jksoft 0:fccb789424fc 309 linked_item_t *it;
jksoft 0:fccb789424fc 310 uint16_t total_service_count = 0;
jksoft 0:fccb789424fc 311 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
jksoft 0:fccb789424fc 312 service_record_item_t * item = (service_record_item_t *) it;
jksoft 0:fccb789424fc 313 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
jksoft 0:fccb789424fc 314 total_service_count++;
jksoft 0:fccb789424fc 315 }
jksoft 0:fccb789424fc 316 if (total_service_count > maximumServiceRecordCount){
jksoft 0:fccb789424fc 317 total_service_count = maximumServiceRecordCount;
jksoft 0:fccb789424fc 318 }
jksoft 0:fccb789424fc 319
jksoft 0:fccb789424fc 320 // ServiceRecordHandleList at 9
jksoft 0:fccb789424fc 321 uint16_t pos = 9;
jksoft 0:fccb789424fc 322 uint16_t current_service_count = 0;
jksoft 0:fccb789424fc 323 uint16_t current_service_index = 0;
jksoft 0:fccb789424fc 324 uint16_t matching_service_count = 0;
jksoft 0:fccb789424fc 325 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){
jksoft 0:fccb789424fc 326 service_record_item_t * item = (service_record_item_t *) it;
jksoft 0:fccb789424fc 327
jksoft 0:fccb789424fc 328 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
jksoft 0:fccb789424fc 329 matching_service_count++;
jksoft 0:fccb789424fc 330
jksoft 0:fccb789424fc 331 if (current_service_index < continuation_index) continue;
jksoft 0:fccb789424fc 332
jksoft 0:fccb789424fc 333 net_store_32(sdp_response_buffer, pos, item->service_record_handle);
jksoft 0:fccb789424fc 334 pos += 4;
jksoft 0:fccb789424fc 335 current_service_count++;
jksoft 0:fccb789424fc 336
jksoft 0:fccb789424fc 337 if (matching_service_count >= total_service_count) break;
jksoft 0:fccb789424fc 338
jksoft 0:fccb789424fc 339 if (current_service_count >= maxNrServiceRecordsPerResponse){
jksoft 0:fccb789424fc 340 continuation = 1;
jksoft 0:fccb789424fc 341 continuation_index = current_service_index + 1;
jksoft 0:fccb789424fc 342 break;
jksoft 0:fccb789424fc 343 }
jksoft 0:fccb789424fc 344 }
jksoft 0:fccb789424fc 345
jksoft 0:fccb789424fc 346 // Store continuation state
jksoft 0:fccb789424fc 347 if (continuation) {
jksoft 0:fccb789424fc 348 sdp_response_buffer[pos++] = 2;
jksoft 0:fccb789424fc 349 net_store_16(sdp_response_buffer, pos, continuation_index);
jksoft 0:fccb789424fc 350 pos += 2;
jksoft 0:fccb789424fc 351 } else {
jksoft 0:fccb789424fc 352 sdp_response_buffer[pos++] = 0;
jksoft 0:fccb789424fc 353 }
jksoft 0:fccb789424fc 354
jksoft 0:fccb789424fc 355 // header
jksoft 0:fccb789424fc 356 sdp_response_buffer[0] = SDP_ServiceSearchResponse;
jksoft 0:fccb789424fc 357 net_store_16(sdp_response_buffer, 1, transaction_id);
jksoft 0:fccb789424fc 358 net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
jksoft 0:fccb789424fc 359 net_store_16(sdp_response_buffer, 5, total_service_count);
jksoft 0:fccb789424fc 360 net_store_16(sdp_response_buffer, 7, current_service_count);
jksoft 0:fccb789424fc 361
jksoft 0:fccb789424fc 362 return pos;
jksoft 0:fccb789424fc 363 }
jksoft 0:fccb789424fc 364
jksoft 0:fccb789424fc 365 int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
jksoft 0:fccb789424fc 366
jksoft 0:fccb789424fc 367 // get request details
jksoft 0:fccb789424fc 368 uint16_t transaction_id = READ_NET_16(packet, 1);
jksoft 0:fccb789424fc 369 // not used yet - uint16_t param_len = READ_NET_16(packet, 3);
jksoft 0:fccb789424fc 370 uint32_t serviceRecordHandle = READ_NET_32(packet, 5);
jksoft 0:fccb789424fc 371 uint16_t maximumAttributeByteCount = READ_NET_16(packet, 9);
jksoft 0:fccb789424fc 372 uint8_t * attributeIDList = &packet[11];
jksoft 0:fccb789424fc 373 uint16_t attributeIDListLen = de_get_len(attributeIDList);
jksoft 0:fccb789424fc 374 uint8_t * continuationState = &packet[11+attributeIDListLen];
jksoft 0:fccb789424fc 375
jksoft 0:fccb789424fc 376 // calc maximumAttributeByteCount based on remote MTU
jksoft 0:fccb789424fc 377 uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3);
jksoft 0:fccb789424fc 378 if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
jksoft 0:fccb789424fc 379 maximumAttributeByteCount = maximumAttributeByteCount2;
jksoft 0:fccb789424fc 380 }
jksoft 0:fccb789424fc 381
jksoft 0:fccb789424fc 382 // continuation state contains the offset into the complete response
jksoft 0:fccb789424fc 383 uint16_t continuation_offset = 0;
jksoft 0:fccb789424fc 384 if (continuationState[0] == 2){
jksoft 0:fccb789424fc 385 continuation_offset = READ_NET_16(continuationState, 1);
jksoft 0:fccb789424fc 386 }
jksoft 0:fccb789424fc 387
jksoft 0:fccb789424fc 388 // get service record
jksoft 0:fccb789424fc 389 service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle);
jksoft 0:fccb789424fc 390 if (!item){
jksoft 0:fccb789424fc 391 // service record handle doesn't exist
jksoft 0:fccb789424fc 392 return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
jksoft 0:fccb789424fc 393 }
jksoft 0:fccb789424fc 394
jksoft 0:fccb789424fc 395
jksoft 0:fccb789424fc 396 // AttributeList - starts at offset 7
jksoft 0:fccb789424fc 397 uint16_t pos = 7;
jksoft 0:fccb789424fc 398
jksoft 0:fccb789424fc 399 if (continuation_offset == 0){
jksoft 0:fccb789424fc 400
jksoft 0:fccb789424fc 401 // get size of this record
jksoft 0:fccb789424fc 402 uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
jksoft 0:fccb789424fc 403
jksoft 0:fccb789424fc 404 // store DES
jksoft 0:fccb789424fc 405 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
jksoft 0:fccb789424fc 406 maximumAttributeByteCount -= 3;
jksoft 0:fccb789424fc 407 pos += 3;
jksoft 0:fccb789424fc 408 }
jksoft 0:fccb789424fc 409
jksoft 0:fccb789424fc 410 // copy maximumAttributeByteCount from record
jksoft 0:fccb789424fc 411 uint16_t bytes_used;
jksoft 0:fccb789424fc 412 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
jksoft 0:fccb789424fc 413 pos += bytes_used;
jksoft 0:fccb789424fc 414
jksoft 0:fccb789424fc 415 uint16_t attributeListByteCount = pos - 7;
jksoft 0:fccb789424fc 416
jksoft 0:fccb789424fc 417 if (complete) {
jksoft 0:fccb789424fc 418 sdp_response_buffer[pos++] = 0;
jksoft 0:fccb789424fc 419 } else {
jksoft 0:fccb789424fc 420 continuation_offset += bytes_used;
jksoft 0:fccb789424fc 421 sdp_response_buffer[pos++] = 2;
jksoft 0:fccb789424fc 422 net_store_16(sdp_response_buffer, pos, continuation_offset);
jksoft 0:fccb789424fc 423 pos += 2;
jksoft 0:fccb789424fc 424 }
jksoft 0:fccb789424fc 425
jksoft 0:fccb789424fc 426 // header
jksoft 0:fccb789424fc 427 sdp_response_buffer[0] = SDP_ServiceAttributeResponse;
jksoft 0:fccb789424fc 428 net_store_16(sdp_response_buffer, 1, transaction_id);
jksoft 0:fccb789424fc 429 net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
jksoft 0:fccb789424fc 430 net_store_16(sdp_response_buffer, 5, attributeListByteCount);
jksoft 0:fccb789424fc 431
jksoft 0:fccb789424fc 432 return pos;
jksoft 0:fccb789424fc 433 }
jksoft 0:fccb789424fc 434
jksoft 0:fccb789424fc 435 static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){
jksoft 0:fccb789424fc 436 uint16_t total_response_size = 0;
jksoft 0:fccb789424fc 437 linked_item_t *it;
jksoft 0:fccb789424fc 438 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
jksoft 0:fccb789424fc 439 service_record_item_t * item = (service_record_item_t *) it;
jksoft 0:fccb789424fc 440
jksoft 0:fccb789424fc 441 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
jksoft 0:fccb789424fc 442
jksoft 0:fccb789424fc 443 // for all service records that match
jksoft 0:fccb789424fc 444 total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList);
jksoft 0:fccb789424fc 445 }
jksoft 0:fccb789424fc 446 return total_response_size;
jksoft 0:fccb789424fc 447 }
jksoft 0:fccb789424fc 448
jksoft 0:fccb789424fc 449 int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){
jksoft 0:fccb789424fc 450
jksoft 0:fccb789424fc 451 // SDP header before attribute sevice list: 7
jksoft 0:fccb789424fc 452 // Continuation, worst case: 5
jksoft 0:fccb789424fc 453
jksoft 0:fccb789424fc 454 // get request details
jksoft 0:fccb789424fc 455 uint16_t transaction_id = READ_NET_16(packet, 1);
jksoft 0:fccb789424fc 456 // not used yet - uint16_t param_len = READ_NET_16(packet, 3);
jksoft 0:fccb789424fc 457 uint8_t * serviceSearchPattern = &packet[5];
jksoft 0:fccb789424fc 458 uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern);
jksoft 0:fccb789424fc 459 uint16_t maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
jksoft 0:fccb789424fc 460 uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2];
jksoft 0:fccb789424fc 461 uint16_t attributeIDListLen = de_get_len(attributeIDList);
jksoft 0:fccb789424fc 462 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen];
jksoft 0:fccb789424fc 463
jksoft 0:fccb789424fc 464 // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block
jksoft 0:fccb789424fc 465 uint16_t maximumAttributeByteCount2 = remote_mtu - 12;
jksoft 0:fccb789424fc 466 if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
jksoft 0:fccb789424fc 467 maximumAttributeByteCount = maximumAttributeByteCount2;
jksoft 0:fccb789424fc 468 }
jksoft 0:fccb789424fc 469
jksoft 0:fccb789424fc 470 // continuation state contains: index of next service record to examine
jksoft 0:fccb789424fc 471 // continuation state contains: byte offset into this service record
jksoft 0:fccb789424fc 472 uint16_t continuation_service_index = 0;
jksoft 0:fccb789424fc 473 uint16_t continuation_offset = 0;
jksoft 0:fccb789424fc 474 if (continuationState[0] == 4){
jksoft 0:fccb789424fc 475 continuation_service_index = READ_NET_16(continuationState, 1);
jksoft 0:fccb789424fc 476 continuation_offset = READ_NET_16(continuationState, 3);
jksoft 0:fccb789424fc 477 }
jksoft 0:fccb789424fc 478
jksoft 0:fccb789424fc 479 // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount);
jksoft 0:fccb789424fc 480
jksoft 0:fccb789424fc 481 // AttributeLists - starts at offset 7
jksoft 0:fccb789424fc 482 uint16_t pos = 7;
jksoft 0:fccb789424fc 483
jksoft 0:fccb789424fc 484 // add DES with total size for first request
jksoft 0:fccb789424fc 485 if (continuation_service_index == 0 && continuation_offset == 0){
jksoft 0:fccb789424fc 486 uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList);
jksoft 0:fccb789424fc 487 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size);
jksoft 0:fccb789424fc 488 // log_info("total response size %u\n", total_response_size);
jksoft 0:fccb789424fc 489 pos += 3;
jksoft 0:fccb789424fc 490 maximumAttributeByteCount -= 3;
jksoft 0:fccb789424fc 491 }
jksoft 0:fccb789424fc 492
jksoft 0:fccb789424fc 493 // create attribute list
jksoft 0:fccb789424fc 494 int first_answer = 1;
jksoft 0:fccb789424fc 495 int continuation = 0;
jksoft 0:fccb789424fc 496 uint16_t current_service_index = 0;
jksoft 0:fccb789424fc 497 linked_item_t *it = (linked_item_t *) sdp_service_records;
jksoft 0:fccb789424fc 498 for ( ; it ; it = it->next, ++current_service_index){
jksoft 0:fccb789424fc 499 service_record_item_t * item = (service_record_item_t *) it;
jksoft 0:fccb789424fc 500
jksoft 0:fccb789424fc 501 if (current_service_index < continuation_service_index ) continue;
jksoft 0:fccb789424fc 502 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
jksoft 0:fccb789424fc 503
jksoft 0:fccb789424fc 504 if (continuation_offset == 0){
jksoft 0:fccb789424fc 505
jksoft 0:fccb789424fc 506 // get size of this record
jksoft 0:fccb789424fc 507 uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
jksoft 0:fccb789424fc 508
jksoft 0:fccb789424fc 509 // stop if complete record doesn't fits into response but we already have a partial response
jksoft 0:fccb789424fc 510 if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) {
jksoft 0:fccb789424fc 511 continuation = 1;
jksoft 0:fccb789424fc 512 break;
jksoft 0:fccb789424fc 513 }
jksoft 0:fccb789424fc 514
jksoft 0:fccb789424fc 515 // store DES
jksoft 0:fccb789424fc 516 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
jksoft 0:fccb789424fc 517 pos += 3;
jksoft 0:fccb789424fc 518 maximumAttributeByteCount -= 3;
jksoft 0:fccb789424fc 519 }
jksoft 0:fccb789424fc 520
jksoft 0:fccb789424fc 521 first_answer = 0;
jksoft 0:fccb789424fc 522
jksoft 0:fccb789424fc 523 // copy maximumAttributeByteCount from record
jksoft 0:fccb789424fc 524 uint16_t bytes_used;
jksoft 0:fccb789424fc 525 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
jksoft 0:fccb789424fc 526 pos += bytes_used;
jksoft 0:fccb789424fc 527 maximumAttributeByteCount -= bytes_used;
jksoft 0:fccb789424fc 528
jksoft 0:fccb789424fc 529 if (complete) {
jksoft 0:fccb789424fc 530 continuation_offset = 0;
jksoft 0:fccb789424fc 531 continue;
jksoft 0:fccb789424fc 532 }
jksoft 0:fccb789424fc 533
jksoft 0:fccb789424fc 534 continuation = 1;
jksoft 0:fccb789424fc 535 continuation_offset += bytes_used;
jksoft 0:fccb789424fc 536 break;
jksoft 0:fccb789424fc 537 }
jksoft 0:fccb789424fc 538
jksoft 0:fccb789424fc 539 uint16_t attributeListsByteCount = pos - 7;
jksoft 0:fccb789424fc 540
jksoft 0:fccb789424fc 541 // Continuation State
jksoft 0:fccb789424fc 542 if (continuation){
jksoft 0:fccb789424fc 543 sdp_response_buffer[pos++] = 4;
jksoft 0:fccb789424fc 544 net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index);
jksoft 0:fccb789424fc 545 pos += 2;
jksoft 0:fccb789424fc 546 net_store_16(sdp_response_buffer, pos, continuation_offset);
jksoft 0:fccb789424fc 547 pos += 2;
jksoft 0:fccb789424fc 548 } else {
jksoft 0:fccb789424fc 549 // complete
jksoft 0:fccb789424fc 550 sdp_response_buffer[pos++] = 0;
jksoft 0:fccb789424fc 551 }
jksoft 0:fccb789424fc 552
jksoft 0:fccb789424fc 553 // create SDP header
jksoft 0:fccb789424fc 554 sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse;
jksoft 0:fccb789424fc 555 net_store_16(sdp_response_buffer, 1, transaction_id);
jksoft 0:fccb789424fc 556 net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
jksoft 0:fccb789424fc 557 net_store_16(sdp_response_buffer, 5, attributeListsByteCount);
jksoft 0:fccb789424fc 558
jksoft 0:fccb789424fc 559 return pos;
jksoft 0:fccb789424fc 560 }
jksoft 0:fccb789424fc 561
jksoft 0:fccb789424fc 562 static void sdp_try_respond(void){
jksoft 0:fccb789424fc 563 if (!sdp_response_size ) return;
jksoft 0:fccb789424fc 564 if (!l2cap_cid) return;
jksoft 0:fccb789424fc 565 if (!l2cap_can_send_packet_now(l2cap_cid)) return;
jksoft 0:fccb789424fc 566
jksoft 0:fccb789424fc 567 // update state before sending packet (avoid getting called when new l2cap credit gets emitted)
jksoft 0:fccb789424fc 568 uint16_t size = sdp_response_size;
jksoft 0:fccb789424fc 569 sdp_response_size = 0;
jksoft 0:fccb789424fc 570 l2cap_send_internal(l2cap_cid, sdp_response_buffer, size);
jksoft 0:fccb789424fc 571 }
jksoft 0:fccb789424fc 572
jksoft 0:fccb789424fc 573 // we assume that we don't get two requests in a row
jksoft 0:fccb789424fc 574 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
jksoft 0:fccb789424fc 575 uint16_t transaction_id;
jksoft 0:fccb789424fc 576 SDP_PDU_ID_t pdu_id;
jksoft 0:fccb789424fc 577 uint16_t remote_mtu;
jksoft 0:fccb789424fc 578 // uint16_t param_len;
jksoft 0:fccb789424fc 579
jksoft 0:fccb789424fc 580 switch (packet_type) {
jksoft 0:fccb789424fc 581
jksoft 0:fccb789424fc 582 case L2CAP_DATA_PACKET:
jksoft 0:fccb789424fc 583 pdu_id = (SDP_PDU_ID_t) packet[0];
jksoft 0:fccb789424fc 584 transaction_id = READ_NET_16(packet, 1);
jksoft 0:fccb789424fc 585 // param_len = READ_NET_16(packet, 3);
jksoft 0:fccb789424fc 586 remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel);
jksoft 0:fccb789424fc 587 // account for our buffer
jksoft 0:fccb789424fc 588 if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){
jksoft 0:fccb789424fc 589 remote_mtu = SDP_RESPONSE_BUFFER_SIZE;
jksoft 0:fccb789424fc 590 }
jksoft 0:fccb789424fc 591
jksoft 0:fccb789424fc 592 // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu);
jksoft 0:fccb789424fc 593 switch (pdu_id){
jksoft 0:fccb789424fc 594
jksoft 0:fccb789424fc 595 case SDP_ServiceSearchRequest:
jksoft 0:fccb789424fc 596 sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu);
jksoft 0:fccb789424fc 597 break;
jksoft 0:fccb789424fc 598
jksoft 0:fccb789424fc 599 case SDP_ServiceAttributeRequest:
jksoft 0:fccb789424fc 600 sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu);
jksoft 0:fccb789424fc 601 break;
jksoft 0:fccb789424fc 602
jksoft 0:fccb789424fc 603 case SDP_ServiceSearchAttributeRequest:
jksoft 0:fccb789424fc 604 sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu);
jksoft 0:fccb789424fc 605 break;
jksoft 0:fccb789424fc 606
jksoft 0:fccb789424fc 607 default:
jksoft 0:fccb789424fc 608 sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax
jksoft 0:fccb789424fc 609 break;
jksoft 0:fccb789424fc 610 }
jksoft 0:fccb789424fc 611
jksoft 0:fccb789424fc 612 sdp_try_respond();
jksoft 0:fccb789424fc 613
jksoft 0:fccb789424fc 614 break;
jksoft 0:fccb789424fc 615
jksoft 0:fccb789424fc 616 case HCI_EVENT_PACKET:
jksoft 0:fccb789424fc 617
jksoft 0:fccb789424fc 618 switch (packet[0]) {
jksoft 0:fccb789424fc 619
jksoft 0:fccb789424fc 620 case L2CAP_EVENT_INCOMING_CONNECTION:
jksoft 0:fccb789424fc 621 if (l2cap_cid) {
jksoft 0:fccb789424fc 622 // CONNECTION REJECTED DUE TO LIMITED RESOURCES
jksoft 0:fccb789424fc 623 l2cap_decline_connection_internal(channel, 0x0d);
jksoft 0:fccb789424fc 624 break;
jksoft 0:fccb789424fc 625 }
jksoft 0:fccb789424fc 626 // accept
jksoft 0:fccb789424fc 627 l2cap_cid = channel;
jksoft 0:fccb789424fc 628 sdp_response_size = 0;
jksoft 0:fccb789424fc 629 l2cap_accept_connection_internal(channel);
jksoft 0:fccb789424fc 630 break;
jksoft 0:fccb789424fc 631
jksoft 0:fccb789424fc 632 case L2CAP_EVENT_CHANNEL_OPENED:
jksoft 0:fccb789424fc 633 if (packet[2]) {
jksoft 0:fccb789424fc 634 // open failed -> reset
jksoft 0:fccb789424fc 635 l2cap_cid = 0;
jksoft 0:fccb789424fc 636 }
jksoft 0:fccb789424fc 637 break;
jksoft 0:fccb789424fc 638
jksoft 0:fccb789424fc 639 case L2CAP_EVENT_CREDITS:
jksoft 0:fccb789424fc 640 case DAEMON_EVENT_HCI_PACKET_SENT:
jksoft 0:fccb789424fc 641 sdp_try_respond();
jksoft 0:fccb789424fc 642 break;
jksoft 0:fccb789424fc 643
jksoft 0:fccb789424fc 644 case L2CAP_EVENT_CHANNEL_CLOSED:
jksoft 0:fccb789424fc 645 if (channel == l2cap_cid){
jksoft 0:fccb789424fc 646 // reset
jksoft 0:fccb789424fc 647 l2cap_cid = 0;
jksoft 0:fccb789424fc 648 }
jksoft 0:fccb789424fc 649 break;
jksoft 0:fccb789424fc 650
jksoft 0:fccb789424fc 651 default:
jksoft 0:fccb789424fc 652 // other event
jksoft 0:fccb789424fc 653 break;
jksoft 0:fccb789424fc 654 }
jksoft 0:fccb789424fc 655 break;
jksoft 0:fccb789424fc 656
jksoft 0:fccb789424fc 657 default:
jksoft 0:fccb789424fc 658 // other packet type
jksoft 0:fccb789424fc 659 break;
jksoft 0:fccb789424fc 660 }
jksoft 0:fccb789424fc 661 }
jksoft 0:fccb789424fc 662