SDP registration of Primary GATT Services
cover SDP registration of Primary GATT Services
This addresses Anderson's issue with the SDP registration. It maintains the prior APIs and adds a couple which can be called any time after a complete Primary Service has been inserted into the attribute database.
This allows the attrib-server user to pick and choose the services he wants to expose to BR/EDR devices, as opposed to LE only devices. It also gives a mechanism to remove the SDP record from the SDP db.
It also has improved naming (attrib_*) to tie all the parts together.
--
Brian Gix
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
PATCH 1/1 Add SDP registration of Primary GATT services
Add capability to register SDP record for Primary Services.
--- attrib/example.c | 29 +++++++++- src/attrib-server.c | 162 +++++++++++++++++++++++++++++++++++++++------------ src/attrib-server.h | 2 + 3 files changed, 155 insertions(+), 38 deletions(-)
attrib/example.c +28 -1
@@ -59,6 +59,9 @@#define FMT_KILOGRAM_UUID 0xA010#define FMT_HANGING_UUID 0xA011 +#define SDP_RECORD_COUNT 10 +uint32_t sdp_handles[SDP_RECORD_COUNT ]; +static int register_attributes (void ) {const char *desc_out_temp ="Outside Temperature" ;
@@ -77,6 +80,7 @@ static int register_attributes(void)uint8_t atval[256 ];uuid_t uuid;int len; +int i =0 ;/* Battery state service: primary service definition */ sdp_uuid16_create (&uuid,GATT_PRIM_SVC_UUID );
@@ -101,6 +105,11 @@ static int register_attributes(void) atval[1 ] =0x00 ;attrib_db_add (0x0111 , &uuid,ATT_NONE ,ATT_AUTHENTICATION , atval,2 ); +/* Add an SDP record for the above service */ + sdp_handles[i] =attrib_create_sdp (0x0100 ,"Battery State Service" ); +if (sdp_handles[i]) + i++; +/* Thermometer: primary service definition */ sdp_uuid16_create (&uuid,GATT_PRIM_SVC_UUID );att_put_u16 (THERM_HUMIDITY_SVC_UUID , &atval[0 ]);
@@ -116,7 +125,8 @@ static int register_attributes(void)/* Thermometer: Include */ att_put_u16 (0x0550 , &atval[0 ]);att_put_u16 (0x0568 , &atval[2 ]); -attrib_db_add (0x0202 , &uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval,4 ); +att_put_u16 (VENDOR_SPECIFIC_SVC_UUID , &atval[4 ]); +attrib_db_add (0x0202 , &uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval,6 );/* Thermometer: temperature characteristic */ sdp_uuid16_create (&uuid,GATT_CHARAC_UUID );
@@ -173,6 +183,11 @@ static int register_attributes(void)strncpy ((char *) atval, desc_out_hum, len);attrib_db_add (0x0214 , &uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval, len); +/* Add an SDP record for the above service */ + sdp_handles[i] =attrib_create_sdp (0x0200 ,"Thermometer" ); +if (sdp_handles[i]) + i++; +/* Secondary Service: Manufacturer Service */ sdp_uuid16_create (&uuid,GATT_SND_SVC_UUID );att_put_u16 (MANUFACTURER_SVC_UUID , &atval[0 ]);
@@ -299,6 +314,11 @@ static int register_attributes(void)strncpy ((char *) atval, desc_weight, len);attrib_db_add (0x0685 , &uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval, len); +/* Add an SDP record for the above service */ + sdp_handles[i] =attrib_create_sdp (0x0680 ,"Weight Service" ); +if (sdp_handles[i]) + i++; +return 0 ; }
@@ -309,4 +329,11 @@ int server_example_init(void)void server_example_exit (void ) { +int i; + +for (i =0 ; i <SDP_RECORD_COUNT ; i++) +if (sdp_handles[i]) { +attrib_free_sdp (sdp_handles[i]); + sdp_handles[i] =0 ; + } }
src/attrib-server.c +125 -37
240 lines not on this page · raw message
src/attrib-server.h +2 -0
@@ -30,3 +30,5 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,int attrib_db_update (uint16_t handle,uuid_t *uuid,const uint8_t *value,int len);int attrib_db_del (uint16_t handle); +uint32_t attrib_create_sdp (uint16_t handle,const char *name); +void attrib_free_sdp (uint32_t sdp_handle);
Signature · 6 lines
1.7.1 -- Brian Gix [email protected] Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Re: [PATCH 1/1] Add SDP registration of Primary GATT services
Please ignore --> I have some merging to do.
Quoted 351 lines · Brian Gix
Add capability to register SDP record for Primary Services.
--- attrib/example.c | 29 +++++++++- src/attrib-server.c | 162 +++++++++++++++++++++++++++++++++++++++------------ src/attrib-server.h | 2 + 3 files changed, 155 insertions(+), 38 deletions(-)attrib/example.c +28
-1@@ -59,6 +59,9 @@#define FMT_KILOGRAM_UUID 0xA010#define FMT_HANGING_UUID 0xA011 +#define SDP_RECORD_COUNT 10 +uint32_t sdp_handles[SDP_RECORD_COUNT ]; +static int register_attributes (void ) {const char *desc_out_temp ="Outside Temperature" ;@@ -77,6 +80,7 @@ static int register_attributes(void)uint8_t atval[256 ];uuid_t uuid;int len; +int i =0 ;/* Battery state service: primary service definition */ sdp_uuid16_create (&uuid,GATT_PRIM_SVC_UUID );@@ -101,6 +105,11 @@ static int register_attributes(void) atval[1 ] =0x00 ;attrib_db_add (0x0111 ,&uuid,ATT_NONE ,ATT_AUTHENTICATION , atval,2 ); +/* Add an SDP record for the above service */ + sdp_handles[i] =attrib_create_sdp (0x0100 ,"Battery State Service" ); +if (sdp_handles[i]) + i++; +/* Thermometer: primary service definition */ sdp_uuid16_create (&uuid,GATT_PRIM_SVC_UUID );att_put_u16 (THERM_HUMIDITY_SVC_UUID ,&atval[0 ]);@@ -116,7 +125,8 @@ static int register_attributes(void)/* Thermometer: Include */ att_put_u16 (0x0550 ,&atval[0 ]);att_put_u16 (0x0568 ,&atval[2 ]); -attrib_db_add (0x0202 ,&uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval,4 ); +att_put_u16 (VENDOR_SPECIFIC_SVC_UUID ,&atval[4 ]); +attrib_db_add (0x0202 ,&uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval,6 );/* Thermometer: temperature characteristic */ sdp_uuid16_create (&uuid,GATT_CHARAC_UUID );@@ -173,6 +183,11 @@ static int register_attributes(void)strncpy ((char *) atval, desc_out_hum, len);attrib_db_add (0x0214 ,&uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval, len); +/* Add an SDP record for the above service */ + sdp_handles[i] =attrib_create_sdp (0x0200 ,"Thermometer" ); +if (sdp_handles[i]) + i++; +/* Secondary Service: Manufacturer Service */ sdp_uuid16_create (&uuid,GATT_SND_SVC_UUID );att_put_u16 (MANUFACTURER_SVC_UUID ,&atval[0 ]);@@ -299,6 +314,11 @@ static int register_attributes(void)strncpy ((char *) atval, desc_weight, len);attrib_db_add (0x0685 ,&uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval, len); +/* Add an SDP record for the above service */ + sdp_handles[i] =attrib_create_sdp (0x0680 ,"Weight Service" ); +if (sdp_handles[i]) + i++; +return 0 ; }@@ -309,4 +329,11 @@ int server_example_init(void)void server_example_exit (void ) { +int i; + +for (i =0 ; i<SDP_RECORD_COUNT ; i++) +if (sdp_handles[i]) { +attrib_free_sdp (sdp_handles[i]); + sdp_handles[i] =0 ; + } }src/attrib-server.c +125
-37@@ -70,7 +70,8 @@ struct group_elem {static GIOChannel *l2cap_io =NULL ;static GIOChannel *le_io =NULL ;static GSList *clients =NULL ; -static uint32_t sdp_handle =0 ; +static uint32_t gatt_sdp_handle =0 ; +static uint32_t gap_sdp_handle =0 ;static uuid_t prim_uuid = { .type =SDP_UUID16 ,@@ -81,14 +82,19 @@ static uuid_t snd_uuid = { .value.uuid16 = GATT_SND_SVC_UUID }; -static sdp_record_t *server_record_new (void ) +static sdp_record_t *server_record_new (uuid_t *uuid,uint16_t start,uint16_t end) { -sdp_list_t *svclass_id, *apseq, *proto[2 ], *profiles, *root, *aproto; +sdp_list_t *svclass_id, *apseq, *proto[2 ], *root, *aproto;uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap; -sdp_profile_desc_t profile;sdp_record_t *record;sdp_data_t *psm, *sh, *eh; -uint16_t lp =GATT_PSM , start =0x0001 , end =0xffff ; +uint16_t lp =GATT_PSM ; + +if (uuid ==NULL ) +return NULL ; + +if (start> end) +return NULL ; record =sdp_record_alloc ();if (record ==NULL )@@ -99,17 +105,10 @@ static sdp_record_t *server_record_new(void)sdp_set_browse_groups (record, root);sdp_list_free (root,NULL ); -sdp_uuid16_create (&gatt_uuid,GENERIC_ATTRIB_SVCLASS_ID ); - svclass_id =sdp_list_append (NULL ,&gatt_uuid); + svclass_id =sdp_list_append (NULL , uuid);sdp_set_service_classes (record, svclass_id);sdp_list_free (svclass_id,NULL ); -sdp_uuid16_create (&profile.uuid,GENERIC_ATTRIB_PROFILE_ID ); - profile.version =0x0100 ; - profiles =sdp_list_append (NULL ,&profile); -sdp_set_profile_descs (record, profiles); -sdp_list_free (profiles,NULL ); -sdp_uuid16_create (&l2cap,L2CAP_UUID ); proto[0 ] =sdp_list_append (NULL ,&l2cap); psm =sdp_data_alloc (SDP_UINT16 ,&lp);@@ -127,11 +126,6 @@ static sdp_record_t *server_record_new(void) aproto =sdp_list_append (NULL , apseq);sdp_set_access_protos (record, aproto); -sdp_set_info_attr (record,"Generic Attribute Profile" ,"BlueZ" ,NULL ); - -sdp_set_url_attr (record,"http://www.bluez.org/" , -"http://www.bluez.org/" ,"http://www.bluez.org/" ); -sdp_set_service_id (record, gatt_uuid);sdp_data_free (psm);@@ -176,6 +170,40 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,return 0 ; } +static struct attribute *find_primary_range (uint16_t start,uint16_t *end) +{ +struct attribute *a, *attrib =NULL ; +GSList *l; +gboolean found = FALSE; + +if (end ==NULL ) +return NULL ; + +for (l = database; l; l = l->next) { + a = l->data; + +if (a->handle< start) +continue ; + +if ((a->handle == start)&& +sdp_uuid_cmp (&a->uuid,&prim_uuid) ==0 ) { + found = TRUE; + *end = start; + attrib = a; +continue ; + }else if (!found) +break ; + +if (sdp_uuid_cmp (&a->uuid,&prim_uuid) ==0 || +sdp_uuid_cmp (&a->uuid,&snd_uuid) ==0 ) +break ; +else + *end = a->handle; + } + +return attrib; +} +static uint16_t read_by_group (struct gatt_channel *channel,uint16_t start,uint16_t end,uuid_t *uuid,uint8_t *pdu,int len)@@ -607,7 +635,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,static uint16_t mtu_exchange (struct gatt_channel *channel,uint16_t mtu,uint8_t *pdu,int len) { - channel->mtu =MIN (mtu,ATT_MAX_MTU ); + channel->mtu =MIN (mtu, channel->mtu);return enc_mtu_resp (channel->mtu, pdu, len); }@@ -794,7 +822,7 @@ static void confirm_event(GIOChannel *io, void *user_data)return ; } -static void register_core_services (void ) +static gboolean register_core_services (void ) {uint8_t atval[256 ];uuid_t uuid;@@ -820,17 +848,37 @@ static void register_core_services(void)/* TODO: Implement Appearance characteristic. It is mandatory for * Peripheral/Central GAP roles. */ + gap_sdp_handle =attrib_create_sdp (0x0001 ,"Generic Access Profile" ); + +if (gap_sdp_handle ==0 ) { +error ("Failed to register GAP service record" ); + goto failed; + }/* GATT service: primary service definition */ sdp_uuid16_create (&uuid,GATT_PRIM_SVC_UUID );att_put_u16 (GENERIC_ATTRIB_PROFILE_ID ,&atval[0 ]);attrib_db_add (0x0010 ,&uuid,ATT_NONE ,ATT_NOT_PERMITTED , atval,2 ); + + gatt_sdp_handle =attrib_create_sdp (0x0010 , +"Generic Attribute Profile" ); +if (gatt_sdp_handle ==0 ) { +error ("Failed to register GATT service record" ); + goto failed; + } + +return TRUE; + +failed: +if (gap_sdp_handle) +remove_record_from_server (gap_sdp_handle); + +return FALSE; }int attrib_server_init (void ) {GError *gerr =NULL ; -sdp_record_t *record;/* BR/EDR socket */ l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,@@ -846,21 +894,8 @@ int attrib_server_init(void)return -1 ; } - record =server_record_new (); -if (record ==NULL ) { -error ("Unable to create GATT service record" ); +if (!register_core_services ()) goto failed; - } - -if (add_record_to_server (BDADDR_ANY , record)<0 ) { -error ("Failed to register GATT service record" ); -sdp_record_free (record); - goto failed; - } - - sdp_handle = record->handle; - -register_core_services ();if (!main_opts.le)return 0 ;@@ -919,8 +954,61 @@ void attrib_server_exit(void)g_slist_free (clients); -if (sdp_handle) -remove_record_from_server (sdp_handle); +if (gatt_sdp_handle) +remove_record_from_server (gatt_sdp_handle); + +if (gap_sdp_handle) +remove_record_from_server (gap_sdp_handle); +} + +uint32_t attrib_create_sdp (uint16_t handle,const char *name) +{ +sdp_record_t *record; +struct attribute *a; +uint16_t end =0 ; +uuid_t svc; + + a =find_primary_range (handle,&end); + +if (a ==NULL ) + goto failed; + +if (a->len ==2 ) { + svc.type =SDP_UUID16 ; + svc.value.uuid16 =att_get_u16 (a->data); + }else if (a->len ==16 ) { + svc.type =SDP_UUID128 ; +memcpy (&svc.value.uuid128, a->data,sizeof (uint128_t)); + }else + goto failed; + + record =server_record_new (&svc, handle, end); + +if (record ==NULL ) + goto failed; + +if (name) +sdp_set_info_attr (record, name,"BlueZ" ,NULL ); + +if (svc.type ==SDP_UUID16 && + svc.value.uuid16 ==GENERIC_ACCESS_PROFILE_ID ) { +sdp_set_url_attr (record,"http://www.bluez.org/" , +"http://www.bluez.org/" , +"http://www.bluez.org/" ); + } + +if (add_record_to_server (BDADDR_ANY , record)<0 ) +sdp_record_free (record); +else +return record->handle; + +failed: +return 0 ; +} + +void attrib_free_sdp (uint32_t sdp_handle) +{ +remove_record_from_server (sdp_handle); } int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,src/attrib-server.h +2
-0@@ -30,3 +30,5 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,int attrib_db_update (uint16_t handle,uuid_t *uuid,const uint8_t *value,int len);int attrib_db_del (uint16_t handle); +uint32_t attrib_create_sdp (uint16_t handle,const char *name); +void attrib_free_sdp (uint32_t sdp_handle);
Signature · 4 lines
Brian Gix [email protected] Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum