2011-12-27 14:33:11

by Santiago Carot

[permalink] [raw]
Subject: Multi-adapter GATT server support

This is a new set of patches toward multiple adapter gatt server
support wich includes the changes suggested previously.

[PATCH 1/8] attrib-server: Initial steps towards multi-adapter GATT
[PATCH 2/8] attrib-server: Register GATT SDP record per each adapter
[PATCH 3/8] attrib-server: Add attributes in adapter database
[PATCH 4/8] attrib-server: Attach attrib_channel in adapter clients
[PATCH 5/8] attrib-server: Remove global le_io variable
[PATCH 6/8] attrib-server: Remove global database list
[PATCH 7/8] attrib-server: Mark attrib_channel_detach as deprecated
[PATCH 8/8] gatt-example: Use adapter driver to register GATT


2011-12-30 10:58:23

by Johan Hedberg

[permalink] [raw]
Subject: Re: Multi-adapter GATT server support

Hi Santiago,

On Tue, Dec 27, 2011, Santiago Carot-Nemesio wrote:
> [PATCH 1/8] attrib-server: Initial steps towards multi-adapter GATT
> [PATCH 2/8] attrib-server: Register GATT SDP record per each adapter
> [PATCH 3/8] attrib-server: Add attributes in adapter database
> [PATCH 4/8] attrib-server: Attach attrib_channel in adapter clients
> [PATCH 5/8] attrib-server: Remove global le_io variable
> [PATCH 6/8] attrib-server: Remove global database list
> [PATCH 7/8] attrib-server: Mark attrib_channel_detach as deprecated
> [PATCH 8/8] gatt-example: Use adapter driver to register GATT

All patches in this set have been applied. Thanks.

Johan

2011-12-27 14:33:19

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 8/8] gatt-example: Use adapter driver to register GATT attributes

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 | 98 ++++++++++++++++++++++++++++++++++++++---------
1 files changed, 79 insertions(+), 19 deletions(-)

diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
index 6d9b6b8..4e8f36f 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"
@@ -57,7 +58,39 @@
#define FMT_KILOGRAM_UUID 0xA010
#define FMT_HANGING_UUID 0xA011

-static GSList *sdp_handles = NULL;
+struct gatt_example_adapter {
+ struct btd_adapter *adapter;
+ GSList *sdp_handles;
+};
+
+static GSList *adapters = NULL;
+
+static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
+{
+ while (gadapter->sdp_handles != NULL) {
+ uint32_t handle = GPOINTER_TO_UINT(gadapter->sdp_handles->data);
+
+ attrib_free_sdp(handle);
+ gadapter->sdp_handles = g_slist_remove(gadapter->sdp_handles,
+ gadapter->sdp_handles->data);
+ }
+
+ if (gadapter->adapter != NULL)
+ btd_adapter_unref(gadapter->adapter);
+
+ g_free(gadapter);
+}
+
+static gint adapter_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_example_adapter *gatt_adapter = a;
+ const struct btd_adapter *adapter = b;
+
+ if (gatt_adapter->adapter == adapter)
+ return 0;
+
+ return -1;
+}

static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
{
@@ -81,8 +114,8 @@ static gboolean register_battery_service(void)
GATT_OPT_INVALID);
}

-static void register_termometer_service(const uint16_t manuf1[2],
- const uint16_t manuf2[2])
+static void register_termometer_service(struct gatt_example_adapter *adapter,
+ const uint16_t manuf1[2], const uint16_t manuf2[2])
{
const char *desc_out_temp = "Outside Temperature";
const char *desc_out_hum = "Outside Relative Humidity";
@@ -189,7 +222,7 @@ static void register_termometer_service(const uint16_t manuf1[2],
/* Add an SDP record for the above service */
sdp_handle = attrib_create_sdp(start_handle, "Thermometer");
if (sdp_handle)
- sdp_handles = g_slist_prepend(sdp_handles,
+ adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
GUINT_TO_POINTER(sdp_handle));
}

@@ -352,7 +385,8 @@ static void register_vendor_service(uint16_t range[2])
range[1] = start_handle + svc_size - 1;
}

