mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-09 16:14:10 +00:00
rework SDP Service Record management. Service Records can be stored in ROM, daemon creates records on the heap
This commit is contained in:
parent
60416aa529
commit
9293bfa465
@ -261,20 +261,9 @@ int btstack_main(void)
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
/* LISTING_PAUSE */
|
||||
#ifdef EMBEDDED
|
||||
/* LISTING_RESUME */
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, RFCOMM_SERVER_CHANNEL, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
/* LISTING_PAUSE */
|
||||
#else
|
||||
sdp_create_spp_service( (uint8_t*)spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter");
|
||||
printf("SDP service record size: %u\n", de_get_len((uint8_t*)spp_service_buffer));
|
||||
sdp_register_service_internal((uint8_t*)spp_service_buffer);
|
||||
#endif
|
||||
/* LISTING_RESUME */
|
||||
sdp_register_service((uint8_t*)spp_service_buffer);
|
||||
|
||||
hci_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
|
||||
|
||||
|
@ -100,20 +100,9 @@ static void spp_service_setup(void){
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
/* LISTING_PAUSE */
|
||||
#ifdef EMBEDDED
|
||||
/* LISTING_RESUME */
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, RFCOMM_SERVER_CHANNEL, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
/* LISTING_PAUSE */
|
||||
#else
|
||||
sdp_create_spp_service( (uint8_t*) spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter");
|
||||
printf("SDP service record size: %u\n", de_get_len((uint8_t*) spp_service_buffer));
|
||||
sdp_register_service_internal((uint8_t*)spp_service_buffer);
|
||||
#endif
|
||||
/* LISTING_RESUME */
|
||||
sdp_register_service((uint8_t*)spp_service_buffer);
|
||||
}
|
||||
/* LISTING_END */
|
||||
|
||||
|
@ -88,15 +88,14 @@ static void spp_service_setup(void){
|
||||
rfcomm_init();
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
// reserved channel, mtu limited by l2cap, 1 credit
|
||||
rfcomm_register_service_with_initial_credits_internal(NULL, rfcomm_channel_nr, 0xffff, 1);
|
||||
rfcomm_register_service_with_initial_credits(rfcomm_channel_nr, 0xffff, 1);
|
||||
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
sdp_create_spp_service( (uint8_t*) &spp_service_buffer, 1, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) de_get_len((uint8_t*) sdp_create_spp_service));
|
||||
sdp_register_service(spp_service_buffer);
|
||||
}
|
||||
/* LISTING_END */
|
||||
|
||||
|
@ -498,7 +498,7 @@ static void daemon_sdp_close_connection(client_state_t * daemon_client){
|
||||
linked_list_iterator_init(&it, list);
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
linked_list_uint32_t * item = (linked_list_uint32_t*) linked_list_iterator_next(&it);
|
||||
sdp_unregister_service_internal(&daemon_client->connection, item->value);
|
||||
sdp_unregister_service(item->value);
|
||||
linked_list_remove(list, (linked_item_t *) item);
|
||||
free(item);
|
||||
}
|
||||
@ -521,6 +521,45 @@ static connection_t * connection_for_l2cap_cid(uint16_t cid){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
|
||||
|
||||
// register a service record
|
||||
// pre: AttributeIDs are in ascending order
|
||||
// pre: ServiceRecordHandle is first attribute and is not already registered in database
|
||||
// @returns status
|
||||
static uint32_t daemon_sdp_create_and_register_service(uint8_t * record){
|
||||
|
||||
// create new handle
|
||||
uint32_t record_handle = sdp_create_service_record_handle();
|
||||
|
||||
// calculate size of new service record: DES (2 byte len)
|
||||
// + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
|
||||
uint16_t recordSize = 3 + (3 + 5) + de_get_data_size(record);
|
||||
|
||||
// alloc memory for new service record
|
||||
uint8_t * newRecord = malloc(recordSize);
|
||||
if (!newRecord) return 0;
|
||||
|
||||
// create DES for new record
|
||||
de_create_sequence(newRecord);
|
||||
|
||||
// set service record handle
|
||||
de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
|
||||
de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
|
||||
|
||||
// add other attributes
|
||||
sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
|
||||
|
||||
uint8_t status = sdp_register_service(newRecord);
|
||||
|
||||
if (status) {
|
||||
free(newRecord);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return record_handle;
|
||||
}
|
||||
|
||||
static connection_t * connection_for_rfcomm_cid(uint16_t cid){
|
||||
linked_list_iterator_t cl;
|
||||
linked_list_iterator_init(&cl, &clients);
|
||||
@ -637,7 +676,6 @@ static void send_l2cap_connection_open_failed(connection_t * connection, bd_addr
|
||||
}
|
||||
|
||||
static void l2cap_emit_service_registered(void *connection, uint8_t status, uint16_t psm){
|
||||
log_info("L2CAP_EVENT_SERVICE_REGISTERED status 0x%x psm 0x%x", status, psm);
|
||||
uint8_t event[5];
|
||||
event[0] = L2CAP_EVENT_SERVICE_REGISTERED;
|
||||
event[1] = sizeof(event) - 2;
|
||||
@ -648,7 +686,6 @@ static void l2cap_emit_service_registered(void *connection, uint8_t status, uint
|
||||
}
|
||||
|
||||
static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
|
||||
log_info("RFCOMM_EVENT_SERVICE_REGISTERED status 0x%x channel #%u", status, channel);
|
||||
uint8_t event[4];
|
||||
event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
|
||||
event[1] = sizeof(event) - 2;
|
||||
@ -675,10 +712,8 @@ static void send_rfcomm_create_channel_failed(void * connection, bd_addr_t addr,
|
||||
socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
|
||||
// data: event(8), len(8), status(8), service_record_handle(32)
|
||||
static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) {
|
||||
if (!app_packet_handler) return;
|
||||
uint8_t event[7];
|
||||
event[0] = SDP_SERVICE_REGISTERED;
|
||||
event[1] = sizeof(event) - 2;
|
||||
@ -781,14 +816,13 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
|
||||
uint32_t service_record_handle;
|
||||
client_state_t *client;
|
||||
uint8_t status;
|
||||
|
||||
uint8_t * data;
|
||||
#if defined(HAVE_MALLOC) && defined(HAVE_BLE)
|
||||
uint8_t uuid128[16];
|
||||
le_service_t service;
|
||||
le_characteristic_t characteristic;
|
||||
le_characteristic_descriptor_t descriptor;
|
||||
uint16_t data_length;
|
||||
uint8_t * data;
|
||||
linked_list_gatt_client_helper_t * gatt_helper;
|
||||
#endif
|
||||
|
||||
@ -985,10 +1019,9 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
|
||||
socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
||||
break;
|
||||
}
|
||||
|
||||
case SDP_REGISTER_SERVICE_RECORD:
|
||||
log_info("SDP_REGISTER_SERVICE_RECORD size %u\n", size);
|
||||
service_record_handle = sdp_register_service_internal(&packet[3]);
|
||||
service_record_handle = daemon_sdp_create_and_register_service(&packet[3]);
|
||||
if (service_record_handle){
|
||||
daemon_add_client_sdp_service_record_handle(connection, service_record_handle);
|
||||
sdp_emit_service_registered(connection, service_record_handle, 0);
|
||||
@ -999,8 +1032,12 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
|
||||
case SDP_UNREGISTER_SERVICE_RECORD:
|
||||
service_record_handle = READ_BT_32(packet, 3);
|
||||
log_info("SDP_UNREGISTER_SERVICE_RECORD handle 0x%x ", service_record_handle);
|
||||
sdp_unregister_service_internal(service_record_handle);
|
||||
data = sdp_get_record_for_handle(service_record_handle);
|
||||
sdp_unregister_service(service_record_handle);
|
||||
daemon_remove_client_sdp_service_record_handle(connection, service_record_handle);
|
||||
if (data){
|
||||
free(data);
|
||||
}
|
||||
break;
|
||||
case SDP_CLIENT_QUERY_RFCOMM_SERVICES:
|
||||
bt_flip_addr(addr, &packet[3]);
|
||||
|
@ -227,10 +227,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
sdp_create_spp_service( (uint8_t*) spp_service_buffer, 1, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) (de_get_len((uint8_t*) spp_service_buffer)));
|
||||
sdp_register_service(service_record_item);
|
||||
|
||||
// set one-shot timer
|
||||
timer_source_t heartbeat;
|
||||
|
@ -217,10 +217,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Accel");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
sdp_create_spp_service((uint8_t*) spp_service_buffer, 1, "SPP Accel");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) de_get_len((uint8_t*) spp_service_buffer));
|
||||
sdp_register_service((uint8_t*) spp_service_buffer);
|
||||
|
||||
// ready - enable irq used in h4 task
|
||||
__enable_interrupt();
|
||||
|
@ -227,10 +227,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
sdp_create_spp_service( (uint8_t*) spp_service_buffer, 1, "SPP Counter");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) de_get_len((uint8_t*) spp_service_buffer));
|
||||
sdp_register_service(spp_service_buffer);
|
||||
|
||||
// set one-shot timer
|
||||
timer_source_t heartbeat;
|
||||
|
@ -217,10 +217,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
|
||||
sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Accel");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
sdp_create_spp_service( (uint8_t*) spp_service_buffer, 1, "SPP Accel");
|
||||
printf("SDP service buffer size: %u\n\r", (uint16_t) de_get_len((uint8_t*) spp_service_buffer));
|
||||
sdp_register_service(spp_service_buffer);
|
||||
|
||||
// ready - enable irq used in h4 task
|
||||
__enable_interrupt();
|
||||
|
@ -39,17 +39,16 @@
|
||||
* Implementation of the Service Discovery Protocol Server
|
||||
*/
|
||||
|
||||
#include "classic/sdp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "classic/sdp_util.h"
|
||||
|
||||
#include "btstack_memory.h"
|
||||
#include "debug.h"
|
||||
#include "hci_dump.h"
|
||||
#include "l2cap.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "classic/sdp.h"
|
||||
#include "classic/sdp_util.h"
|
||||
|
||||
// max reserved ServiceRecordHandle
|
||||
#define maxReservedServiceRecordHandle 0xffff
|
||||
@ -58,7 +57,6 @@
|
||||
#define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
|
||||
|
||||
static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
uint32_t sdp_get_service_record_handle(uint8_t * record);
|
||||
|
||||
// registered service records
|
||||
static linked_list_t sdp_service_records = NULL;
|
||||
@ -76,15 +74,16 @@ void sdp_init(void){
|
||||
l2cap_register_service(sdp_packet_handler, PSM_SDP, 0xffff, LEVEL_0);
|
||||
}
|
||||
|
||||
uint32_t sdp_get_service_record_handle(uint8_t * record){
|
||||
uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
|
||||
uint32_t sdp_get_service_record_handle(const uint8_t * record){
|
||||
// TODO: make sdp_get_attribute_value_for_attribute_id accept const data to remove cast
|
||||
uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id((uint8_t *)record, SDP_ServiceRecordHandle);
|
||||
if (!serviceRecordHandleAttribute) return 0;
|
||||
if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
|
||||
if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
|
||||
return READ_NET_32(serviceRecordHandleAttribute, 1);
|
||||
}
|
||||
|
||||
static service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
|
||||
static service_record_item_t * sdp_get_record_item_for_handle(uint32_t handle){
|
||||
linked_item_t *it;
|
||||
for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
|
||||
service_record_item_t * item = (service_record_item_t *) it;
|
||||
@ -95,140 +94,58 @@ static service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * sdp_get_record_for_handle(uint32_t handle){
|
||||
service_record_item_t * record_item = sdp_get_record_item_for_handle(handle);
|
||||
if (!record_item) return 0;
|
||||
return record_item->service_record;
|
||||
}
|
||||
|
||||
// get next free, unregistered service record handle
|
||||
static uint32_t sdp_create_service_record_handle(void){
|
||||
uint32_t sdp_create_service_record_handle(void){
|
||||
uint32_t handle = 0;
|
||||
do {
|
||||
handle = sdp_next_service_record_handle++;
|
||||
if (sdp_get_record_for_handle(handle)) handle = 0;
|
||||
if (sdp_get_record_item_for_handle(handle)) handle = 0;
|
||||
} while (handle == 0);
|
||||
return handle;
|
||||
}
|
||||
|
||||
#ifdef EMBEDDED
|
||||
/**
|
||||
* @brief Register Service Record with database using ServiceRecordHandle stored in record
|
||||
* @pre AttributeIDs are in ascending order
|
||||
* @pre ServiceRecordHandle is first attribute and valid
|
||||
* @param record is not copied!
|
||||
* @result status
|
||||
*/
|
||||
uint8_t sdp_register_service(const uint8_t * record){
|
||||
|
||||
// register service record internally - this special version doesn't copy the record, it should not be freeed
|
||||
// pre: AttributeIDs are in ascending order
|
||||
// pre: ServiceRecordHandle is first attribute and valid
|
||||
// pre: record
|
||||
// @returns ServiceRecordHandle or 0 if registration failed
|
||||
uint32_t sdp_register_service_internal(service_record_item_t * record_item){
|
||||
// get user record handle
|
||||
uint32_t record_handle = record_item->service_record_handle;
|
||||
// get actual record
|
||||
uint8_t *record = record_item->service_record;
|
||||
|
||||
// check for ServiceRecordHandle attribute, returns pointer or null
|
||||
uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
|
||||
if (!req_record_handle) {
|
||||
log_error("SDP Error - record does not contain ServiceRecordHandle attribute");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// validate service record handle is not in reserved range
|
||||
if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
|
||||
|
||||
// check if already in use
|
||||
if (record_handle) {
|
||||
if (sdp_get_record_for_handle(record_handle)) {
|
||||
record_handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// create new handle if needed
|
||||
if (!record_handle){
|
||||
record_handle = sdp_create_service_record_handle();
|
||||
// Write the handle back into the record too
|
||||
record_item->service_record_handle = record_handle;
|
||||
sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle);
|
||||
}
|
||||
|
||||
// add to linked list
|
||||
linked_list_add(&sdp_service_records, (linked_item_t *) record_item);
|
||||
|
||||
return record_handle;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// AttributeIDList used to remove ServiceRecordHandle
|
||||
static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
|
||||
|
||||
// register service record internally - the normal version creates a copy of the record
|
||||
// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
|
||||
// @returns ServiceRecordHandle or 0 if registration failed
|
||||
uint32_t sdp_register_service_internal(uint8_t * record){
|
||||
|
||||
// dump for now
|
||||
// log_info("Register service record");
|
||||
// de_dump_data_element(record);
|
||||
|
||||
// get user record handle
|
||||
// validate service record handle. it must: exist, be in valid range, not have been already used
|
||||
uint32_t record_handle = sdp_get_service_record_handle(record);
|
||||
if (!record_handle) return SDP_HANDLE_INVALID;
|
||||
if (record_handle <= maxReservedServiceRecordHandle) return SDP_HANDLE_INVALID;
|
||||
if (sdp_get_record_item_for_handle(record_handle)) return SDP_HANDLE_ALREADY_REGISTERED;
|
||||
|
||||
// validate service record handle is not in reserved range
|
||||
if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
|
||||
|
||||
// check if already in use
|
||||
if (record_handle) {
|
||||
if (sdp_get_record_for_handle(record_handle)) {
|
||||
record_handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// create new handle if needed
|
||||
if (!record_handle){
|
||||
record_handle = sdp_create_service_record_handle();
|
||||
}
|
||||
|
||||
// calculate size of new service record: DES (2 byte len)
|
||||
// + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
|
||||
uint16_t recordSize = 3 + (3 + 5) + de_get_data_size(record);
|
||||
|
||||
// alloc memory for new service_record_item
|
||||
service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t));
|
||||
if (!newRecordItem) {
|
||||
return 0;
|
||||
}
|
||||
// set new handle
|
||||
newRecordItem->service_record_handle = record_handle;
|
||||
service_record_item_t * newRecordItem = btstack_memory_service_record_item_get();
|
||||
if (!newRecordItem) return BTSTACK_MEMORY_ALLOC_FAILED;
|
||||
|
||||
// create updated service record
|
||||
uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record);
|
||||
|
||||
// create DES for new record
|
||||
de_create_sequence(newRecord);
|
||||
|
||||
// set service record handle
|
||||
de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
|
||||
de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
|
||||
|
||||
// add other attributes
|
||||
sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
|
||||
|
||||
// dump for now
|
||||
// de_dump_data_element(newRecord);
|
||||
// log_info("reserved size %u, actual size %u", recordSize, de_get_len(newRecord));
|
||||
// set handle and record
|
||||
newRecordItem->service_record_handle = record_handle;
|
||||
newRecordItem->service_record = (uint8_t*) record;
|
||||
|
||||
// add to linked list
|
||||
linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem);
|
||||
|
||||
return record_handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// unregister service record internally
|
||||
//
|
||||
// makes sure one client cannot remove service records of other clients
|
||||
//
|
||||
void sdp_unregister_service_internal(uint32_t service_record_handle){
|
||||
service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle);
|
||||
// unregister service record
|
||||
//
|
||||
void sdp_unregister_service(uint32_t service_record_handle){
|
||||
service_record_item_t * record_item = sdp_get_record_item_for_handle(service_record_handle);
|
||||
if (!record_item) return;
|
||||
linked_list_remove(&sdp_service_records, (linked_item_t *) record_item);
|
||||
#ifndef EMBEDDED
|
||||
free(record_item);
|
||||
#endif
|
||||
}
|
||||
|
||||
// PDU
|
||||
@ -343,7 +260,7 @@ int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
|
||||
}
|
||||
|
||||
// get service record
|
||||
service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle);
|
||||
service_record_item_t * item = sdp_get_record_item_for_handle(serviceRecordHandle);
|
||||
if (!item){
|
||||
// service record handle doesn't exist
|
||||
return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
|
||||
|
@ -57,22 +57,18 @@ typedef enum {
|
||||
SDP_ServiceSearchAttributeResponse
|
||||
} SDP_PDU_ID_t;
|
||||
|
||||
// service record
|
||||
// -- uses user_data field for actual
|
||||
typedef struct {
|
||||
// linked list - assert: first field
|
||||
linked_item_t item;
|
||||
|
||||
// data is contained in same memory
|
||||
|
||||
uint32_t service_record_handle;
|
||||
uint8_t service_record[1]; // waste 1 byte to allow compilation with older compilers
|
||||
uint8_t * service_record;
|
||||
} service_record_item_t;
|
||||
|
||||
int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu);
|
||||
int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu);
|
||||
int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu);
|
||||
|
||||
|
||||
/* API_START */
|
||||
|
||||
/**
|
||||
@ -80,30 +76,43 @@ int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remot
|
||||
*/
|
||||
void sdp_init(void);
|
||||
|
||||
#ifdef EMBEDDED
|
||||
/**
|
||||
* @brief Register service record internally - this version doesn't copy the record therefore it must be forever accessible. Preconditions:
|
||||
- AttributeIDs are in ascending order;
|
||||
- ServiceRecordHandle is first attribute and valid.
|
||||
* @return ServiceRecordHandle or 0 if registration failed.
|
||||
/**
|
||||
* @brief Register Service Record with database using ServiceRecordHandle stored in record
|
||||
* @pre AttributeIDs are in ascending order
|
||||
* @pre ServiceRecordHandle is first attribute and valid
|
||||
* @param record is not copied!
|
||||
* @result status
|
||||
*/
|
||||
uint32_t sdp_register_service_internal(service_record_item_t * record_item);
|
||||
#endif
|
||||
|
||||
#ifndef EMBEDDED
|
||||
/**
|
||||
* @brief Register service record internally - this version creates a copy of the record precondition: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present.
|
||||
* @return ServiceRecordHandle or 0 if registration failed
|
||||
*/
|
||||
uint32_t sdp_register_service_internal(uint8_t * service_record);
|
||||
#endif
|
||||
uint8_t sdp_register_service(const uint8_t * record);
|
||||
|
||||
/**
|
||||
* @brief Unregister service record internally.
|
||||
*/
|
||||
void sdp_unregister_service_internal(uint32_t service_record_handle);
|
||||
void sdp_unregister_service(uint32_t service_record_handle);
|
||||
|
||||
/* API_END */
|
||||
|
||||
// used by daemon
|
||||
|
||||
/**
|
||||
* @brief Finds an unused valid service record handle
|
||||
* @result handle
|
||||
*/
|
||||
uint32_t sdp_create_service_record_handle(void);
|
||||
|
||||
/**
|
||||
* @brief gets record for handle
|
||||
* @result record
|
||||
*/
|
||||
|
||||
uint8_t * sdp_get_record_for_handle(uint32_t handle);
|
||||
|
||||
/**
|
||||
* @brief gets service record handle from record
|
||||
* @resutl service record handle or 0
|
||||
*/
|
||||
uint32_t sdp_get_service_record_handle(const uint8_t * record);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -853,6 +853,7 @@ extern "C" {
|
||||
#define SDP_HANDLE_ALREADY_REGISTERED 0x80
|
||||
#define SDP_QUERY_INCOMPLETE 0x81
|
||||
#define SDP_SERVICE_NOT_FOUND 0x82
|
||||
#define SDP_HANDLE_INVALID 0x83
|
||||
|
||||
#define ATT_HANDLE_VALUE_INDICATION_IN_PORGRESS 0x90
|
||||
#define ATT_HANDLE_VALUE_INDICATION_TIMEOUT 0x91
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "ble/sm.h"
|
||||
|
||||
static btstack_packet_handler_t att_packet_handler;
|
||||
static void (*registered_l2cap_packet_handler) (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
|
||||
static void (*registered_l2cap_packet_handler) (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
|
||||
|
||||
static linked_list_t connections;
|
||||
static const uint16_t max_mtu = 23;
|
||||
@ -25,22 +25,22 @@ uint16_t get_gatt_client_handle(void){
|
||||
|
||||
void mock_simulate_command_complete(const hci_cmd_t *cmd){
|
||||
uint8_t packet[] = {HCI_EVENT_COMMAND_COMPLETE, 4, 1, cmd->opcode & 0xff, cmd->opcode >> 8, 0};
|
||||
registered_l2cap_packet_handler(NULL, HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
registered_l2cap_packet_handler(HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
void mock_simulate_hci_state_working(void){
|
||||
uint8_t packet[3] = {BTSTACK_EVENT_STATE, 0, HCI_STATE_WORKING};
|
||||
registered_l2cap_packet_handler(NULL, HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, 3);
|
||||
registered_l2cap_packet_handler(HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, 3);
|
||||
}
|
||||
|
||||
void mock_simulate_connected(void){
|
||||
uint8_t packet[] = {0x3E, 0x13, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x9B, 0x77, 0xD1, 0xF7, 0xB1, 0x34, 0x50, 0x00, 0x00, 0x00, 0xD0, 0x07, 0x05};
|
||||
registered_l2cap_packet_handler(NULL, HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
registered_l2cap_packet_handler(HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
void mock_simulate_scan_response(void){
|
||||
uint8_t packet[] = {0xE2, 0x13, 0xE2, 0x01, 0x34, 0xB1, 0xF7, 0xD1, 0x77, 0x9B, 0xCC, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
registered_l2cap_packet_handler(NULL, HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
registered_l2cap_packet_handler(HCI_EVENT_PACKET, NULL, (uint8_t *)&packet, sizeof(packet));
|
||||
}
|
||||
|
||||
le_command_status_t le_central_start_scan(void){
|
||||
@ -89,7 +89,7 @@ void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint1
|
||||
att_packet_handler = packet_handler;
|
||||
}
|
||||
|
||||
void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
|
||||
void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
|
||||
registered_l2cap_packet_handler = handler;
|
||||
}
|
||||
|
||||
|
@ -799,16 +799,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
sdp_init();
|
||||
|
||||
uint16_t network_packet_types[] = { NETWORK_TYPE_IPv4, NETWORK_TYPE_ARP, 0}; // 0 as end of list
|
||||
#ifdef EMBEDDED
|
||||
service_record_item_t * service_record_item = (service_record_item_t *) panu_sdp_record;
|
||||
pan_create_panu_service((uint8_t*) &service_record_item->service_record, network_packet_types, NULL, NULL, BNEP_SECURITY_NONE);
|
||||
printf("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
|
||||
sdp_register_service_internal(service_record_item);
|
||||
#else
|
||||
pan_create_panu_service(panu_sdp_record, network_packet_types, NULL, NULL, BNEP_SECURITY_NONE);
|
||||
printf("SDP service record size: %u\n", de_get_len((uint8_t*) panu_sdp_record));
|
||||
sdp_register_service_internal((uint8_t*)panu_sdp_record);
|
||||
#endif
|
||||
sdp_register_service((uint8_t*)panu_sdp_record);
|
||||
|
||||
/* Turn on the device */
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
@ -781,12 +781,12 @@ int btstack_main(int argc, const char * argv[]){
|
||||
sdp_create_spp_service((uint8_t*) spp_service_buffer, RFCOMM_SERVER_CHANNEL, "SPP Counter");
|
||||
de_dump_data_element((uint8_t*) spp_service_buffer);
|
||||
printf("SDP service record size: %u\n\r", de_get_len((uint8_t*)spp_service_buffer));
|
||||
sdp_register_service_internal((uint8_t*)spp_service_buffer);
|
||||
sdp_register_service((uint8_t*)spp_service_buffer);
|
||||
memset(dummy_service_buffer, 0, sizeof(dummy_service_buffer));
|
||||
sdp_create_dummy_service((uint8_t*)dummy_service_buffer, "UUID128 Test");
|
||||
de_dump_data_element((uint8_t*)dummy_service_buffer);
|
||||
printf("Dummy service record size: %u\n\r", de_get_len((uint8_t*)dummy_service_buffer));
|
||||
sdp_register_service_internal((uint8_t*)dummy_service_buffer);
|
||||
sdp_register_service((uint8_t*)dummy_service_buffer);
|
||||
|
||||
sdp_query_rfcomm_register_callback(handle_query_rfcomm_event, NULL);
|
||||
|
||||
|
@ -202,12 +202,11 @@ int btstack_main(int argc, const char * argv[]){
|
||||
|
||||
hfp_ag_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset((uint8_t *)hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_ag_create_sdp_record((uint8_t *)hfp_service_buffer, rfcomm_channel_nr, hfp_ag_service_name, 0, 0);
|
||||
|
||||
sdp_register_service_internal((uint8_t *)hfp_service_buffer);
|
||||
sdp_register_service((uint8_t *)hfp_service_buffer);
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
@ -236,11 +236,11 @@ int btstack_main(int argc, const char * argv[]){
|
||||
|
||||
hfp_hf_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
memset((uint8_t *)hfp_service_buffer, 0, sizeof(hfp_service_buffer));
|
||||
hfp_hf_create_sdp_record((uint8_t *)hfp_service_buffer, rfcomm_channel_nr, hfp_hf_service_name, 0);
|
||||
sdp_register_service_internal((uint8_t *)hfp_service_buffer);
|
||||
sdp_register_service((uint8_t *)hfp_service_buffer);
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
@ -184,15 +184,15 @@ static void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
|
||||
int btstack_main(int argc, const char * argv[]);
|
||||
int btstack_main(int argc, const char * argv[]){
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
|
||||
hsp_ag_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_ag_service_name);
|
||||
|
||||
hsp_ag_init(rfcomm_channel_nr);
|
||||
hsp_ag_register_packet_handler(packet_handler);
|
||||
|
||||
// init SDP, create record for SPP and register with SDP
|
||||
sdp_init();
|
||||
sdp_register_service_internal((uint8_t *)hsp_service_buffer);
|
||||
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
|
||||
hsp_ag_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_ag_service_name);
|
||||
sdp_register_service((uint8_t *)hsp_service_buffer);
|
||||
|
||||
// turn on!
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
|
@ -305,14 +305,13 @@ int btstack_main(int argc, const char * argv[]){
|
||||
setup_audio();
|
||||
hci_register_sco_packet_handler(&sco_packet_handler);
|
||||
|
||||
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
|
||||
hsp_hs_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_hs_service_name, 0);
|
||||
|
||||
hsp_hs_init(rfcomm_channel_nr);
|
||||
hsp_hs_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
sdp_register_service_internal((uint8_t *)hsp_service_buffer);
|
||||
memset((uint8_t *)hsp_service_buffer, 0, sizeof(hsp_service_buffer));
|
||||
hsp_hs_create_service((uint8_t *)hsp_service_buffer, rfcomm_channel_nr, hsp_hs_service_name, 0);
|
||||
sdp_register_service((uint8_t *)hsp_service_buffer);
|
||||
|
||||
hci_discoverable_control(1);
|
||||
hci_set_class_of_device(0x200418);
|
||||
|
Loading…
x
Reference in New Issue
Block a user