* RFC: GATT server multi-adapter support @ 2011-12-16 16:09 Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth This is an initial work to provide support for multiple adapters in GATT server. Current implementation manages handlers and device connections using global list without taking into account that we can have many adapters plugged. These patches propose a separation among handlers, clients management and other stuff in each adapter. In this way, GATT servers plugins should register their attributes on each adapter. Current interfaces doesn't provide support for that, future work include exposing adapters in the APIS and using adapter drivers to register attributes instead of doing that when the plugin is initialized. These patches don't modify current API yet, they use the default adapter to manage GATT stuff when the adapter is not provided in order to keep backward compatibility. In this way they can be applied without causing compilation problems in GATT dependant plugins which are using current GATT server interface. Comments are welcome. [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter [PATCH 02/11] attrib-server: Register GATT SDP record per each [PATCH 03/11] attrib-server: Add attributes in adapter database [PATCH 04/11] attrib-server: Attach attrib_channel in adapter [PATCH 05/11] attrib-server: Remove global client list [PATCH 06/11] attrib-server: Remove global le_io variable [PATCH 07/11] attrib-server: Attah gatt channels to a adapters [PATCH 08/11] attrib-server: Remove global database list [PATCH 09/11] attrib-server: Mark attrib_channel_detach as [PATCH 10/11] attrib-server: Remove [PATCH 11/11] gatt-example: Use adapter driver to register GATT ^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-16 16:09 RFC: GATT server multi-adapter support Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 02/11] attrib-server: Register GATT SDP record per each adapter Santiago Carot-Nemesio 2011-12-19 14:08 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Claudio Takahasi 0 siblings, 2 replies; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio This patch prepares the structures in att-server to start and stop GATT server whenever an adapter is plugged or unplugged. --- src/attrib-server.c | 168 +++++++++++++++++++++++++++++++++++---------------- 1 files changed, 116 insertions(+), 52 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index b767b72..e8dade8 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -71,12 +71,23 @@ struct group_elem { uint16_t len; }; -static GIOChannel *l2cap_io = NULL; static GIOChannel *le_io = NULL; static GSList *clients = NULL; static uint32_t gatt_sdp_handle = 0; static uint32_t gap_sdp_handle = 0; +struct gatt_adapter { + struct btd_adapter *adapter; + GIOChannel *l2cap_io; + GIOChannel *le_io; + GSList *clients; + uint32_t gatt_sdp_handle; + uint32_t gap_sdp_handle; + GSList *database; +}; + +static GSList *adapters = NULL; + /* GAP attribute handles */ static uint16_t name_handle = 0x0000; static uint16_t appearance_handle = 0x0000; @@ -94,6 +105,60 @@ static bt_uuid_t ccc_uuid = { .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID }; +static void attrib_free(void *data) +{ + struct attribute *a = data; + + g_free(a->data); + g_free(a); +} + +static void channel_free(struct gatt_channel *channel) +{ + g_attrib_unref(channel->attrib); + + g_free(channel); +} + +static void free_gatt_adapter(struct gatt_adapter *gatt_adapter) +{ + g_slist_free_full(gatt_adapter->database, attrib_free); + + if (gatt_adapter->l2cap_io != NULL) { + g_io_channel_unref(gatt_adapter->l2cap_io); + g_io_channel_shutdown(gatt_adapter->l2cap_io, FALSE, NULL); + } + + if (gatt_adapter->le_io != NULL) { + g_io_channel_unref(gatt_adapter->le_io); + g_io_channel_shutdown(gatt_adapter->le_io, FALSE, NULL); + } + + g_slist_free_full(gatt_adapter->clients, (GDestroyNotify) channel_free); + + if (gatt_adapter->gatt_sdp_handle > 0) + remove_record_from_server(gatt_adapter->gatt_sdp_handle); + + if (gatt_adapter->gap_sdp_handle > 0) + remove_record_from_server(gatt_adapter->gap_sdp_handle); + + if (gatt_adapter->adapter != NULL) + btd_adapter_unref(gatt_adapter->adapter); + + g_free(gatt_adapter); +} + +static gint adapter_cmp(gconstpointer a, gconstpointer b) +{ + const struct gatt_adapter *gatt_adapter = a; + const struct btd_adapter *adapter = b; + + if (gatt_adapter->adapter == adapter) + return 0; + + return -1; +} + static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end) { sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto; @@ -689,21 +754,6 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, return enc_mtu_resp(old_mtu, pdu, len); } -static void attrib_free(void *data) -{ - struct attribute *a = data; - - g_free(a->data); - g_free(a); -} - -static void channel_free(struct gatt_channel *channel) -{ - g_attrib_unref(channel->attrib); - - g_free(channel); -} - static void channel_disconnect(void *user_data) { struct gatt_channel *channel = user_data; @@ -1012,74 +1062,88 @@ failed: return FALSE; } -int attrib_server_init(void) +static int attrib_adapter_probe(struct btd_adapter *adapter) { + struct gatt_adapter *gatt_adapter; GError *gerr = NULL; + bdaddr_t addr; + + DBG("Start GATT server in %s", adapter_get_path(adapter)); + + gatt_adapter = g_new0(struct gatt_adapter, 1); + gatt_adapter->adapter = btd_adapter_ref(adapter); + + adapter_get_address(gatt_adapter->adapter, &addr); /* BR/EDR socket */ - l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, + gatt_adapter->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, NULL, NULL, &gerr, - BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY, + BT_IO_OPT_SOURCE_BDADDR, &addr, BT_IO_OPT_PSM, ATT_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); - if (l2cap_io == NULL) { + + if (gatt_adapter->l2cap_io == NULL) { error("%s", gerr->message); g_error_free(gerr); + free_gatt_adapter(gatt_adapter); return -1; } - if (!register_core_services()) - goto failed; + if (!register_core_services()) { + g_io_channel_unref(gatt_adapter->l2cap_io); + free_gatt_adapter(gatt_adapter); + return -1; + } /* LE socket */ - le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, - &le_io, NULL, &gerr, - BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY, + gatt_adapter->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, + &gatt_adapter->le_io, NULL, &gerr, + BT_IO_OPT_SOURCE_BDADDR, &addr, BT_IO_OPT_CID, ATT_CID, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); - if (le_io == NULL) { + + if (gatt_adapter->le_io == NULL) { error("%s", gerr->message); g_error_free(gerr); /* Doesn't have LE support, continue */ } + adapters = g_slist_prepend(adapters, gatt_adapter); return 0; - -failed: - g_io_channel_unref(l2cap_io); - l2cap_io = NULL; - - if (le_io) { - g_io_channel_unref(le_io); - le_io = NULL; - } - - return -1; } -void attrib_server_exit(void) +static void attrib_adapter_remove(struct btd_adapter *adapter) { - g_slist_free_full(database, attrib_free); + struct gatt_adapter *gatt_adapter; + GSList *l; - if (l2cap_io) { - g_io_channel_unref(l2cap_io); - g_io_channel_shutdown(l2cap_io, FALSE, NULL); - } + l = g_slist_find_custom(adapters, adapter, adapter_cmp); + if (l == NULL) + return; - if (le_io) { - g_io_channel_unref(le_io); - g_io_channel_shutdown(le_io, FALSE, NULL); - } + DBG("Stop GATT server in %s", adapter_get_path(adapter)); - g_slist_free_full(clients, (GDestroyNotify) channel_free); + gatt_adapter = l->data; + adapters = g_slist_remove(adapters, gatt_adapter); + free_gatt_adapter(gatt_adapter); +} - if (gatt_sdp_handle) - remove_record_from_server(gatt_sdp_handle); +static struct btd_adapter_driver attrib_adapter_driver = { + .name = "attrib-adapter-driver", + .probe = attrib_adapter_probe, + .remove = attrib_adapter_remove, +}; - if (gap_sdp_handle) - remove_record_from_server(gap_sdp_handle); +int attrib_server_init(void) +{ + return btd_register_adapter_driver(&attrib_adapter_driver); +} + +void attrib_server_exit(void) +{ + btd_unregister_adapter_driver(&attrib_adapter_driver); } uint32_t attrib_create_sdp(uint16_t handle, const char *name) -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 02/11] attrib-server: Register GATT SDP record per each adapter 2011-12-16 16:09 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 03/11] attrib-server: Add attributes in adapter database Santiago Carot-Nemesio 2011-12-19 14:08 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Claudio Takahasi 1 sibling, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio Each adapter has its own SDP registry wich will be managed separately. This patch makes a wrapper over attrib_create_sdp function using the default adapter in order to keep backward compatibility with the gatt server interface until the api is finally updated. --- src/attrib-server.c | 203 ++++++++++++++++++++++++++++++--------------------- 1 files changed, 120 insertions(+), 83 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index e8dade8..5a5024c 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -73,8 +73,6 @@ struct group_elem { static GIOChannel *le_io = NULL; static GSList *clients = NULL; -static uint32_t gatt_sdp_handle = 0; -static uint32_t gap_sdp_handle = 0; struct gatt_adapter { struct btd_adapter *adapter; @@ -159,6 +157,30 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b) return -1; } +static struct gatt_adapter *get_default_gatt_adapter(void) +{ + struct gatt_adapter *gatt_adapter; + struct btd_adapter *adapter; + GSList *l; + + adapter = manager_get_default_adapter(); + if (adapter == NULL) { + error("Can't get default adapter"); + return NULL; + } + + l = g_slist_find_custom(adapters, adapter, adapter_cmp); + if (l == NULL) { + error("Not GATT server initialized on adapter %s", + adapter_get_path(adapter)); + return NULL; + } + + gatt_adapter = l->data; + + return gatt_adapter; +} + static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end) { sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto; @@ -230,6 +252,85 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2) return attrib1->handle - attrib2->handle; } +static struct attribute *find_primary_range(struct gatt_adapter *gatt_adapter, + uint16_t start, uint16_t *end) +{ + struct attribute *attrib; + guint h = start; + GSList *l; + + if (end == NULL) + return NULL; + + l = g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h), + handle_cmp); + if (!l) + return NULL; + + attrib = l->data; + + if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0) + return NULL; + + *end = start; + + for (l = l->next; l; l = l->next) { + struct attribute *a = l->data; + + if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || + bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) + break; + + *end = a->handle; + } + + return attrib; +} + +static uint32_t attrib_create_sdp_new(struct gatt_adapter *gatt_adapter, + uint16_t handle, const char *name) +{ + sdp_record_t *record; + struct attribute *a; + uint16_t end = 0; + uuid_t svc, gap_uuid; + bdaddr_t addr; + + a = find_primary_range(gatt_adapter, handle, &end); + + if (a == NULL) + return 0; + + if (a->len == 2) + sdp_uuid16_create(&svc, att_get_u16(a->data)); + else if (a->len == 16) + sdp_uuid128_create(&svc, a->data); + else + return 0; + + record = server_record_new(&svc, handle, end); + if (record == NULL) + return 0; + + if (name) + sdp_set_info_attr(record, name, "BlueZ", NULL); + + sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID); + if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) { + sdp_set_url_attr(record, "http://www.bluez.org/", + "http://www.bluez.org/", + "http://www.bluez.org/"); + } + + adapter_get_address(gatt_adapter->adapter, &addr); + if (add_record_to_server(&addr, record) < 0) + sdp_record_free(record); + else + return record->handle; + + return 0; +} + static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode, int reqs) { @@ -586,39 +687,6 @@ static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid, return len; } -static struct attribute *find_primary_range(uint16_t start, uint16_t *end) -{ - struct attribute *attrib; - guint h = start; - GSList *l; - - if (end == NULL) - return NULL; - - l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp); - if (!l) - return NULL; - - attrib = l->data; - - if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0) - return NULL; - - *end = start; - - for (l = l->next; l; l = l->next) { - struct attribute *a = l->data; - - if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || - bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) - break; - - *end = a->handle; - } - - return attrib; -} - static uint16_t read_value(struct gatt_channel *channel, uint16_t handle, uint8_t *pdu, int len) { @@ -998,7 +1066,7 @@ static void confirm_event(GIOChannel *io, void *user_data) return; } -static gboolean register_core_services(void) +static gboolean register_core_services(struct gatt_adapter *gatt_adapter) { uint8_t atval[256]; bt_uuid_t uuid; @@ -1035,10 +1103,12 @@ static gboolean register_core_services(void) att_put_u16(appearance, &atval[0]); attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2); - gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile"); - if (gap_sdp_handle == 0) { + + gatt_adapter->gap_sdp_handle = attrib_create_sdp_new(gatt_adapter, + 0x0001, "Generic Access Profile"); + if (gatt_adapter->gap_sdp_handle == 0) { error("Failed to register GAP service record"); - goto failed; + return FALSE; } /* GATT service: primary service definition */ @@ -1046,20 +1116,14 @@ static gboolean register_core_services(void) 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) { + gatt_adapter->gatt_sdp_handle = attrib_create_sdp_new(gatt_adapter, + 0x0010, "Generic Attribute Profile"); + if (gatt_adapter->gatt_sdp_handle == 0) { error("Failed to register GATT service record"); - goto failed; + return FALSE;; } return TRUE; - -failed: - if (gap_sdp_handle) - remove_record_from_server(gap_sdp_handle); - - return FALSE; } static int attrib_adapter_probe(struct btd_adapter *adapter) @@ -1090,7 +1154,7 @@ static int attrib_adapter_probe(struct btd_adapter *adapter) return -1; } - if (!register_core_services()) { + if (!register_core_services(gatt_adapter)) { g_io_channel_unref(gatt_adapter->l2cap_io); free_gatt_adapter(gatt_adapter); return -1; @@ -1144,47 +1208,20 @@ int attrib_server_init(void) void attrib_server_exit(void) { btd_unregister_adapter_driver(&attrib_adapter_driver); + g_slist_free_full(database, attrib_free); } 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, gap_uuid; - - a = find_primary_range(handle, &end); - - if (a == NULL) - return 0; + struct gatt_adapter *gatt_adapter; - if (a->len == 2) - sdp_uuid16_create(&svc, att_get_u16(a->data)); - else if (a->len == 16) - sdp_uuid128_create(&svc, a->data); - else - return 0; + DBG("Deprecated function"); - record = server_record_new(&svc, handle, end); - if (record == NULL) + gatt_adapter = get_default_gatt_adapter(); + if (gatt_adapter == NULL) return 0; - if (name) - sdp_set_info_attr(record, name, "BlueZ", NULL); - - sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID); - if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) { - 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; - - return 0; + return attrib_create_sdp_new(gatt_adapter, handle, name); } void attrib_free_sdp(uint32_t sdp_handle) -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 03/11] attrib-server: Add attributes in adapter database 2011-12-16 16:09 ` [PATCH 02/11] attrib-server: Register GATT SDP record per each adapter Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 04/11] attrib-server: Attach attrib_channel in adapter clients list Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio Each adapter has its own database so the global database list will be removed. This patch makes a wrapper over attrib_db_add function to get the default adapter in order to add attributes in the default adapter, int his way we keep backward compatibility with the gatt server interface until the api is updated. --- src/attrib-server.c | 68 +++++++++++++++++++++++++++++++++----------------- 1 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index 5a5024c..b2f0edb 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -331,6 +331,33 @@ static uint32_t attrib_create_sdp_new(struct gatt_adapter *gatt_adapter, return 0; } +static struct attribute *attrib_db_add_new(struct gatt_adapter *gatt_adapter, + uint16_t handle, bt_uuid_t *uuid, int read_reqs, + int write_reqs, const uint8_t *value, int len) +{ + struct attribute *a; + guint h = handle; + + DBG("handle=0x%04x", handle); + + if (g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h), + handle_cmp)) + return NULL; + + a = g_new0(struct attribute, 1); + a->len = len; + a->data = g_memdup(value, len); + a->handle = handle; + a->uuid = *uuid; + a->read_reqs = read_reqs; + a->write_reqs = write_reqs; + + gatt_adapter->database = g_slist_insert_sorted(gatt_adapter->database, + a, attribute_cmp); + + return a; +} + static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode, int reqs) { @@ -1075,7 +1102,8 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter) /* GAP service: primary service definition */ bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID); att_put_u16(GENERIC_ACCESS_PROFILE_ID, &atval[0]); - attrib_db_add(0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2); + attrib_db_add_new(gatt_adapter, 0x0001, &uuid, ATT_NONE, + ATT_NOT_PERMITTED, atval, 2); /* GAP service: device name characteristic */ name_handle = 0x0006; @@ -1083,12 +1111,13 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter) atval[0] = ATT_CHAR_PROPER_READ; att_put_u16(name_handle, &atval[1]); att_put_u16(GATT_CHARAC_DEVICE_NAME, &atval[3]); - attrib_db_add(0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5); + attrib_db_add_new(gatt_adapter, 0x0004, &uuid, ATT_NONE, + ATT_NOT_PERMITTED, atval, 5); /* GAP service: device name attribute */ bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME); - attrib_db_add(name_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED, - NULL, 0); + attrib_db_add_new(gatt_adapter, name_handle, &uuid, ATT_NONE, + ATT_NOT_PERMITTED, NULL, 0); /* GAP service: device appearance characteristic */ appearance_handle = 0x0008; @@ -1096,13 +1125,14 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter) atval[0] = ATT_CHAR_PROPER_READ; att_put_u16(appearance_handle, &atval[1]); att_put_u16(GATT_CHARAC_APPEARANCE, &atval[3]); - attrib_db_add(0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5); + attrib_db_add_new(gatt_adapter, 0x0007, &uuid, ATT_NONE, + ATT_NOT_PERMITTED, atval, 5); /* GAP service: device appearance attribute */ bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE); att_put_u16(appearance, &atval[0]); - attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED, - atval, 2); + attrib_db_add_new(gatt_adapter, appearance_handle, &uuid, ATT_NONE, + ATT_NOT_PERMITTED, atval, 2); gatt_adapter->gap_sdp_handle = attrib_create_sdp_new(gatt_adapter, 0x0001, "Generic Access Profile"); @@ -1114,7 +1144,8 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter) /* GATT service: primary service definition */ bt_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); + attrib_db_add_new(gatt_adapter, 0x0010, &uuid, ATT_NONE, + ATT_NOT_PERMITTED, atval, 2); gatt_adapter->gatt_sdp_handle = attrib_create_sdp_new(gatt_adapter, 0x0010, "Generic Attribute Profile"); @@ -1260,25 +1291,16 @@ uint16_t attrib_db_find_avail(uint16_t nitems) struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs, int write_reqs, const uint8_t *value, int len) { - struct attribute *a; - guint h = handle; + struct gatt_adapter *gatt_adapter; - DBG("handle=0x%04x", handle); + DBG("Deprecated function!"); - if (g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp)) + gatt_adapter = get_default_gatt_adapter(); + if (gatt_adapter == NULL) return NULL; - a = g_new0(struct attribute, 1); - a->len = len; - a->data = g_memdup(value, len); - a->handle = handle; - a->uuid = *uuid; - a->read_reqs = read_reqs; - a->write_reqs = write_reqs; - - database = g_slist_insert_sorted(database, a, attribute_cmp); - - return a; + return attrib_db_add_new(gatt_adapter, handle, uuid, read_reqs, write_reqs, + value, len); } int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value, -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 04/11] attrib-server: Attach attrib_channel in adapter clients list 2011-12-16 16:09 ` [PATCH 03/11] attrib-server: Add attributes in adapter database Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 05/11] attrib-server: Remove global client list Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio This patch attaches attribute channels to the adapter list instead of using the global client list. --- src/attrib-server.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index b2f0edb..751091e 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -146,6 +146,17 @@ static void free_gatt_adapter(struct gatt_adapter *gatt_adapter) g_free(gatt_adapter); } +static gint adapter_cmp_addr(gconstpointer a, gconstpointer b) +{ + const struct gatt_adapter *gatt_adapter = a; + const bdaddr_t *bdaddr = b; + bdaddr_t src; + + adapter_get_address(gatt_adapter->adapter, &src); + + return bacmp(&src, bdaddr); +} + static gint adapter_cmp(gconstpointer a, gconstpointer b) { const struct gatt_adapter *gatt_adapter = a; @@ -157,6 +168,22 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b) return -1; } +static struct gatt_adapter *find_gatt_adapter(const bdaddr_t *bdaddr) +{ + GSList *l; + + l = g_slist_find_custom(adapters, bdaddr, adapter_cmp_addr); + if (l == NULL) { + char addr[18]; + + ba2str(bdaddr, addr); + error("Not GATT adapter found for address %s", addr); + return NULL; + } + + return l->data; +} + static struct gatt_adapter *get_default_gatt_adapter(void) { struct gatt_adapter *gatt_adapter; @@ -852,8 +879,13 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, static void channel_disconnect(void *user_data) { struct gatt_channel *channel = user_data; + struct gatt_adapter *gatt_adapter; + + gatt_adapter = find_gatt_adapter(&channel->src); + if (gatt_adapter == NULL) + return; - clients = g_slist_remove(clients, channel); + gatt_adapter->clients = g_slist_remove(gatt_adapter->clients, channel); channel_free(channel); } @@ -983,7 +1015,7 @@ done: guint attrib_channel_attach(GAttrib *attrib, gboolean out) { - struct btd_adapter *adapter; + struct gatt_adapter *gatt_adapter; struct btd_device *device; struct gatt_channel *channel; GIOChannel *io; @@ -1008,10 +1040,12 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out) return 0; } - adapter = manager_find_adapter(&channel->src); + gatt_adapter = find_gatt_adapter(&channel->src); + if (gatt_adapter == NULL) + return 0; ba2str(&channel->dst, addr); - device = adapter_find_device(adapter, addr); + device = adapter_find_device(gatt_adapter->adapter, addr); if (device_is_bonded(device) == FALSE) delete_device_ccc(&channel->src, &channel->dst); @@ -1033,7 +1067,7 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out) g_attrib_set_disconnect_function(channel->attrib, channel_disconnect, channel); - clients = g_slist_append(clients, channel); + gatt_adapter->clients = g_slist_append(gatt_adapter->clients, channel); return channel->id; } -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 05/11] attrib-server: Remove global client list 2011-12-16 16:09 ` [PATCH 04/11] attrib-server: Attach attrib_channel in adapter clients list Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 06/11] attrib-server: Remove global le_io variable Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- src/attrib-server.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index 751091e..453bdd7 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -72,7 +72,6 @@ struct group_elem { }; static GIOChannel *le_io = NULL; -static GSList *clients = NULL; struct gatt_adapter { struct btd_adapter *adapter; @@ -1082,11 +1081,18 @@ static gint channel_id_cmp(gconstpointer data, gconstpointer user_data) gboolean attrib_channel_detach(guint id) { + struct gatt_adapter *gatt_adapter; struct gatt_channel *channel; GSList *l; - l = g_slist_find_custom(clients, GUINT_TO_POINTER(id), - channel_id_cmp); + DBG("Deprecated function"); + + gatt_adapter = get_default_gatt_adapter(); + if (gatt_adapter == NULL) + return FALSE; + + l = g_slist_find_custom(gatt_adapter->clients, GUINT_TO_POINTER(id), + channel_id_cmp); if (!l) return FALSE; -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 06/11] attrib-server: Remove global le_io variable 2011-12-16 16:09 ` [PATCH 05/11] attrib-server: Remove global client list Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 07/11] attrib-server: Attah gatt channels to a adapters Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio Get ride of the global low energy channel in order to use the low energy channel managed in each adapter. --- src/attrib-server.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index 453bdd7..c7a9a67 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -71,8 +71,6 @@ struct group_elem { uint16_t len; }; -static GIOChannel *le_io = NULL; - struct gatt_adapter { struct btd_adapter *adapter; GIOChannel *l2cap_io; @@ -861,6 +859,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) { + struct gatt_adapter *gatt_adapter; guint old_mtu = channel->mtu; if (mtu < ATT_DEFAULT_LE_MTU) @@ -868,7 +867,11 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, else channel->mtu = MIN(mtu, channel->mtu); - bt_io_set(le_io, BT_IO_L2CAP, NULL, + gatt_adapter = find_gatt_adapter(&channel->src); + if (gatt_adapter == NULL) + return 0; + + bt_io_set(gatt_adapter->le_io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, channel->mtu, BT_IO_OPT_INVALID); -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 07/11] attrib-server: Attah gatt channels to a adapters 2011-12-16 16:09 ` [PATCH 06/11] attrib-server: Remove global le_io variable Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 08/11] attrib-server: Remove global database list Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio This patch adds a new field to gatt channel structure to referentiate the adapter which the channel belongs --- src/attrib-server.c | 22 +++++++++++++--------- 1 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index c7a9a67..ad2dfd5 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -54,15 +54,6 @@ static GSList *database = NULL; -struct gatt_channel { - bdaddr_t src; - bdaddr_t dst; - GAttrib *attrib; - guint mtu; - gboolean le; - guint id; - gboolean encrypted; -}; struct group_elem { uint16_t handle; @@ -81,6 +72,17 @@ struct gatt_adapter { GSList *database; }; +struct gatt_channel { + bdaddr_t src; + bdaddr_t dst; + GAttrib *attrib; + guint mtu; + gboolean le; + guint id; + gboolean encrypted; + struct gatt_adapter *gatt_adapter; +}; + static GSList *adapters = NULL; /* GAP attribute handles */ @@ -1046,6 +1048,8 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out) if (gatt_adapter == NULL) return 0; + channel->gatt_adapter = gatt_adapter; + ba2str(&channel->dst, addr); device = adapter_find_device(gatt_adapter->adapter, addr); -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 08/11] attrib-server: Remove global database list 2011-12-16 16:09 ` [PATCH 07/11] attrib-server: Attah gatt channels to a adapters Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 09/11] attrib-server: Mark attrib_channel_detach as deprecated Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio Each adapter use its own databa list to manage handlers so all operations should managed in adapters instead of using a global handler list. --- src/attrib-server.c | 68 ++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index ad2dfd5..61bb05b 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -52,9 +52,6 @@ #include "attrib-server.h" -static GSList *database = NULL; - - struct group_elem { uint16_t handle; uint16_t end; @@ -425,7 +422,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start, struct att_data_list *adl; struct attribute *a; struct group_elem *cur, *old = NULL; - GSList *l, *groups; + GSList *l, *groups, *database; uint16_t length, last_handle, last_size = 0; uint8_t status; int i; @@ -444,6 +441,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start, return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000, ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len); + database = channel->gatt_adapter->database; last_handle = end; for (l = database, groups = NULL, cur = NULL; l; l = l->next) { @@ -536,7 +534,7 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start, uint8_t *pdu, int len) { struct att_data_list *adl; - GSList *l, *types; + GSList *l, *types, *database; struct attribute *a; uint16_t num, length; uint8_t status; @@ -546,6 +544,7 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start, return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start, ATT_ECODE_INVALID_HANDLE, pdu, len); + database = channel->gatt_adapter->database; for (l = database, length = 0, types = NULL; l; l = l->next) { a = l->data; @@ -612,11 +611,12 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start, return length; } -static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len) +static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end, + uint8_t *pdu, int len) { struct attribute *a; struct att_data_list *adl; - GSList *l, *info; + GSList *l, *info, *database; uint8_t format, last_type = BT_UUID_UNSPEC; uint16_t length, num; int i; @@ -625,6 +625,7 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len) return enc_error_resp(ATT_OP_FIND_INFO_REQ, start, ATT_ECODE_INVALID_HANDLE, pdu, len); + database = channel->gatt_adapter->database; for (l = database, info = NULL, num = 0; l; l = l->next) { a = l->data; @@ -684,12 +685,13 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len) return length; } -static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid, - const uint8_t *value, int vlen, uint8_t *opdu, int mtu) +static int find_by_type(struct gatt_channel *channel, uint16_t start, + uint16_t end, bt_uuid_t *uuid, const uint8_t *value, + int vlen, uint8_t *opdu, int mtu) { struct attribute *a; struct att_range *range; - GSList *l, *matches; + GSList *l, *matches, *database; int len; if (start > end || start == 0x0000) @@ -697,6 +699,7 @@ static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid, ATT_ECODE_INVALID_HANDLE, opdu, mtu); /* Searching first requested handle number */ + database = channel->gatt_adapter->database; for (l = database, matches = NULL, range = NULL; l; l = l->next) { a = l->data; @@ -749,7 +752,8 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle, uint16_t cccval; guint h = handle; - l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp); + l = g_slist_find_custom(channel->gatt_adapter->database, + GUINT_TO_POINTER(h), handle_cmp); if (!l) return enc_error_resp(ATT_OP_READ_REQ, handle, ATT_ECODE_INVALID_HANDLE, pdu, len); @@ -786,7 +790,8 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle, uint16_t cccval; guint h = handle; - l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp); + l = g_slist_find_custom(channel->gatt_adapter->database, + GUINT_TO_POINTER(h), handle_cmp); if (!l) return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, ATT_ECODE_INVALID_HANDLE, pdu, len); @@ -828,7 +833,8 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle, GSList *l; guint h = handle; - l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp); + l = g_slist_find_custom(channel->gatt_adapter->database, + GUINT_TO_POINTER(h), handle_cmp); if (!l) return enc_error_resp(ATT_OP_WRITE_REQ, handle, ATT_ECODE_INVALID_HANDLE, pdu, len); @@ -965,7 +971,7 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len, goto done; } - length = find_info(start, end, opdu, channel->mtu); + length = find_info(channel, start, end, opdu, channel->mtu); break; case ATT_OP_WRITE_REQ: length = dec_write_req(ipdu, len, &start, value, &vlen); @@ -991,7 +997,7 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len, goto done; } - length = find_by_type(start, end, &uuid, value, vlen, + length = find_by_type(channel, start, end, &uuid, value, vlen, opdu, channel->mtu); break; case ATT_OP_HANDLE_CNF: @@ -1286,7 +1292,6 @@ int attrib_server_init(void) void attrib_server_exit(void) { btd_unregister_adapter_driver(&attrib_adapter_driver); - g_slist_free_full(database, attrib_free); } uint32_t attrib_create_sdp(uint16_t handle, const char *name) @@ -1309,12 +1314,19 @@ void attrib_free_sdp(uint32_t sdp_handle) uint16_t attrib_db_find_avail(uint16_t nitems) { + struct gatt_adapter *gatt_adapter; uint16_t handle; GSList *l; + DBG("Deprecated function"); + g_assert(nitems > 0); - for (l = database, handle = 0; l; l = l->next) { + gatt_adapter = get_default_gatt_adapter(); + if (gatt_adapter == NULL) + return 0; + + for (l = gatt_adapter->database, handle = 0; l; l = l->next) { struct attribute *a = l->data; if (handle && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || @@ -1353,13 +1365,21 @@ struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs, int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value, int len, struct attribute **attr) { + struct gatt_adapter *gatt_adapter; struct attribute *a; GSList *l; guint h = handle; + DBG("Deprecated function!"); + DBG("handle=0x%04x", handle); - l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp); + gatt_adapter = get_default_gatt_adapter(); + if (gatt_adapter == NULL) + return -ENOENT; + + l = g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h), + handle_cmp); if (!l) return -ENOENT; @@ -1383,18 +1403,26 @@ int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value, int attrib_db_del(uint16_t handle) { + struct gatt_adapter *gatt_adapter; struct attribute *a; GSList *l; guint h = handle; + DBG("Deprecated function!"); + DBG("handle=0x%04x", handle); - l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp); + gatt_adapter = get_default_gatt_adapter(); + if (gatt_adapter == NULL) + return -ENOENT; + + l = g_slist_find_custom(gatt_adapter->database, GUINT_TO_POINTER(h), + handle_cmp); if (!l) return -ENOENT; a = l->data; - database = g_slist_remove(database, a); + gatt_adapter->database = g_slist_remove(gatt_adapter->database, a); g_free(a->data); g_free(a); -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 09/11] attrib-server: Mark attrib_channel_detach as deprecated 2011-12-16 16:09 ` [PATCH 08/11] attrib-server: Remove global database list Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 10/11] attrib-server: Remove attrib_server_exit/attrib_server_exit functions Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio All public attrib-server functions are marked as deprecated until they expose adapter facilities to operate with. This is a transactional patch toward multiple adapter support is implemented. All those functions use default adaptar in order to keep backward compatibility. --- src/attrib-server.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/src/attrib-server.c b/src/attrib-server.c index 61bb05b..0414ff7 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -1433,6 +1433,8 @@ int attrib_gap_set(uint16_t uuid, const uint8_t *value, int len) { uint16_t handle; + DBG("Deprecated function!"); + /* FIXME: Missing Privacy and Reconnection Address */ switch (uuid) { -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 10/11] attrib-server: Remove attrib_server_exit/attrib_server_exit functions 2011-12-16 16:09 ` [PATCH 09/11] attrib-server: Mark attrib_channel_detach as deprecated Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes Santiago Carot-Nemesio 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio We need neither to init nor stop gatt server whenever the demon starts and finishes the execution, instead of doing that, we init or stop the GATT server when the adapter is initialized or removed. Furthermore, we don't use btd_adapter_driver any more because the GATT server must be already initialized before any plugin use it. --- src/adapter.c | 7 +++++++ src/adapter.h | 3 +++ src/attrib-server.c | 24 ++++-------------------- src/hcid.h | 3 --- src/main.c | 8 -------- 5 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/adapter.c b/src/adapter.c index 1a701a4..200e9d9 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -2483,6 +2483,10 @@ gboolean adapter_init(struct btd_adapter *adapter) } sdp_init_services_list(&adapter->bdaddr); + + if (main_opts.attrib_server) + btd_adapter_gatt_server_start(adapter); + load_drivers(adapter); clear_blocked(adapter); load_devices(adapter); @@ -2542,6 +2546,9 @@ void adapter_remove(struct btd_adapter *adapter) g_slist_free(adapter->devices); unload_drivers(adapter); + if (main_opts.attrib_server) + btd_adapter_gatt_server_stop(adapter); + g_slist_free(adapter->pin_callbacks); /* Return adapter to down state if it was not up on init */ diff --git a/src/adapter.h b/src/adapter.h index ff1d659..2f8f125 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -275,3 +275,6 @@ int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter, int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter, bdaddr_t *bdaddr); + +int btd_adapter_gatt_server_start(struct btd_adapter *adapter); +void btd_adapter_gatt_server_stop(struct btd_adapter *adapter); \ No newline at end of file diff --git a/src/attrib-server.c b/src/attrib-server.c index 0414ff7..12065fa 100644 --- a/src/attrib-server.c +++ b/src/attrib-server.c @@ -1210,13 +1210,13 @@ static gboolean register_core_services(struct gatt_adapter *gatt_adapter) return TRUE; } -static int attrib_adapter_probe(struct btd_adapter *adapter) +int btd_adapter_gatt_server_start(struct btd_adapter *adapter) { struct gatt_adapter *gatt_adapter; GError *gerr = NULL; bdaddr_t addr; - DBG("Start GATT server in %s", adapter_get_path(adapter)); + DBG("Start GATT server in hci%d", adapter_get_dev_id(adapter)); gatt_adapter = g_new0(struct gatt_adapter, 1); gatt_adapter->adapter = btd_adapter_ref(adapter); @@ -1262,7 +1262,7 @@ static int attrib_adapter_probe(struct btd_adapter *adapter) return 0; } -static void attrib_adapter_remove(struct btd_adapter *adapter) +void btd_adapter_gatt_server_stop(struct btd_adapter *adapter) { struct gatt_adapter *gatt_adapter; GSList *l; @@ -1271,29 +1271,13 @@ static void attrib_adapter_remove(struct btd_adapter *adapter) if (l == NULL) return; - DBG("Stop GATT server in %s", adapter_get_path(adapter)); + DBG("Stop GATT server in hci%d", adapter_get_dev_id(adapter)); gatt_adapter = l->data; adapters = g_slist_remove(adapters, gatt_adapter); free_gatt_adapter(gatt_adapter); } -static struct btd_adapter_driver attrib_adapter_driver = { - .name = "attrib-adapter-driver", - .probe = attrib_adapter_probe, - .remove = attrib_adapter_remove, -}; - -int attrib_server_init(void) -{ - return btd_register_adapter_driver(&attrib_adapter_driver); -} - -void attrib_server_exit(void) -{ - btd_unregister_adapter_driver(&attrib_adapter_driver); -} - uint32_t attrib_create_sdp(uint16_t handle, const char *name) { struct gatt_adapter *gatt_adapter; diff --git a/src/hcid.h b/src/hcid.h index e993a16..1987b7d 100644 --- a/src/hcid.h +++ b/src/hcid.h @@ -63,6 +63,3 @@ void plugin_cleanup(void); void rfkill_init(void); void rfkill_exit(void); - -int attrib_server_init(void); -void attrib_server_exit(void); diff --git a/src/main.c b/src/main.c index 3031f09..74ec3fa 100644 --- a/src/main.c +++ b/src/main.c @@ -521,11 +521,6 @@ int main(int argc, char *argv[]) start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT); - if (main_opts.attrib_server) { - if (attrib_server_init() < 0) - error("Can't initialize attribute server"); - } - /* Loading plugins has to be done after D-Bus has been setup since * the plugins might wanna expose some paths on the bus. However the * best order of how to init various subsystems of the Bluetooth @@ -551,9 +546,6 @@ int main(int argc, char *argv[]) plugin_cleanup(); - if (main_opts.attrib_server) - attrib_server_exit(); - stop_sdp_server(); agent_exit(); -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes 2011-12-16 16:09 ` [PATCH 10/11] attrib-server: Remove attrib_server_exit/attrib_server_exit functions Santiago Carot-Nemesio @ 2011-12-16 16:09 ` Santiago Carot-Nemesio 2011-12-17 9:28 ` Santiago Carot 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot-Nemesio @ 2011-12-16 16:09 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio GATT servers should register their attributes on each adapter when it is plugged instead of doing that when the plugins is loaded. This patch registers a new adapter driver to manage plug and unplug events in order to register attributes in each GATT served managed in each adapter. --- plugins/gatt-example.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 files changed, 39 insertions(+), 7 deletions(-) diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c index 6d9b6b8..c719697 100644 --- a/plugins/gatt-example.c +++ b/plugins/gatt-example.c @@ -29,6 +29,7 @@ #include <glib.h> #include <bluetooth/uuid.h> #include <errno.h> +#include <adapter.h> #include "plugin.h" #include "hcid.h" @@ -59,6 +60,8 @@ static GSList *sdp_handles = NULL; +static gboolean started = FALSE; + static uint8_t battery_state_read(struct attribute *a, gpointer user_data) { uint8_t value; @@ -436,19 +439,19 @@ static void register_weight_service(const uint16_t vendor[2]) GUINT_TO_POINTER(sdp_handle)); } -static int gatt_example_init(void) +static int gatt_example_adapter_probe(struct btd_adapter *adapter) { uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0}; uint16_t vendor_range[2] = {0, 0}; - if (!main_opts.attrib_server) { - DBG("Attribute server is disabled"); + /* FIXME: Add support for more than one adapter */ + + if (started) return -1; - } if (!register_battery_service()) { DBG("Battery service could not be registered"); - return -EIO; + return -1; } register_manuf1_service(manuf1_range); @@ -457,12 +460,15 @@ static int gatt_example_init(void) register_vendor_service(vendor_range); register_weight_service(vendor_range); + started = TRUE; return 0; } -static void gatt_example_exit(void) +static void gatt_example_adapter_remove(struct btd_adapter *adapter) { - if (!main_opts.attrib_server) + /* FIXME: Add support for more than one adapter */ + + if (!started) return; while (sdp_handles) { @@ -471,6 +477,32 @@ static void gatt_example_exit(void) attrib_free_sdp(handle); sdp_handles = g_slist_remove(sdp_handles, sdp_handles->data); } + + started = FALSE; +} + +static struct btd_adapter_driver gatt_example_adapter_driver = { + .name = "hdp-adapter-driver", + .probe = gatt_example_adapter_probe, + .remove = gatt_example_adapter_remove, +}; + +static int gatt_example_init(void) +{ + if (!main_opts.attrib_server) { + DBG("Attribute server is disabled"); + return -1; + } + + return btd_register_adapter_driver(&gatt_example_adapter_driver); +} + +static void gatt_example_exit(void) +{ + if (!main_opts.attrib_server) + return; + + btd_register_adapter_driver(&gatt_example_adapter_driver); } BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW, -- 1.7.8 ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes 2011-12-16 16:09 ` [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes Santiago Carot-Nemesio @ 2011-12-17 9:28 ` Santiago Carot 0 siblings, 0 replies; 21+ messages in thread From: Santiago Carot @ 2011-12-17 9:28 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio Hi everybody, 2011/12/16 Santiago Carot-Nemesio <sancane@gmail.com>: > GATT servers should register their attributes on each adapter when > it is plugged instead of doing that when the plugins is loaded. This > patch registers a new adapter driver to manage plug and unplug > events in order to register attributes in each GATT served managed > in each adapter. > --- > plugins/gatt-example.c | 46 +++++++++++++++++++++++++++++++++++++++------- > 1 files changed, 39 insertions(+), 7 deletions(-) > > diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c > index 6d9b6b8..c719697 100644 > --- a/plugins/gatt-example.c > +++ b/plugins/gatt-example.c > @@ -29,6 +29,7 @@ > #include <glib.h> > #include <bluetooth/uuid.h> > #include <errno.h> > +#include <adapter.h> > > #include "plugin.h" > #include "hcid.h" > @@ -59,6 +60,8 @@ > > static GSList *sdp_handles = NULL; > > +static gboolean started = FALSE; > + > static uint8_t battery_state_read(struct attribute *a, gpointer user_data) > { > uint8_t value; > @@ -436,19 +439,19 @@ static void register_weight_service(const uint16_t vendor[2]) > GUINT_TO_POINTER(sdp_handle)); > } > > -static int gatt_example_init(void) > +static int gatt_example_adapter_probe(struct btd_adapter *adapter) > { > uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0}; > uint16_t vendor_range[2] = {0, 0}; > > - if (!main_opts.attrib_server) { > - DBG("Attribute server is disabled"); > + /* FIXME: Add support for more than one adapter */ > + > + if (started) > return -1; > - } > > if (!register_battery_service()) { > DBG("Battery service could not be registered"); > - return -EIO; > + return -1; > } > > register_manuf1_service(manuf1_range); > @@ -457,12 +460,15 @@ static int gatt_example_init(void) > register_vendor_service(vendor_range); > register_weight_service(vendor_range); > > + started = TRUE; > return 0; > } > > -static void gatt_example_exit(void) > +static void gatt_example_adapter_remove(struct btd_adapter *adapter) > { > - if (!main_opts.attrib_server) > + /* FIXME: Add support for more than one adapter */ > + > + if (!started) > return; > > while (sdp_handles) { > @@ -471,6 +477,32 @@ static void gatt_example_exit(void) > attrib_free_sdp(handle); > sdp_handles = g_slist_remove(sdp_handles, sdp_handles->data); > } > + > + started = FALSE; > +} > + > +static struct btd_adapter_driver gatt_example_adapter_driver = { > + .name = "hdp-adapter-driver", > + .probe = gatt_example_adapter_probe, > + .remove = gatt_example_adapter_remove, > +}; > + > +static int gatt_example_init(void) > +{ > + if (!main_opts.attrib_server) { > + DBG("Attribute server is disabled"); > + return -1; > + } > + > + return btd_register_adapter_driver(&gatt_example_adapter_driver); > +} > + > +static void gatt_example_exit(void) > +{ > + if (!main_opts.attrib_server) > + return; > + > + btd_register_adapter_driver(&gatt_example_adapter_driver); > } > > BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW, > -- > 1.7.8 > This last patch is only a proof of concept, don't waste your time rewieging it, just discard it Regards ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-16 16:09 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 02/11] attrib-server: Register GATT SDP record per each adapter Santiago Carot-Nemesio @ 2011-12-19 14:08 ` Claudio Takahasi 2011-12-19 14:35 ` Anderson Lizardo 2011-12-19 14:35 ` Santiago Carot 1 sibling, 2 replies; 21+ messages in thread From: Claudio Takahasi @ 2011-12-19 14:08 UTC (permalink / raw) To: Santiago Carot-Nemesio; +Cc: linux-bluetooth Hi Santiago, On Fri, Dec 16, 2011 at 1:09 PM, Santiago Carot-Nemesio <sancane@gmail.com> wrote: > This patch prepares the structures in att-server to start and stop > GATT server whenever an adapter is plugged or unplugged. > --- > src/attrib-server.c | 168 +++++++++++++++++++++++++++++++++++---------------- > 1 files changed, 116 insertions(+), 52 deletions(-) > > diff --git a/src/attrib-server.c b/src/attrib-server.c > index b767b72..e8dade8 100644 > --- a/src/attrib-server.c > +++ b/src/attrib-server.c > @@ -71,12 +71,23 @@ struct group_elem { > uint16_t len; > }; > > -static GIOChannel *l2cap_io = NULL; > static GIOChannel *le_io = NULL; le_io is not being used anymore. > static GSList *clients = NULL; > static uint32_t gatt_sdp_handle = 0; > static uint32_t gap_sdp_handle = 0; > > +struct gatt_adapter { > + struct btd_adapter *adapter; > + GIOChannel *l2cap_io; > + GIOChannel *le_io; > + GSList *clients; > + uint32_t gatt_sdp_handle; > + uint32_t gap_sdp_handle; > + GSList *database; I recommend to introduce new variable when the it is really being used. "database" and "clients" are used by free functions only, but new elements are not being added in the list by this patch. > +}; > + > +static GSList *adapters = NULL; > + > /* GAP attribute handles */ > static uint16_t name_handle = 0x0000; > static uint16_t appearance_handle = 0x0000; > @@ -94,6 +105,60 @@ static bt_uuid_t ccc_uuid = { > .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID > }; > > +static void attrib_free(void *data) > +{ > + struct attribute *a = data; > + > + g_free(a->data); > + g_free(a); > +} > + > +static void channel_free(struct gatt_channel *channel) > +{ > + g_attrib_unref(channel->attrib); > + > + g_free(channel); > +} > + > +static void free_gatt_adapter(struct gatt_adapter *gatt_adapter) the coding style is "free" at the end of the function name > +{ > + g_slist_free_full(gatt_adapter->database, attrib_free); > + > + if (gatt_adapter->l2cap_io != NULL) { > + g_io_channel_unref(gatt_adapter->l2cap_io); > + g_io_channel_shutdown(gatt_adapter->l2cap_io, FALSE, NULL); > + } > + > + if (gatt_adapter->le_io != NULL) { > + g_io_channel_unref(gatt_adapter->le_io); > + g_io_channel_shutdown(gatt_adapter->le_io, FALSE, NULL); > + } > + > + g_slist_free_full(gatt_adapter->clients, (GDestroyNotify) channel_free); > + > + if (gatt_adapter->gatt_sdp_handle > 0) > + remove_record_from_server(gatt_adapter->gatt_sdp_handle); > + > + if (gatt_adapter->gap_sdp_handle > 0) > + remove_record_from_server(gatt_adapter->gap_sdp_handle); Removing gap_sdp_handle again > + > + if (gatt_adapter->adapter != NULL) > + btd_adapter_unref(gatt_adapter->adapter); > + > + g_free(gatt_adapter); > +} > + > +static gint adapter_cmp(gconstpointer a, gconstpointer b) > +{ > + const struct gatt_adapter *gatt_adapter = a; > + const struct btd_adapter *adapter = b; > + > + if (gatt_adapter->adapter == adapter) > + return 0; > + > + return -1; > +} > + > static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end) > { > sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto; > @@ -689,21 +754,6 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, > return enc_mtu_resp(old_mtu, pdu, len); > } > > -static void attrib_free(void *data) > -{ > - struct attribute *a = data; > - > - g_free(a->data); > - g_free(a); > -} > - > -static void channel_free(struct gatt_channel *channel) > -{ > - g_attrib_unref(channel->attrib); > - > - g_free(channel); > -} > - > static void channel_disconnect(void *user_data) > { > struct gatt_channel *channel = user_data; > @@ -1012,74 +1062,88 @@ failed: > return FALSE; > } > > -int attrib_server_init(void) > +static int attrib_adapter_probe(struct btd_adapter *adapter) > { > + struct gatt_adapter *gatt_adapter; > GError *gerr = NULL; > + bdaddr_t addr; > + > + DBG("Start GATT server in %s", adapter_get_path(adapter)); > + > + gatt_adapter = g_new0(struct gatt_adapter, 1); > + gatt_adapter->adapter = btd_adapter_ref(adapter); > + > + adapter_get_address(gatt_adapter->adapter, &addr); > > /* BR/EDR socket */ > - l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, > + gatt_adapter->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, > NULL, NULL, &gerr, > - BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY, > + BT_IO_OPT_SOURCE_BDADDR, &addr, > BT_IO_OPT_PSM, ATT_PSM, > BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, > BT_IO_OPT_INVALID); > - if (l2cap_io == NULL) { > + > + if (gatt_adapter->l2cap_io == NULL) { > error("%s", gerr->message); > g_error_free(gerr); > + free_gatt_adapter(gatt_adapter); > return -1; > } > > - if (!register_core_services()) > - goto failed; > + if (!register_core_services()) { > + g_io_channel_unref(gatt_adapter->l2cap_io); > + free_gatt_adapter(gatt_adapter); Two unref calls for l2cap_io here. free function also calls unref for l2cap_io > + return -1; > + } > > /* LE socket */ > - le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, > - &le_io, NULL, &gerr, > - BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY, > + gatt_adapter->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, > + &gatt_adapter->le_io, NULL, &gerr, > + BT_IO_OPT_SOURCE_BDADDR, &addr, > BT_IO_OPT_CID, ATT_CID, > BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, > BT_IO_OPT_INVALID); > - if (le_io == NULL) { > + > + if (gatt_adapter->le_io == NULL) { > error("%s", gerr->message); > g_error_free(gerr); > /* Doesn't have LE support, continue */ > } > > + adapters = g_slist_prepend(adapters, gatt_adapter); > return 0; > - > -failed: > - g_io_channel_unref(l2cap_io); > - l2cap_io = NULL; > - > - if (le_io) { > - g_io_channel_unref(le_io); > - le_io = NULL; > - } > - > - return -1; > } > > -void attrib_server_exit(void) > +static void attrib_adapter_remove(struct btd_adapter *adapter) > { > - g_slist_free_full(database, attrib_free); > + struct gatt_adapter *gatt_adapter; > + GSList *l; > > - if (l2cap_io) { > - g_io_channel_unref(l2cap_io); > - g_io_channel_shutdown(l2cap_io, FALSE, NULL); > - } > + l = g_slist_find_custom(adapters, adapter, adapter_cmp); > + if (l == NULL) > + return; > > - if (le_io) { > - g_io_channel_unref(le_io); > - g_io_channel_shutdown(le_io, FALSE, NULL); > - } > + DBG("Stop GATT server in %s", adapter_get_path(adapter)); > > - g_slist_free_full(clients, (GDestroyNotify) channel_free); > + gatt_adapter = l->data; > + adapters = g_slist_remove(adapters, gatt_adapter); > + free_gatt_adapter(gatt_adapter); > +} > > - if (gatt_sdp_handle) > - remove_record_from_server(gatt_sdp_handle); > +static struct btd_adapter_driver attrib_adapter_driver = { > + .name = "attrib-adapter-driver", > + .probe = attrib_adapter_probe, > + .remove = attrib_adapter_remove, > +}; Is there race condition here? Remember that plugins can also register an adapter driver. If a GATT "plugin" wants to register attributes during the probing the attribute server needs to be ready. BR, Claudio ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 14:08 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Claudio Takahasi @ 2011-12-19 14:35 ` Anderson Lizardo 2011-12-19 14:35 ` Santiago Carot 1 sibling, 0 replies; 21+ messages in thread From: Anderson Lizardo @ 2011-12-19 14:35 UTC (permalink / raw) To: Claudio Takahasi; +Cc: Santiago Carot-Nemesio, linux-bluetooth Hi Santiago, On Mon, Dec 19, 2011 at 10:08 AM, Claudio Takahasi <claudio.takahasi@openbossa.org> wrote: >> +static struct btd_adapter_driver attrib_adapter_driver = { >> + .name = "attrib-adapter-driver", >> + .probe = attrib_adapter_probe, >> + .remove = attrib_adapter_remove, >> +}; > > Is there race condition here? Remember that plugins can also register > an adapter driver. > If a GATT "plugin" wants to register attributes during the probing the > attribute server needs to be ready. I agree with Claudio here. We should not rely on adapter drivers for initializing the attribute server (although I previously thought it could be that simple as well). Otherwise, plugins can't also use adapter driver's probe() to register attributes , which defeats the idea of per-adapter ATT attributes. I think the attribute server should be initialized at an early stage, after the adapter is created, but prior to having the adapter drivers called. Regards, -- Anderson Lizardo Instituto Nokia de Tecnologia - INdT Manaus - Brazil ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 14:08 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Claudio Takahasi 2011-12-19 14:35 ` Anderson Lizardo @ 2011-12-19 14:35 ` Santiago Carot 2011-12-19 14:41 ` Anderson Lizardo 1 sibling, 1 reply; 21+ messages in thread From: Santiago Carot @ 2011-12-19 14:35 UTC (permalink / raw) To: Claudio Takahasi; +Cc: linux-bluetooth Hi Claudio, 2011/12/19 Claudio Takahasi <claudio.takahasi@openbossa.org>: > Hi Santiago, > > On Fri, Dec 16, 2011 at 1:09 PM, Santiago Carot-Nemesio > <sancane@gmail.com> wrote: >> This patch prepares the structures in att-server to start and stop >> GATT server whenever an adapter is plugged or unplugged. >> --- >> src/attrib-server.c | 168 +++++++++++++++++++++++++++++++++++---------------- >> 1 files changed, 116 insertions(+), 52 deletions(-) >> >> diff --git a/src/attrib-server.c b/src/attrib-server.c >> index b767b72..e8dade8 100644 >> --- a/src/attrib-server.c >> +++ b/src/attrib-server.c >> @@ -71,12 +71,23 @@ struct group_elem { >> uint16_t len; >> }; >> >> -static GIOChannel *l2cap_io = NULL; >> static GIOChannel *le_io = NULL; > le_io is not being used anymore. > >> static GSList *clients = NULL; >> static uint32_t gatt_sdp_handle = 0; >> static uint32_t gap_sdp_handle = 0; >> >> +struct gatt_adapter { >> + struct btd_adapter *adapter; >> + GIOChannel *l2cap_io; >> + GIOChannel *le_io; >> + GSList *clients; >> + uint32_t gatt_sdp_handle; >> + uint32_t gap_sdp_handle; >> + GSList *database; > > I recommend to introduce new variable when the it is really being > used. "database" and "clients" are used by free functions only, but > new elements are not being added in the list by this patch. > These are a RFC patches, I put them in here so that everybody can see at the first sight what I'm pretending to do. Anycase I agree with you. >> +}; >> + >> +static GSList *adapters = NULL; >> + >> /* GAP attribute handles */ >> static uint16_t name_handle = 0x0000; >> static uint16_t appearance_handle = 0x0000; >> @@ -94,6 +105,60 @@ static bt_uuid_t ccc_uuid = { >> .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID >> }; >> >> +static void attrib_free(void *data) >> +{ >> + struct attribute *a = data; >> + >> + g_free(a->data); >> + g_free(a); >> +} >> + >> +static void channel_free(struct gatt_channel *channel) >> +{ >> + g_attrib_unref(channel->attrib); >> + >> + g_free(channel); >> +} >> + >> +static void free_gatt_adapter(struct gatt_adapter *gatt_adapter) > the coding style is "free" at the end of the function name > >> +{ >> + g_slist_free_full(gatt_adapter->database, attrib_free); >> + >> + if (gatt_adapter->l2cap_io != NULL) { >> + g_io_channel_unref(gatt_adapter->l2cap_io); >> + g_io_channel_shutdown(gatt_adapter->l2cap_io, FALSE, NULL); >> + } >> + >> + if (gatt_adapter->le_io != NULL) { >> + g_io_channel_unref(gatt_adapter->le_io); >> + g_io_channel_shutdown(gatt_adapter->le_io, FALSE, NULL); >> + } >> + >> + g_slist_free_full(gatt_adapter->clients, (GDestroyNotify) channel_free); >> + >> + if (gatt_adapter->gatt_sdp_handle > 0) >> + remove_record_from_server(gatt_adapter->gatt_sdp_handle); >> + >> + if (gatt_adapter->gap_sdp_handle > 0) >> + remove_record_from_server(gatt_adapter->gap_sdp_handle); > > Removing gap_sdp_handle again > >> + >> + if (gatt_adapter->adapter != NULL) >> + btd_adapter_unref(gatt_adapter->adapter); >> + >> + g_free(gatt_adapter); >> +} >> + >> +static gint adapter_cmp(gconstpointer a, gconstpointer b) >> +{ >> + const struct gatt_adapter *gatt_adapter = a; >> + const struct btd_adapter *adapter = b; >> + >> + if (gatt_adapter->adapter == adapter) >> + return 0; >> + >> + return -1; >> +} >> + >> static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end) >> { >> sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto; >> @@ -689,21 +754,6 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, >> return enc_mtu_resp(old_mtu, pdu, len); >> } >> >> -static void attrib_free(void *data) >> -{ >> - struct attribute *a = data; >> - >> - g_free(a->data); >> - g_free(a); >> -} >> - >> -static void channel_free(struct gatt_channel *channel) >> -{ >> - g_attrib_unref(channel->attrib); >> - >> - g_free(channel); >> -} >> - >> static void channel_disconnect(void *user_data) >> { >> struct gatt_channel *channel = user_data; >> @@ -1012,74 +1062,88 @@ failed: >> return FALSE; >> } >> >> -int attrib_server_init(void) >> +static int attrib_adapter_probe(struct btd_adapter *adapter) >> { >> + struct gatt_adapter *gatt_adapter; >> GError *gerr = NULL; >> + bdaddr_t addr; >> + >> + DBG("Start GATT server in %s", adapter_get_path(adapter)); >> + >> + gatt_adapter = g_new0(struct gatt_adapter, 1); >> + gatt_adapter->adapter = btd_adapter_ref(adapter); >> + >> + adapter_get_address(gatt_adapter->adapter, &addr); >> >> /* BR/EDR socket */ >> - l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, >> + gatt_adapter->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, >> NULL, NULL, &gerr, >> - BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY, >> + BT_IO_OPT_SOURCE_BDADDR, &addr, >> BT_IO_OPT_PSM, ATT_PSM, >> BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, >> BT_IO_OPT_INVALID); >> - if (l2cap_io == NULL) { >> + >> + if (gatt_adapter->l2cap_io == NULL) { >> error("%s", gerr->message); >> g_error_free(gerr); >> + free_gatt_adapter(gatt_adapter); >> return -1; >> } >> >> - if (!register_core_services()) >> - goto failed; >> + if (!register_core_services()) { >> + g_io_channel_unref(gatt_adapter->l2cap_io); >> + free_gatt_adapter(gatt_adapter); > > Two unref calls for l2cap_io here. free function also calls unref for l2cap_io > >> + return -1; >> + } >> >> /* LE socket */ >> - le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, >> - &le_io, NULL, &gerr, >> - BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY, >> + gatt_adapter->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, >> + &gatt_adapter->le_io, NULL, &gerr, >> + BT_IO_OPT_SOURCE_BDADDR, &addr, >> BT_IO_OPT_CID, ATT_CID, >> BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, >> BT_IO_OPT_INVALID); >> - if (le_io == NULL) { >> + >> + if (gatt_adapter->le_io == NULL) { >> error("%s", gerr->message); >> g_error_free(gerr); >> /* Doesn't have LE support, continue */ >> } >> >> + adapters = g_slist_prepend(adapters, gatt_adapter); >> return 0; >> - >> -failed: >> - g_io_channel_unref(l2cap_io); >> - l2cap_io = NULL; >> - >> - if (le_io) { >> - g_io_channel_unref(le_io); >> - le_io = NULL; >> - } >> - >> - return -1; >> } >> >> -void attrib_server_exit(void) >> +static void attrib_adapter_remove(struct btd_adapter *adapter) >> { >> - g_slist_free_full(database, attrib_free); >> + struct gatt_adapter *gatt_adapter; >> + GSList *l; >> >> - if (l2cap_io) { >> - g_io_channel_unref(l2cap_io); >> - g_io_channel_shutdown(l2cap_io, FALSE, NULL); >> - } >> + l = g_slist_find_custom(adapters, adapter, adapter_cmp); >> + if (l == NULL) >> + return; >> >> - if (le_io) { >> - g_io_channel_unref(le_io); >> - g_io_channel_shutdown(le_io, FALSE, NULL); >> - } >> + DBG("Stop GATT server in %s", adapter_get_path(adapter)); >> >> - g_slist_free_full(clients, (GDestroyNotify) channel_free); >> + gatt_adapter = l->data; >> + adapters = g_slist_remove(adapters, gatt_adapter); >> + free_gatt_adapter(gatt_adapter); >> +} >> >> - if (gatt_sdp_handle) >> - remove_record_from_server(gatt_sdp_handle); >> +static struct btd_adapter_driver attrib_adapter_driver = { >> + .name = "attrib-adapter-driver", >> + .probe = attrib_adapter_probe, >> + .remove = attrib_adapter_remove, >> +}; > > Is there race condition here? Remember that plugins can also register > an adapter driver. > If a GATT "plugin" wants to register attributes during the probing the > attribute server needs to be ready. > I know that, remember these are transactional patches towardas multi-adapter support. They only prepare the environment to start coding. The patch 11 fixes this issue. In fact, one could think that it should in this place but when I started coding it I thought it was easier to reutilize functions which were already implemented and change it after multi-adapter started working. Changing the order of patches or redo them is easy once I get an ack to do that if the idea showed here is good. I'm just looking for comments about the main idea behind them. Thanks ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 14:35 ` Santiago Carot @ 2011-12-19 14:41 ` Anderson Lizardo 2011-12-19 14:51 ` Santiago Carot 0 siblings, 1 reply; 21+ messages in thread From: Anderson Lizardo @ 2011-12-19 14:41 UTC (permalink / raw) To: Santiago Carot; +Cc: Claudio Takahasi, linux-bluetooth Hi Santiago, On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <sancane@gmail.com> wrote: >> Is there race condition here? Remember that plugins can also register >> an adapter driver. >> If a GATT "plugin" wants to register attributes during the probing the >> attribute server needs to be ready. >> > > I know that, remember these are transactional patches towardas > multi-adapter support. They only prepare the environment to start > coding. The patch 11 fixes this issue. In fact, one could think that > it should in this place but when I started coding it I thought it was > easier to reutilize functions which were already implemented and > change it after multi-adapter started working. I don't think patch 11 fixes the architectural issue of initializing the attribute databases on a adapter driver. You can't guarantee it will be initialized prior to other adapter drivers (registered by GATT plugins). > Changing the order of patches or redo them is easy once I get an ack > to do that if the idea showed here is good. I'm just looking for > comments about the main idea behind them. Please take our comments as responses to the RFC :) Regards, -- Anderson Lizardo Instituto Nokia de Tecnologia - INdT Manaus - Brazil ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 14:41 ` Anderson Lizardo @ 2011-12-19 14:51 ` Santiago Carot 2011-12-19 14:54 ` Santiago Carot 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot @ 2011-12-19 14:51 UTC (permalink / raw) To: Anderson Lizardo; +Cc: Claudio Takahasi, linux-bluetooth Hi Anderson, 2011/12/19 Anderson Lizardo <anderson.lizardo@openbossa.org>: > Hi Santiago, > > On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <sancane@gmail.com> wrote: >>> Is there race condition here? Remember that plugins can also register >>> an adapter driver. >>> If a GATT "plugin" wants to register attributes during the probing the >>> attribute server needs to be ready. >>> >> >> I know that, remember these are transactional patches towardas >> multi-adapter support. They only prepare the environment to start >> coding. The patch 11 fixes this issue. In fact, one could think that >> it should in this place but when I started coding it I thought it was >> easier to reutilize functions which were already implemented and >> change it after multi-adapter started working. > > I don't think patch 11 fixes the architectural issue of initializing > the attribute databases on a adapter driver. You can't guarantee it > will be initialized prior to other adapter drivers (registered by GATT > plugins). > Patch 11 removes the adapter driver usage and initializes the GATT server (and related stuff) in the adapter during the adapter setup, this is operation is done before any other adapter plugin is called: diff --git a/src/adapter.c b/src/adapter.c index 1a701a4..200e9d9 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -2483,6 +2483,10 @@ gboolean adapter_init(struct btd_adapter *adapter) } sdp_init_services_list(&adapter->bdaddr); + + if (main_opts.attrib_server) + btd_adapter_gatt_server_start(adapter); + load_drivers(adapter); clear_blocked(adapter); load_devices(adapter); Please, corect me if I'm wrong. > Please take our comments as responses to the RFC :) Of course, and they are very welcome ;) Regards. ^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 14:51 ` Santiago Carot @ 2011-12-19 14:54 ` Santiago Carot 2011-12-19 16:17 ` Anderson Lizardo 0 siblings, 1 reply; 21+ messages in thread From: Santiago Carot @ 2011-12-19 14:54 UTC (permalink / raw) To: Anderson Lizardo; +Cc: Claudio Takahasi, linux-bluetooth Hi, 2011/12/19 Santiago Carot <sancane@gmail.com>: > Hi Anderson, > > 2011/12/19 Anderson Lizardo <anderson.lizardo@openbossa.org>: >> Hi Santiago, >> >> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <sancane@gmail.com> wrote: >>>> Is there race condition here? Remember that plugins can also register >>>> an adapter driver. >>>> If a GATT "plugin" wants to register attributes during the probing the >>>> attribute server needs to be ready. >>>> >>> >>> I know that, remember these are transactional patches towardas >>> multi-adapter support. They only prepare the environment to start >>> coding. The patch 11 fixes this issue. In fact, one could think that >>> it should in this place but when I started coding it I thought it was >>> easier to reutilize functions which were already implemented and >>> change it after multi-adapter started working. >> Sorry: patch 10 is supposed to deal with that :P >> I don't think patch 11 fixes the architectural issue of initializing >> the attribute databases on a adapter driver. You can't guarantee it >> will be initialized prior to other adapter drivers (registered by GATT >> plugins). >> > > Patch 11 removes the adapter driver usage and initializes the GATT > server (and related stuff) in the adapter during the adapter setup, > this is operation is done before any other adapter plugin is called: > > diff --git a/src/adapter.c b/src/adapter.c > index 1a701a4..200e9d9 100644 > --- a/src/adapter.c > +++ b/src/adapter.c > @@ -2483,6 +2483,10 @@ gboolean adapter_init(struct btd_adapter *adapter) > } > > sdp_init_services_list(&adapter->bdaddr); > + > + if (main_opts.attrib_server) > + btd_adapter_gatt_server_start(adapter); > + > load_drivers(adapter); > clear_blocked(adapter); > load_devices(adapter); > > Please, corect me if I'm wrong. > >> Please take our comments as responses to the RFC :) > > Of course, and they are very welcome ;) > Regards. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 14:54 ` Santiago Carot @ 2011-12-19 16:17 ` Anderson Lizardo 2011-12-19 18:13 ` Santiago Carot 0 siblings, 1 reply; 21+ messages in thread From: Anderson Lizardo @ 2011-12-19 16:17 UTC (permalink / raw) To: Santiago Carot; +Cc: Claudio Takahasi, linux-bluetooth Hi Santiago, On Mon, Dec 19, 2011 at 10:54 AM, Santiago Carot <sancane@gmail.com> wrote: > Hi, > > 2011/12/19 Santiago Carot <sancane@gmail.com>: >> Hi Anderson, >> >> 2011/12/19 Anderson Lizardo <anderson.lizardo@openbossa.org>: >>> Hi Santiago, >>> >>> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <sancane@gmail.com> wrote: >>>>> Is there race condition here? Remember that plugins can also register >>>>> an adapter driver. >>>>> If a GATT "plugin" wants to register attributes during the probing the >>>>> attribute server needs to be ready. >>>>> >>>> >>>> I know that, remember these are transactional patches towardas >>>> multi-adapter support. They only prepare the environment to start >>>> coding. The patch 11 fixes this issue. In fact, one could think that >>>> it should in this place but when I started coding it I thought it was >>>> easier to reutilize functions which were already implemented and >>>> change it after multi-adapter started working. >>> > > Sorry: patch 10 is supposed to deal with that :P Ok. Now it makes sense :) I still had not time to review the full series (only took a look on Claudio comments). Still, I'm not sure adding a whole adapter driver just to remove it later on the same series is worth the trouble. Looks like you are fixing an issue introduced on the same series. Is it possible for you to rearrange the series so it is not necessary to introduce the adapter driver? If not, please improve the patches commit messages to explain why it is introduced (and the known problems), and that it is removed on a later patch. This helps a lot tracing regressions later. Best Regards, -- Anderson Lizardo Instituto Nokia de Tecnologia - INdT Manaus - Brazil ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support 2011-12-19 16:17 ` Anderson Lizardo @ 2011-12-19 18:13 ` Santiago Carot 0 siblings, 0 replies; 21+ messages in thread From: Santiago Carot @ 2011-12-19 18:13 UTC (permalink / raw) To: Anderson Lizardo; +Cc: Claudio Takahasi, linux-bluetooth Hi, 2011/12/19 Anderson Lizardo <anderson.lizardo@openbossa.org>: > Hi Santiago, > > On Mon, Dec 19, 2011 at 10:54 AM, Santiago Carot <sancane@gmail.com> wrote: >> Hi, >> >> 2011/12/19 Santiago Carot <sancane@gmail.com>: >>> Hi Anderson, >>> >>> 2011/12/19 Anderson Lizardo <anderson.lizardo@openbossa.org>: >>>> Hi Santiago, >>>> >>>> On Mon, Dec 19, 2011 at 10:35 AM, Santiago Carot <sancane@gmail.com> wrote: >>>>>> Is there race condition here? Remember that plugins can also register >>>>>> an adapter driver. >>>>>> If a GATT "plugin" wants to register attributes during the probing the >>>>>> attribute server needs to be ready. >>>>>> >>>>> >>>>> I know that, remember these are transactional patches towardas >>>>> multi-adapter support. They only prepare the environment to start >>>>> coding. The patch 11 fixes this issue. In fact, one could think that >>>>> it should in this place but when I started coding it I thought it was >>>>> easier to reutilize functions which were already implemented and >>>>> change it after multi-adapter started working. >>>> >> >> Sorry: patch 10 is supposed to deal with that :P > > Ok. Now it makes sense :) I still had not time to review the full > series (only took a look on Claudio comments). > > Still, I'm not sure adding a whole adapter driver just to remove it > later on the same series is worth the trouble. Looks like you are > fixing an issue introduced on the same series. > > Is it possible for you to rearrange the series so it is not necessary > to introduce the adapter driver? I'll try to redo the patches again, don't worry about that, I have sent them in this way to be sure I was following the right toward the multi-adapter suport, I didn't want to spent the time fixing the patches until being sure that this is the architecture we were looking for. Regards. ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2011-12-19 18:13 UTC | newest] Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-12-16 16:09 RFC: GATT server multi-adapter support Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 02/11] attrib-server: Register GATT SDP record per each adapter Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 03/11] attrib-server: Add attributes in adapter database Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 04/11] attrib-server: Attach attrib_channel in adapter clients list Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 05/11] attrib-server: Remove global client list Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 06/11] attrib-server: Remove global le_io variable Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 07/11] attrib-server: Attah gatt channels to a adapters Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 08/11] attrib-server: Remove global database list Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 09/11] attrib-server: Mark attrib_channel_detach as deprecated Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 10/11] attrib-server: Remove attrib_server_exit/attrib_server_exit functions Santiago Carot-Nemesio 2011-12-16 16:09 ` [PATCH 11/11] gatt-example: Use adapter driver to register GATT attributes Santiago Carot-Nemesio 2011-12-17 9:28 ` Santiago Carot 2011-12-19 14:08 ` [PATCH 01/11] attrib-server: Initial steps to provide multi-adapter GATT server support Claudio Takahasi 2011-12-19 14:35 ` Anderson Lizardo 2011-12-19 14:35 ` Santiago Carot 2011-12-19 14:41 ` Anderson Lizardo 2011-12-19 14:51 ` Santiago Carot 2011-12-19 14:54 ` Santiago Carot 2011-12-19 16:17 ` Anderson Lizardo 2011-12-19 18:13 ` Santiago Carot
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.