-static void register_weight_service(const uint16_t vendor[2])
+static void register_weight_service(struct gatt_example_adapter *adapter,
+ const uint16_t vendor[2])
{
const char *desc_weight = "Rucksack Weight";
const uint128_t char_weight_uuid_btorder = {
@@ -432,45 +466,71 @@ static void register_weight_service(const uint16_t vendor[2])
/* Add an SDP record for the above service */
sdp_handle = attrib_create_sdp(start_handle, "Weight Service");
if (sdp_handle)
- sdp_handles = g_slist_prepend(sdp_handles,
+ adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
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};
+ struct gatt_example_adapter *gadapter;

- if (!main_opts.attrib_server) {
- DBG("Attribute server is disabled");
- return -1;
- }
+ gadapter = g_new0(struct gatt_example_adapter, 1);
+ gadapter->adapter = btd_adapter_ref(adapter);

if (!register_battery_service()) {
DBG("Battery service could not be registered");
+ gatt_example_adapter_free(gadapter);
return -EIO;
}

register_manuf1_service(manuf1_range);
register_manuf2_service(manuf2_range);
- register_termometer_service(manuf1_range, manuf2_range);
+ register_termometer_service(gadapter, manuf1_range, manuf2_range);
register_vendor_service(vendor_range);
- register_weight_service(vendor_range);
+ register_weight_service(gadapter, vendor_range);
+
+ adapters = g_slist_append(adapters, gadapter);

return 0;
}

-static void gatt_example_exit(void)
+static void gatt_example_adapter_remove(struct btd_adapter *adapter)
{
- if (!main_opts.attrib_server)
+ struct gatt_example_adapter *gadapter;
+ GSList *l;
+
+ l = g_slist_find_custom(adapters, adapter, adapter_cmp);
+ if (l == NULL)
return;

- while (sdp_handles) {
- uint32_t handle = GPOINTER_TO_UINT(sdp_handles->data);
+ gadapter = l->data;
+ gatt_example_adapter_free(gadapter);
+}

- attrib_free_sdp(handle);
- sdp_handles = g_slist_remove(sdp_handles, sdp_handles->data);
+static struct btd_adapter_driver gatt_example_adapter_driver = {
+ .name = "gatt-example-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 -ENOTSUP;
}
+
+ return btd_register_adapter_driver(&gatt_example_adapter_driver);
+}
+
+static void gatt_example_exit(void)
+{
+ if (!main_opts.attrib_server)
+ return;
+
+ btd_unregister_adapter_driver(&gatt_example_adapter_driver);
}

BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW,
--
1.7.8.1


2011-12-27 14:33:18

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 7/8] attrib-server: Mark attrib_channel_detach as deprecated

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 219c7c9..3a3eebb 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -1402,6 +1402,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.1


2011-12-27 14:33:17

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 6/8] attrib-server: Remove global database list

Each server use its own databa list to manage handlers so all
operations should managed separately by each GATT server instead
of using a global handler list.
---
src/attrib-server.c | 67 ++++++++++++++++++++++++++++++++++++--------------
1 files changed, 48 insertions(+), 19 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index d987d76..219c7c9 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -52,7 +52,6 @@

#include "attrib-server.h"

-static GSList *database = NULL;
static GSList *servers = NULL;

struct gatt_server {
@@ -419,7 +418,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;
@@ -439,6 +438,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len);

