2011-12-20 15:57:53

by Santiago Carot

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

Here you have a new set of rearranged patches wich initialize and stop
a GATT server in each adapter. Now, all GATT stuff is managed separately
in the adapter instead using global lists and variables.

Next step is to modify gatt server api in order to provide the adapter
in which GATT servers will able to register the attributes for each
service. This feature will enable plugins to register services when each
adapter is plugged instead doing that when the plugins are initialized.

comments are welcome.

[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-20 15:58:01

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


2011-12-20 15:58:00

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 402db3e..90ec1c2 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


2011-12-20 15:57:59

by Santiago Carot

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

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

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5c0f9b4..402db3e 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 *adapters = NULL;

struct gatt_adapter {
@@ -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->gadapter->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->gadapter->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->gadapter->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->gadapter->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->gadapter->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->gadapter->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->gadapter->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)
gadapter = l->data;
adapters = g_slist_remove(adapters, gadapter);
gatt_adapter_free(gadapter);
-
- 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_adapter *gadapter;
uint16_t handle;
GSList *l;

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

- for (l = database, handle = 0; l; l = l->next) {
+ gadapter = get_default_gatt_adapter();
+ if (gadapter == NULL)
+ return 0;
+
+ for (l = gadapter->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_adapter *gadapter;
struct attribute *a;
GSList *l;
guint h = handle;

+ DBG("Deprecated function!");
+
+ gadapter = get_default_gatt_adapter();
+ if (gadapter == 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(gadapter->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_adapter *gadapter;
struct attribute *a;
GSList *l;
guint h = handle;

+ DBG("Deprecated function!");
+
+ gadapter = get_default_gatt_adapter();
+ if (gadapter == 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(gadapter->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return -ENOENT;

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

--
1.7.8


2011-12-20 15:57:58

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 adapter.
---
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 8681652..5c0f9b4 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->gadapter->le_io, BT_IO_L2CAP, NULL,
BT_IO_OPT_OMTU, channel->mtu,
BT_IO_OPT_INVALID);

--
1.7.8


2011-12-20 15:57:57

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 adapter list instead
of using the global client list. Furthermore, we use 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 c9b7796..8681652 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -62,6 +62,7 @@ struct gatt_adapter {
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_adapter *gadapter;
};

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_adapter_free(struct gatt_adapter *gadapter)
{
g_slist_free_full(gadapter->database, attrib_free);
@@ -123,6 +131,8 @@ static void gatt_adapter_free(struct gatt_adapter *gadapter)
g_io_channel_shutdown(gadapter->le_io, FALSE, NULL);
}

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

@@ -135,6 +145,17 @@ static void gatt_adapter_free(struct gatt_adapter *gadapter)
g_free(gadapter);
}

+static gint adapter_cmp_addr(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_adapter *gadapter = a;
+ const bdaddr_t *bdaddr = b;
+ bdaddr_t src;
+
+ adapter_get_address(gadapter->adapter, &src);
+
+ return bacmp(&src, bdaddr);
+}
+
static gint adapter_cmp(gconstpointer a, gconstpointer b)
{
const struct gatt_adapter *gatt_adapter = a;
@@ -146,6 +167,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 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->gadapter->clients = g_slist_remove(channel->gadapter->clients,
+ channel);
channel_free(channel);
}

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

guint attrib_channel_attach(GAttrib *attrib, gboolean out)
{
- struct btd_adapter *adapter;
+ struct gatt_adapter *gadapter;
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);
+ gadapter = find_gatt_adapter(&channel->src);
+ if (gadapter == NULL)
+ return 0;
+
+ channel->gadapter = gadapter;

ba2str(&channel->dst, addr);
- device = adapter_find_device(adapter, addr);
+ device = adapter_find_device(gadapter->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);
+ gadapter->clients = g_slist_append(gadapter->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_adapter *gadapter;
struct gatt_channel *channel;
GSList *l;

- l = g_slist_find_custom(clients, GUINT_TO_POINTER(id),
- channel_id_cmp);
+ DBG("Deprecated function");
+
+ gadapter = get_default_gatt_adapter();
+ if (gadapter == NULL)
+ return FALSE;
+
+ l = g_slist_find_custom(gadapter->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_adapter_free(gadapter);

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


2011-12-20 15:57:56

by Santiago Carot

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

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

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 68e8524..c9b7796 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -61,6 +61,7 @@ struct gatt_adapter {
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_adapter_free(struct gatt_adapter *gadapter)
{
+ g_slist_free_full(gadapter->database, attrib_free);
+
if (gadapter->l2cap_io != NULL) {
g_io_channel_unref(gadapter->l2cap_io);
g_io_channel_shutdown(gadapter->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_adapter *gadapter,
+ 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(gadapter->database, GUINT_TO_POINTER(h),
+ handle_cmp);
if (!l)
return NULL;

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

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

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

+static struct attribute *attrib_db_add_new(struct gatt_adapter *gadapter,
+ 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(gadapter->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;
+
+ gadapter->database = g_slist_insert_sorted(gadapter->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_adapter *gadapter)
/* 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(gadapter, 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_adapter *gadapter)
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(gadapter, 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(gadapter, 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_adapter *gadapter)
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(gadapter, 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(gadapter, appearance_handle, &uuid, ATT_NONE,
+ ATT_NOT_PERMITTED, atval, 2);
gadapter->gap_sdp_handle = attrib_create_sdp_new(gadapter, 0x0001,
"Generic Access Profile");
if (gadapter->gap_sdp_handle == 0) {
@@ -1100,7 +1135,8 @@ static gboolean register_core_services(struct gatt_adapter *gadapter)
/* 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(gadapter, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+ atval, 2);

gadapter->gatt_sdp_handle = attrib_create_sdp_new(gadapter, 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_adapter *gadapter;

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

- if (g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp))
+ gadapter = get_default_gatt_adapter();
+ if (gadapter == 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(gadapter, 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


2011-12-20 15:57:55

by Santiago Carot

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

Each adapter has its own SDP registry wich will be managed
separately. Furthermore, 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 | 207 +++++++++++++++++++++++++++++----------------------
1 files changed, 119 insertions(+), 88 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 24778e5..68e8524 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -59,6 +59,8 @@ struct gatt_adapter {
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_adapter_free(struct gatt_adapter *gadapter)
g_io_channel_shutdown(gadapter->le_io, FALSE, NULL);
}

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

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

+static struct gatt_adapter *get_default_gatt_adapter(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(adapters, 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_adapter *gadapter,
+ 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(gadapter->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_adapter *gadapter)
{
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) {
+ gadapter->gap_sdp_handle = attrib_create_sdp_new(gadapter, 0x0001,
+ "Generic Access Profile");
+ if (gadapter->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,
+ gadapter->gatt_sdp_handle = attrib_create_sdp_new(gadapter, 0x0010,
"Generic Attribute Profile");
- if (gatt_sdp_handle == 0) {
+ if (gadapter->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(gadapter)) {
gatt_adapter_free(gadapter);
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_adapter *gadapter;

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

- if (a == NULL)
+ gadapter = get_default_gatt_adapter();
+ if (gadapter == 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(gadapter, handle, name);
}

void attrib_free_sdp(uint32_t sdp_handle)
--
1.7.8


2011-12-20 15:57:54

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 a776997..57e4c12 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 23bc8a5..f6f35f2 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -277,3 +277,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..24778e5 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 *adapters = NULL;
+
+struct gatt_adapter {
+ 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_adapter_free(struct gatt_adapter *gadapter)
+{
+ if (gadapter->l2cap_io != NULL) {
+ g_io_channel_unref(gadapter->l2cap_io);
+ g_io_channel_shutdown(gadapter->l2cap_io, FALSE, NULL);
+ }
+
+ if (gadapter->le_io != NULL) {
+ g_io_channel_unref(gadapter->le_io);
+ g_io_channel_shutdown(gadapter->le_io, FALSE, NULL);
+ }
+
+ if (gadapter->adapter != NULL)
+ btd_adapter_unref(gadapter->adapter);
+
+ g_free(gadapter);
+}
+
+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;
@@ -1012,66 +1047,73 @@ failed:
return FALSE;
}

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

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

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

+ adapters = g_slist_prepend(adapters, gadapter);
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_adapter *gadapter;
+ 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 hci%d", adapter_get_dev_id(adapter));
+
+ gadapter = l->data;
+ adapters = g_slist_remove(adapters, gadapter);
+ gatt_adapter_free(gadapter);
+
+ 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