source: asp3_tinet_ecnl_arm/trunk/btstack/src/sdp.c@ 352

Last change on this file since 352 was 352, checked in by coas-nagasima, 6 years ago

arm向けASP3版ECNLを追加

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