last_handle = end;
+ database = channel->server->database;
for (l = database, groups = NULL, cur = NULL; l; l = l->next) {

a = l->data;
@@ -530,7 +530,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;
@@ -540,6 +540,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->server->database;
for (l = database, length = 0, types = NULL; l; l = l->next) {

a = l->data;
@@ -606,11 +607,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;
@@ -619,6 +621,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->server->database;
for (l = database, info = NULL, num = 0; l; l = l->next) {
a = l->data;

@@ -678,12 +681,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)
@@ -691,6 +695,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->server->database;
for (l = database, matches = NULL, range = NULL; l; l = l->next) {
a = l->data;

@@ -743,7 +748,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->server->database,
+ GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return enc_error_resp(ATT_OP_READ_REQ, handle,
ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -780,7 +786,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->server->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);
@@ -822,7 +829,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->server->database,
+ GUINT_TO_POINTER(h), handle_cmp);
if (!l)
return enc_error_resp(ATT_OP_WRITE_REQ, handle,
ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -950,7 +958,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);
@@ -976,7 +984,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:
@@ -1253,8 +1261,6 @@ void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
server = l->data;
servers = g_slist_remove(servers, server);
gatt_server_free(server);
-
- g_slist_free_full(database, attrib_free);
}

uint32_t attrib_create_sdp(uint16_t handle, const char *name)
@@ -1277,12 +1283,19 @@ void attrib_free_sdp(uint32_t sdp_handle)

uint16_t attrib_db_find_avail(uint16_t nitems)
{
+ struct gatt_server *server;
uint16_t handle;
GSList *l;

+ DBG("Deprecated function!");
+
g_assert(nitems > 0);

- for (l = database, handle = 0; l; l = l->next) {
+ server = get_default_gatt_server();
+ if (server == NULL)
+ return 0;
+
+ for (l = server->database, handle = 0; l; l = l->next) {
struct attribute *a = l->data;

if (handle && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
@@ -1321,13 +1334,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_server *server;
struct attribute *a;
GSList *l;
guint h = handle;

+ DBG("Deprecated function!");
+
+ server = get_default_gatt_server();
+ if (server == NULL)
+ return -ENOENT;
+
DBG("handle=0x%04x", handle);

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return -ENOENT;

@@ -1351,18 +1372,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_server *server;
struct attribute *a;
GSList *l;
guint h = handle;

+ DBG("Deprecated function!");
+
+ server = get_default_gatt_server();
+ if (server == NULL)
+ return -ENOENT;
+
DBG("handle=0x%04x", handle);

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return -ENOENT;

a = l->data;
- database = g_slist_remove(database, a);
+ server->database = g_slist_remove(server->database, a);
g_free(a->data);
g_free(a);

--
1.7.8.1


2011-12-27 14:33:13

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 2/8] attrib-server: Register GATT SDP record per each adapter

Each server has its own SDP registry wich will be managed
separately. Furthermore, this patch makes a wrapper over
attrib_create_sdp function using the default GATT server
started in thye default adapter in order to keep backward
compatibility with the gatt server interface until the api
is finally updated.
---
src/attrib-server.c | 207 +++++++++++++++++++++++++++++----------------------
1 files changed, 119 insertions(+), 88 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 452e72b..88d6033 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -59,6 +59,8 @@ struct gatt_server {
struct btd_adapter *adapter;
GIOChannel *l2cap_io;
GIOChannel *le_io;
+ uint32_t gatt_sdp_handle;
+ uint32_t gap_sdp_handle;
};

struct gatt_channel {
@@ -80,8 +82,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;

/* GAP attribute handles */
static uint16_t name_handle = 0x0000;
@@ -112,6 +112,12 @@ static void gatt_server_free(struct gatt_server *server)
g_io_channel_shutdown(server->le_io, FALSE, NULL);
}

+ if (server->gatt_sdp_handle > 0)
+ remove_record_from_server(server->gatt_sdp_handle);
+
+ if (server->gap_sdp_handle > 0)
+ remove_record_from_server(server->gap_sdp_handle);
+
if (server->adapter != NULL)
btd_adapter_unref(server->adapter);

@@ -129,6 +135,27 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b)
return -1;
}

+static struct gatt_server *get_default_gatt_server(void)
+{
+ 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(servers, adapter, adapter_cmp);
+ if (l == NULL) {
+ error("Not GATT server initialized on adapter %s",
+ adapter_get_path(adapter));
+ return NULL;
+ }
+
+ return l->data;
+}
+
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;
@@ -200,6 +227,82 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2)
return attrib1->handle - attrib2->handle;
}

+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 uint32_t attrib_create_sdp_new(struct gatt_server *server,
+ 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(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 != NULL)
+ 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(server->adapter, &addr);
+ if (add_record_to_server(&addr, record) == 0)
+ return record->handle;
+
+ sdp_record_free(record);
+ return 0;
+}
+
static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
int reqs)
{
@@ -556,39 +659,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)
{
@@ -983,7 +1053,7 @@ static void confirm_event(GIOChannel *io, void *user_data)
return;
}

-static gboolean register_core_services(void)
+static gboolean register_core_services(struct gatt_server *server)
{
uint8_t atval[256];
bt_uuid_t uuid;
@@ -1020,10 +1090,11 @@ 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) {
+ server->gap_sdp_handle = attrib_create_sdp_new(server, 0x0001,
+ "Generic Access Profile");
+ if (server->gap_sdp_handle == 0) {
error("Failed to register GAP service record");
- goto failed;
+ return FALSE;
}

/* GATT service: primary service definition */
@@ -1031,20 +1102,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,
+ server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010,
"Generic Attribute Profile");
- if (gatt_sdp_handle == 0) {
+ if (server->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;
}

int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
@@ -1075,7 +1140,7 @@ int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
return -1;
}

- if (!register_core_services()) {
+ if (!register_core_services(server)) {
gatt_server_free(server);
return -1;
}
@@ -1116,53 +1181,19 @@ void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
g_slist_free_full(database, attrib_free);

g_slist_free_full(clients, (GDestroyNotify) channel_free);
-
- 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, gap_uuid;
+ struct gatt_server *server;

- a = find_primary_range(handle, &end);
+ DBG("Deprecated function!");

- if (a == NULL)
+ server = get_default_gatt_server();
+ if (server == 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/");
- }
-
- if (add_record_to_server(BDADDR_ANY, record) < 0)
- sdp_record_free(record);
- else
- return record->handle;
-
- return 0;
+ return attrib_create_sdp_new(server, handle, name);
}

void attrib_free_sdp(uint32_t sdp_handle)
--
1.7.8.1


2011-12-27 14:33:16

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 5/8] attrib-server: Remove global le_io variable

Get ride of the global low energy channel in order to use the low
energy channel managed in each server.
---
src/attrib-server.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index a04964e..d987d76 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -83,8 +83,6 @@ struct group_elem {
uint16_t len;
};

-static GIOChannel *le_io = NULL;
-
/* GAP attribute handles */
static uint16_t name_handle = 0x0000;
static uint16_t appearance_handle = 0x0000;
@@ -864,7 +862,7 @@ 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,
+ bt_io_set(channel->server->le_io, BT_IO_L2CAP, NULL,
BT_IO_OPT_OMTU, channel->mtu,
BT_IO_OPT_INVALID);

--
1.7.8.1


2011-12-27 14:33:15

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 4/8] attrib-server: Attach attrib_channel in adapter clients list

This patch attaches attribute channels to the gatt server list
instead of using the global client list. Furthermore, we use the
GATT server started in the default adapter when attrib_channel_detach
is invoked in order to keep backward compatibility until the interface
is updated to accept the adapter too.
---
src/attrib-server.c | 74 +++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 2e3e6f2..a04964e 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -62,6 +62,7 @@ struct gatt_server {
uint32_t gatt_sdp_handle;
uint32_t gap_sdp_handle;
GSList *database;
+ GSList *clients;
};

struct gatt_channel {
@@ -72,6 +73,7 @@ struct gatt_channel {
gboolean le;
guint id;
gboolean encrypted;
+ struct gatt_server *server;
};

struct group_elem {
@@ -82,7 +84,6 @@ struct group_elem {
};

static GIOChannel *le_io = NULL;
-static GSList *clients = NULL;

/* GAP attribute handles */
static uint16_t name_handle = 0x0000;
@@ -109,6 +110,13 @@ static void attrib_free(void *data)
g_free(a);
}

+static void channel_free(struct gatt_channel *channel)
+{
+ g_attrib_unref(channel->attrib);
+
+ g_free(channel);
+}
+
static void gatt_server_free(struct gatt_server *server)
{
g_slist_free_full(server->database, attrib_free);
@@ -123,6 +131,8 @@ static void gatt_server_free(struct gatt_server *server)
g_io_channel_shutdown(server->le_io, FALSE, NULL);
}

+ g_slist_free_full(server->clients, (GDestroyNotify) channel_free);
+
if (server->gatt_sdp_handle > 0)
remove_record_from_server(server->gatt_sdp_handle);

@@ -135,6 +145,17 @@ static void gatt_server_free(struct gatt_server *server)
g_free(server);
}

+static gint adapter_cmp_addr(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_server *server = a;
+ const bdaddr_t *bdaddr = b;
+ bdaddr_t src;
+
+ adapter_get_address(server->adapter, &src);
+
+ return bacmp(&src, bdaddr);
+}
+
static gint adapter_cmp(gconstpointer a, gconstpointer b)
{
const struct gatt_server *server = a;
@@ -146,6 +167,22 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b)
return -1;
}

+static struct gatt_server *find_gatt_server(const bdaddr_t *bdaddr)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(servers, 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_server *get_default_gatt_server(void)
{
struct btd_adapter *adapter;
@@ -834,18 +871,12 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
return enc_mtu_resp(old_mtu, pdu, len);
}

-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;

- clients = g_slist_remove(clients, channel);
+ channel->server->clients = g_slist_remove(channel->server->clients,
+ channel);
channel_free(channel);
}

@@ -975,7 +1006,7 @@ done:

guint attrib_channel_attach(GAttrib *attrib, gboolean out)
{
- struct btd_adapter *adapter;
+ struct gatt_server *server;
struct btd_device *device;
struct gatt_channel *channel;
GIOChannel *io;
@@ -1000,10 +1031,14 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
return 0;
}

- adapter = manager_find_adapter(&channel->src);
+ server = find_gatt_server(&channel->src);
+ if (server == NULL)
+ return 0;
+
+ channel->server = server;

ba2str(&channel->dst, addr);
- device = adapter_find_device(adapter, addr);
+ device = adapter_find_device(server->adapter, addr);

if (device_is_bonded(device) == FALSE)
delete_device_ccc(&channel->src, &channel->dst);
@@ -1025,7 +1060,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);
+ server->clients = g_slist_append(server->clients, channel);

return channel->id;
}
@@ -1040,11 +1075,18 @@ static gint channel_id_cmp(gconstpointer data, gconstpointer user_data)

gboolean attrib_channel_detach(guint id)
{
+ struct gatt_server *server;
struct gatt_channel *channel;
GSList *l;

- l = g_slist_find_custom(clients, GUINT_TO_POINTER(id),
- channel_id_cmp);
+ DBG("Deprecated function");
+
+ server = get_default_gatt_server();
+ if (server == NULL)
+ return FALSE;
+
+ l = g_slist_find_custom(server->clients, GUINT_TO_POINTER(id),
+ channel_id_cmp);
if (!l)
return FALSE;

@@ -1215,8 +1257,6 @@ void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
gatt_server_free(server);

g_slist_free_full(database, attrib_free);
-
- g_slist_free_full(clients, (GDestroyNotify) channel_free);
}

uint32_t attrib_create_sdp(uint16_t handle, const char *name)
--
1.7.8.1


2011-12-27 14:33:14

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 3/8] attrib-server: Add attributes in adapter database

Each server 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 GATT server 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 | 95 ++++++++++++++++++++++++++++++++------------------
1 files changed, 61 insertions(+), 34 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 88d6033..2e3e6f2 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -61,6 +61,7 @@ struct gatt_server {
GIOChannel *le_io;
uint32_t gatt_sdp_handle;
uint32_t gap_sdp_handle;
+ GSList *database;
};

struct gatt_channel {
@@ -100,8 +101,18 @@ 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 gatt_server_free(struct gatt_server *server)
{
+ g_slist_free_full(server->database, attrib_free);
+
if (server->l2cap_io != NULL) {
g_io_channel_unref(server->l2cap_io);
g_io_channel_shutdown(server->l2cap_io, FALSE, NULL);
@@ -227,7 +238,8 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2)
return attrib1->handle - attrib2->handle;
}

-static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
+static struct attribute *find_primary_range(struct gatt_server *server,
+ uint16_t start, uint16_t *end)
{
struct attribute *attrib;
guint h = start;
@@ -236,7 +248,8 @@ static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
if (end == NULL)
return NULL;

- l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+ l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return NULL;

@@ -269,7 +282,7 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
uuid_t svc, gap_uuid;
bdaddr_t addr;

- a = find_primary_range(handle, &end);
+ a = find_primary_range(server, handle, &end);

if (a == NULL)
return 0;
@@ -303,6 +316,33 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
return 0;
}

+static struct attribute *attrib_db_add_new(struct gatt_server *server,
+ 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(server->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;
+
+ server->database = g_slist_insert_sorted(server->database, a,
+ attribute_cmp);
+
+ return a;
+}
+
static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
int reqs)
{
@@ -794,14 +834,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);
@@ -1062,7 +1094,8 @@ static gboolean register_core_services(struct gatt_server *server)
/* 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(server, 0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ atval, 2);

/* GAP service: device name characteristic */
name_handle = 0x0006;
@@ -1070,12 +1103,13 @@ static gboolean register_core_services(struct gatt_server *server)
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(server, 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(server, name_handle, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, NULL, 0);

/* GAP service: device appearance characteristic */
appearance_handle = 0x0008;
@@ -1083,13 +1117,14 @@ static gboolean register_core_services(struct gatt_server *server)
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(server, 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(server, appearance_handle, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 2);
server->gap_sdp_handle = attrib_create_sdp_new(server, 0x0001,
"Generic Access Profile");
if (server->gap_sdp_handle == 0) {
@@ -1100,7 +1135,8 @@ static gboolean register_core_services(struct gatt_server *server)
/* 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(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ atval, 2);

server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010,
"Generic Attribute Profile");
@@ -1232,25 +1268,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_server *server;

- DBG("handle=0x%04x", handle);
+ DBG("Deprecated function!");

- if (g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp))
+ server = get_default_gatt_server();
+ if (server == 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(server, 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.1


2011-12-27 14:33:12

by Santiago Carot

[permalink] [raw]
Subject: [PATCH 1/8] attrib-server: Initial steps towards multi-adapter GATT server support

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.
---
src/adapter.c | 7 +++
src/adapter.h | 3 +
src/attrib-server.c | 106 +++++++++++++++++++++++++++++++++++---------------
src/hcid.h | 3 -
src/main.c | 8 ----
5 files changed, 84 insertions(+), 43 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 2d9e368..5fd6802 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2484,6 +2484,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);
@@ -2543,6 +2547,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 3e93441..1c1768e 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -282,3 +282,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);
diff --git a/src/attrib-server.c b/src/attrib-server.c
index b767b72..452e72b 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -53,6 +53,13 @@
#include "attrib-server.h"

static GSList *database = NULL;
+static GSList *servers = NULL;
+
+struct gatt_server {
+ struct btd_adapter *adapter;
+ GIOChannel *l2cap_io;
+ GIOChannel *le_io;
+};

struct gatt_channel {
bdaddr_t src;
@@ -71,7 +78,6 @@ 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;
@@ -94,6 +100,35 @@ static bt_uuid_t ccc_uuid = {
.value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
};

+static void gatt_server_free(struct gatt_server *server)
+{
+ if (server->l2cap_io != NULL) {
+ g_io_channel_unref(server->l2cap_io);
+ g_io_channel_shutdown(server->l2cap_io, FALSE, NULL);
+ }
+
+ if (server->le_io != NULL) {
+ g_io_channel_unref(server->le_io);
+ g_io_channel_shutdown(server->le_io, FALSE, NULL);
+ }
+
+ if (server->adapter != NULL)
+ btd_adapter_unref(server->adapter);
+
+ g_free(server);
+}
+
+static gint adapter_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_server *server = a;
+ const struct btd_adapter *adapter = b;
+
+ if (server->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;
@@ -1012,66 +1047,73 @@ failed:
return FALSE;
}

-int attrib_server_init(void)
+int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
{
+ struct gatt_server *server;
GError *gerr = NULL;
+ bdaddr_t addr;
+
+ DBG("Start GATT server in hci%d", adapter_get_dev_id(adapter));
+
+ server = g_new0(struct gatt_server, 1);
+ server->adapter = btd_adapter_ref(adapter);
+
+ adapter_get_address(server->adapter, &addr);

/* BR/EDR socket */
- l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+ server->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 (server->l2cap_io == NULL) {
error("%s", gerr->message);
g_error_free(gerr);
+ gatt_server_free(server);
return -1;
}

- if (!register_core_services())
- goto failed;
+ if (!register_core_services()) {
+ gatt_server_free(server);
+ 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,
+ server->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+ &server->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 (server->le_io == NULL) {
error("%s", gerr->message);
g_error_free(gerr);
/* Doesn't have LE support, continue */
}

+ servers = g_slist_prepend(servers, server);
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)
+void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
{
- g_slist_free_full(database, attrib_free);
+ struct gatt_server *server;
+ GSList *l;

- if (l2cap_io) {
- g_io_channel_unref(l2cap_io);
- g_io_channel_shutdown(l2cap_io, FALSE, NULL);
- }
+ l = g_slist_find_custom(servers, 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 hci%d", adapter_get_dev_id(adapter));
+
+ server = l->data;
+ servers = g_slist_remove(servers, server);
+ gatt_server_free(server);
+
+ g_slist_free_full(database, attrib_free);

g_slist_free_full(clients, (GDestroyNotify) channel_free);

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.1


2011-12-27 10:07:40

by Santiago Carot

[permalink] [raw]
Subject: Re: [PATCH 1/8] attrib-server: Initial steps towards multi-adapter GATT server support

Hi johan,

2011/12/27 Johan Hedberg <[email protected]>:
> Hi Santiago,
>
> On Tue, Dec 20, 2011, Santiago Carot-Nemesio wrote:
>> +struct gatt_adapter {
>> + ? ? struct btd_adapter *adapter;
>> + ? ? GIOChannel *l2cap_io;
>> + ? ? GIOChannel *le_io;
>> +};
>
> Could we just call this struct attrib_server? That would be less
> confusing than having different types of adapters when in reality you
> only have one adapter. What we have here is an attrib server running on
> a specific adapter, so struct attrib_server would make most sense to me.
> Also update the corresponding function names to reflect this.

Do you mind if I send a patch on top fixing that?

2011-12-27 10:00:59

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 1/8] attrib-server: Initial steps towards multi-adapter GATT server support

Hi Santiago,

On Tue, Dec 20, 2011, Santiago Carot-Nemesio wrote:
> +struct gatt_adapter {
> + struct btd_adapter *adapter;
> + GIOChannel *l2cap_io;
> + GIOChannel *le_io;
> +};

Could we just call this struct attrib_server? That would be less
confusing than having different types of adapters when in reality you
only have one adapter. What we have here is an attrib server running on
a specific adapter, so struct attrib_server would make most sense to me.
Also update the corresponding function names to reflect this.

Johan