This patch set add GATT clien scan, connect/disconnect
functionality.
Some changes in handling discovery has been done as
there are two clients of discovery: HAL and GATT
For now daemon makes sure that device is available before
connecting it. It is because in case device is not available
we would block connect to other devices.
Once white list will be available we can simplify that code.
I'm sending also fixed Grzegorz and Jakub patches to avoid
rebasing.
Grzegorz Kolodziejczyk (1):
android/gatt: Use queue and stdlib instead of glib
Jakub Tyszkowski (5):
android/gatt: Change name of match functions
android/bluetooth: Refactor start/stop discovery
android/bluetooth: Move start discovery function up in the file
android/bluetooth: Add GATT notifications on LE discovery
android/gatt: Use Core profile for LE scan
Lukasz Rymanowski (2):
android/gatt: Add GATT Connect
android/gatt: Add disconnect GATT device
android/Android.mk | 4 +
android/Makefile.am | 3 +
android/bluetooth.c | 195 ++++++++++++----
android/bluetooth.h | 7 +
android/gatt.c | 623 ++++++++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 773 insertions(+), 59 deletions(-)
--
1.8.4
Hi Ćukasz,
On Thursday 13 March 2014 19:46:07 Lukasz Rymanowski wrote:
> This patch set add GATT clien scan, connect/disconnect
> functionality.
>
> Some changes in handling discovery has been done as
> there are two clients of discovery: HAL and GATT
>
> For now daemon makes sure that device is available before
> connecting it. It is because in case device is not available
> we would block connect to other devices.
>
> Once white list will be available we can simplify that code.
>
> I'm sending also fixed Grzegorz and Jakub patches to avoid
> rebasing.
>
> Grzegorz Kolodziejczyk (1):
> android/gatt: Use queue and stdlib instead of glib
>
> Jakub Tyszkowski (5):
> android/gatt: Change name of match functions
> android/bluetooth: Refactor start/stop discovery
> android/bluetooth: Move start discovery function up in the file
> android/bluetooth: Add GATT notifications on LE discovery
> android/gatt: Use Core profile for LE scan
>
> Lukasz Rymanowski (2):
> android/gatt: Add GATT Connect
> android/gatt: Add disconnect GATT device
>
> android/Android.mk | 4 +
> android/Makefile.am | 3 +
> android/bluetooth.c | 195 ++++++++++++----
> android/bluetooth.h | 7 +
> android/gatt.c | 623
> ++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 773
> insertions(+), 59 deletions(-)
Patches 1-4 are now applied (with some small fixes).
--
Szymon K. Janc
[email protected]
From: Jakub Tyszkowski <[email protected]>
This makes gatt capable of triggering LE scan using functionality
exposed by Core API. GATT registers its own callbacks for discovering
events.
---
android/gatt.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 2 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 54325a0..57883a4 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -32,10 +32,12 @@
#include "ipc.h"
#include "ipc-common.h"
-#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "bluetooth.h"
#include "gatt.h"
#include "src/log.h"
#include "hal-msg.h"
+#include "utils.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
@@ -47,6 +49,7 @@ struct gatt_client {
static struct ipc *hal_ipc = NULL;
static bdaddr_t adapter_addr;
static struct queue *gatt_clients = NULL;
+static struct queue *scan_clients = NULL;
static bool match_client_by_uuid(const void *data, const void *user_data)
{
@@ -64,6 +67,36 @@ static bool match_client_by_id(const void *data, const void *user_data)
return client->id == exp_id;
}
+static bool match_by_value(const void *data, const void *user_data)
+{
+ return data == user_data;
+}
+
+static void le_device_found_handler(bdaddr_t *addr, uint8_t addr_type, int rssi,
+ uint16_t eir_len, const void *eir)
+{
+ uint8_t buf[IPC_MTU];
+ struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
+ char bda[18];
+
+ if (queue_isempty(scan_clients))
+ return;
+
+ ba2str(addr, bda);
+ DBG("gatt: LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi,
+ eir ? true : false);
+
+ bdaddr2android(addr, ev->bda);
+ ev->rssi = rssi;
+ ev->len = eir_len;
+
+ memcpy(ev->adv_data, eir, ev->len);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SCAN_RESULT,
+ sizeof(ev) + eir_len, ev);
+}
+
static void handle_client_register(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_register *cmd = buf;
@@ -124,6 +157,13 @@ static void handle_client_unregister(const void *buf, uint16_t len)
goto failed;
}
+ queue_remove_if(scan_clients, match_by_value,
+ INT_TO_PTR(cmd->client_if));
+
+ /* If there is no client interesting in scan, just stop it */
+ if (queue_isempty(scan_clients))
+ bt_le_discovery_stop(NULL);
+
free(cl);
status = HAL_STATUS_SUCCESS;
@@ -134,10 +174,59 @@ failed:
static void handle_client_scan(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_scan *cmd = buf;
+ uint8_t status;
+ void *registered;
+ void *l;
+
DBG("");
+ registered = queue_find(gatt_clients, match_client_by_id,
+ INT_TO_PTR(cmd->client_if));
+ /* Turn off scan */
+ if (!cmd->start) {
+ if (registered) {
+ queue_remove_if(scan_clients, match_by_value,
+ INT_TO_PTR(cmd->client_if));
+
+ if (queue_isempty(scan_clients))
+ bt_le_discovery_stop(NULL);
+
+ status = HAL_STATUS_SUCCESS;
+ } else {
+ status = HAL_STATUS_FAILED;
+ }
+ goto reply;
+ }
+
+ /* If device already do scan, reply with success and avoid to add it
+ * again to the list
+ */
+ l = queue_find(scan_clients, match_by_value,
+ INT_TO_PTR(cmd->client_if));
+ if (l) {
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+ }
+
+ /* Add scan client to the list */
+ if (!queue_push_tail(scan_clients, INT_TO_PTR(cmd->client_if))) {
+ error("gatt: Cannot push scan client");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ if (!bt_le_discovery_start(le_device_found_handler)) {
+ error("gatt: LE scan switch failed");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_SCAN,
- HAL_STATUS_FAILED);
+ status);
}
static void handle_client_connect(const void *buf, uint16_t len)
@@ -530,6 +619,13 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
return false;
}
+ scan_clients = queue_new();
+ if (!scan_clients) {
+ error("gatt: Cannot allocate scan_clients");
+ queue_destroy(gatt_clients, NULL);
+ return false;
+ }
+
return true;
}
--
1.8.4
This patch introduce connect LE device functionality.
There is gatt_device representing remote le device. Each gatt device
has a list own list of clients as it is possible that more apps
would like to use same remote device.
Possible connect scenarios:
1. There is no ACL connection to device:
Then new dev is put on conn_wait_queue and le scan is enabled.
Once device is found we do connect it.
Once device is connected then device is moved form conn_wait_queue to
conn_list and success event is sent to client(s) with conn_id
2. Device is already connected:
Then we update client list, reply with success and do send connect event.
3. For unregisterd clients or uknown conn_id, failed response is sent.
---
android/Android.mk | 4 +
android/Makefile.am | 3 +
android/gatt.c | 475 +++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 463 insertions(+), 19 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 49bf108..9b1e6b9 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -59,9 +59,13 @@ LOCAL_SRC_FILES := \
bluez/lib/sdp.c \
bluez/lib/bluetooth.c \
bluez/lib/hci.c \
+ bluez/lib/uuid.c \
bluez/btio/btio.c \
bluez/src/sdp-client.c \
bluez/profiles/network/bnep.c \
+ bluez/attrib/gattrib.c \
+ bluez/attrib/gatt.c \
+ bluez/attrib/att.c
LOCAL_C_INCLUDES := \
$(call include-path-for, glib) \
diff --git a/android/Makefile.am b/android/Makefile.am
index 330529f..7b7d160 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -41,6 +41,9 @@ android_bluetoothd_SOURCES = android/main.c \
android/pan.h android/pan.c \
android/handsfree.h android/handsfree.c \
android/gatt.h android/gatt.c \
+ attrib/att.c attrib/att.h \
+ attrib/gatt.c attrib/gatt.h \
+ attrib/gattrib.c attrib/gattrib.h \
btio/btio.h btio/btio.c \
src/sdp-client.h src/sdp-client.c \
profiles/network/bnep.h profiles/network/bnep.c
diff --git a/android/gatt.c b/android/gatt.c
index 57883a4..c342a7d 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -29,10 +29,13 @@
#include <stdlib.h>
#include <stdint.h>
#include <glib.h>
+#include <errno.h>
+#include <sys/socket.h>
#include "ipc.h"
#include "ipc-common.h"
#include "lib/sdp.h"
+#include "lib/uuid.h"
#include "bluetooth.h"
#include "gatt.h"
#include "src/log.h"
@@ -40,16 +43,38 @@
#include "utils.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "btio/btio.h"
struct gatt_client {
int32_t id;
uint8_t uuid[16];
};
+struct gatt_device {
+ bdaddr_t bdaddr;
+ uint8_t bdaddr_type;
+
+ struct queue *clients;
+
+ bool connect_ready;
+ int32_t conn_id;
+
+ GAttrib *attrib;
+ GIOChannel *att_io;
+
+ guint watch_id;
+};
+
static struct ipc *hal_ipc = NULL;
static bdaddr_t adapter_addr;
+
static struct queue *gatt_clients = NULL;
static struct queue *scan_clients = NULL;
+static struct queue *conn_list = NULL; /* Connected devices */
+static struct queue *conn_wait_queue = NULL; /* Devices waiting for connect */
static bool match_client_by_uuid(const void *data, const void *user_data)
{
@@ -72,29 +97,25 @@ static bool match_by_value(const void *data, const void *user_data)
return data == user_data;
}
-static void le_device_found_handler(bdaddr_t *addr, uint8_t addr_type, int rssi,
- uint16_t eir_len, const void *eir)
+static bool match_dev_by_bdaddr(const void *data, const void *user_data)
{
- uint8_t buf[IPC_MTU];
- struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
- char bda[18];
+ const struct gatt_device *dev = data;
+ const bdaddr_t *addr = user_data;
- if (queue_isempty(scan_clients))
- return;
-
- ba2str(addr, bda);
- DBG("gatt: LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi,
- eir ? true : false);
+ return !bacmp(&dev->bdaddr, addr);
+}
- bdaddr2android(addr, ev->bda);
- ev->rssi = rssi;
- ev->len = eir_len;
+static bool match_dev_connect_ready(const void *data, const void *user_data)
+{
+ const struct gatt_device *dev = data;
- memcpy(ev->adv_data, eir, ev->len);
+ return dev->connect_ready;
+}
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_SCAN_RESULT,
- sizeof(ev) + eir_len, ev);
+static void destroy_device(struct gatt_device *dev)
+{
+ queue_destroy(dev->clients, NULL);
+ free(dev);
}
static void handle_client_register(const void *buf, uint16_t len)
@@ -172,6 +193,253 @@ failed:
HAL_OP_GATT_CLIENT_UNREGISTER, status);
}
+static void connection_cleanup(struct gatt_device *device)
+{
+ if (device->watch_id) {
+ g_source_remove(device->watch_id);
+ device->watch_id = 0;
+ }
+
+ if (device->att_io) {
+ g_io_channel_shutdown(device->att_io, FALSE, NULL);
+ g_io_channel_unref(device->att_io);
+ device->att_io = NULL;
+ }
+
+ if (device->attrib) {
+ GAttrib *attrib = device->attrib;
+ device->attrib = NULL;
+ g_attrib_cancel_all(attrib);
+ g_attrib_unref(attrib);
+ }
+}
+
+static void send_disconnect_notify(void *data, void *user_data)
+{
+ struct hal_ev_gatt_client_disconnect ev;
+ struct gatt_device *dev = user_data;
+
+ ev.client_if = PTR_TO_INT(data);
+ ev.conn_id = dev->conn_id;
+ ev.status = HAL_STATUS_SUCCESS;
+ bdaddr2android(&dev->bdaddr, &ev.bda);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
+}
+
+static bool is_device_wating_for_connect(const bdaddr_t *addr, uint8_t addr_type)
+{
+ struct gatt_device *dev;
+
+ DBG("");
+
+ dev = queue_find(conn_wait_queue, match_dev_by_bdaddr, (void *)addr);
+ if (!dev)
+ return false;
+
+ dev->bdaddr_type = addr_type;
+
+ /* Mark that this device is ready for connect.
+ * Need it because will continue with connect after scan is stopped
+ */
+ dev->connect_ready = true;
+
+ return true;
+}
+
+static void bt_le_discovery_stop_cb(void);
+
+static void le_device_found_handler(bdaddr_t *addr, uint8_t addr_type,
+ int rssi, uint16_t eir_len,
+ const void *eir)
+{
+ uint8_t buf[IPC_MTU];
+ struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
+ char bda[18];
+
+ if (queue_isempty(scan_clients))
+ goto connect;
+
+ ba2str(addr, bda);
+ DBG("gatt: LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi,
+ !!eir);
+
+ bdaddr2android(addr, ev->bda);
+ ev->rssi = rssi;
+ ev->len = eir_len;
+
+ memcpy(ev->adv_data, eir, ev->len);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SCAN_RESULT,
+ sizeof(ev) + eir_len, ev);
+
+connect:
+ if (!is_device_wating_for_connect(addr, addr_type))
+ return;
+
+ /* We are ok to perform connect now. Stop discovery
+ * and once it is stopped continue with creating ACL
+ */
+ bt_le_discovery_stop(bt_le_discovery_stop_cb);
+}
+
+static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ bdaddr_t *addr = user_data;
+ struct gatt_device *dev;
+ int sock, err = 0;
+ socklen_t len;
+
+ sock = g_io_channel_unix_get_fd(io);
+ len = sizeof(err);
+ getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len);
+
+ DBG("%s (%d)", strerror(err), err);
+
+ dev = queue_remove_if(conn_list, match_dev_by_bdaddr, addr);
+ connection_cleanup(dev);
+
+ /* Keep scanning/re-connection active if disconnection reason
+ * is connection timeout, remote user terminated connection or local
+ * initiated disconnection.
+ */
+ if (err == ETIMEDOUT || err == ECONNRESET || err == ECONNABORTED) {
+ if (!queue_push_tail(conn_wait_queue, dev)) {
+ error("gatt: Cannot push data");
+ } else {
+ bt_le_discovery_start(le_device_found_handler);
+ return FALSE;
+ }
+ }
+
+ queue_foreach(dev->clients, send_disconnect_notify, dev);
+ destroy_device(dev);
+
+ return FALSE;
+}
+
+static void send_client_connect_notify(void *data, void *user_data)
+{
+ struct hal_ev_gatt_client_connect *ev = user_data;
+ int32_t id = PTR_TO_INT(data);
+
+ ev->client_if = id;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_CONNECT, sizeof(*ev), ev);
+
+}
+static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
+{
+ bdaddr_t *addr = user_data;
+ struct gatt_device *dev;
+ struct hal_ev_gatt_client_connect ev;
+ GAttrib *attrib;
+ static uint32_t conn_id = 0;
+ uint8_t status;
+
+ /* Take device form conn waiting queue */
+ dev = queue_remove_if(conn_wait_queue, match_dev_by_bdaddr, addr);
+ if (!dev) {
+ error("gatt: Device not on the connect wait queue!?");
+ g_io_channel_shutdown(io, TRUE, NULL);
+ return;
+ }
+
+ g_io_channel_unref(dev->att_io);
+ dev->att_io = NULL;
+
+ /* Set address and client id in the event */
+ bdaddr2android(&dev->bdaddr, &ev.bda);
+
+ if (gerr) {
+ error("gatt: connection failed %s", gerr->message);
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ attrib = g_attrib_new(io);
+ if (!attrib) {
+ error("gatt: unable to create new GAttrib instance");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ dev->attrib = attrib;
+ dev->watch_id = g_io_add_watch(io, G_IO_HUP, disconnected_cb, dev);
+ dev->conn_id = ++conn_id;
+
+ /* Move gatt device from connect queue to conn_list */
+ if (!queue_push_tail(conn_list, dev)) {
+ error("gatt: Cannot push dev on conn_list");
+ connection_cleanup(dev);
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+
+reply:
+ ev.conn_id = dev ? conn_id : 0;
+ ev.status = status;
+
+ queue_foreach(dev->clients, send_client_connect_notify, &ev);
+
+ /* If connection did not succeed, destroy device */
+ if (status)
+ destroy_device(dev);
+}
+
+static int connect_le(struct gatt_device *dev)
+{
+ BtIOSecLevel sec_level;
+ GIOChannel *io;
+ GError *gerr = NULL;
+ char addr[18];
+
+ ba2str(&dev->bdaddr, addr);
+
+ /* There is one connection attempt going on */
+ if (dev->att_io) {
+ info("gatt: connection to dev %s is ongoing", addr);
+ return -EALREADY;
+ }
+
+ DBG("Connection attempt to: %s", addr);
+
+ /*TODO: If we are bonded then we should use higier sec level */
+ sec_level = BT_IO_SEC_LOW;
+
+ /*
+ * This connection will help us catch any PDUs that comes before
+ * pairing finishes
+ */
+ io = bt_io_connect(connect_cb, dev, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR,
+ &adapter_addr,
+ BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
+ BT_IO_OPT_DEST_BDADDR, &dev->bdaddr,
+ BT_IO_OPT_DEST_TYPE, dev->bdaddr_type,
+ BT_IO_OPT_CID, ATT_CID,
+ BT_IO_OPT_SEC_LEVEL, sec_level,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("gatt: Failed bt_io_connect(%s): %s", addr,
+ gerr->message);
+ g_error_free(gerr);
+ return -EIO;
+ }
+
+ /* Keep this, so we can cancel the connection */
+ dev->att_io = io;
+
+ return 0;
+}
+
static void handle_client_scan(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_scan *cmd = buf;
@@ -229,12 +497,166 @@ reply:
status);
}
+static int connect_next_dev(void)
+{
+ struct gatt_device *dev;
+
+ DBG("");
+
+ if (queue_isempty(conn_wait_queue))
+ return 0;
+
+ /* Discovery has been stopped because there is connection waiting */
+ dev = queue_find(conn_wait_queue, match_dev_connect_ready, NULL);
+ if (!dev)
+ /* Lets try again. */
+ return -1;
+
+ dev->connect_ready = false;
+
+ return connect_le(dev);
+}
+
+static void bt_le_discovery_stop_cb(void)
+{
+ DBG("");
+
+ /* Check now if there is any device ready to connect*/
+ if (connect_next_dev() < 0)
+ bt_le_discovery_start(le_device_found_handler);
+}
+
+static struct gatt_device *find_device(bdaddr_t *addr)
+{
+ struct gatt_device *dev;
+
+ dev = queue_find(conn_list, match_dev_by_bdaddr, addr);
+ if (dev)
+ return dev;
+
+ dev = queue_find(conn_wait_queue, match_dev_by_bdaddr, addr);
+ if (dev)
+ return dev;
+
+ return NULL;
+}
+
static void handle_client_connect(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_connect *cmd = buf;
+ struct gatt_device *dev = NULL;
+ void *l;
+ bdaddr_t addr;
+ uint8_t status;
+ bool send_notify = false;
+
DBG("");
+ /* Check if client is registered */
+ l = queue_find(gatt_clients, match_client_by_id,
+ INT_TO_PTR(cmd->client_if));
+ if (!l) {
+ error("gatt: Client id %d not found", cmd->client_if);
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ android2bdaddr(&cmd->bdaddr, &addr);
+
+ /* We do support many clients for one device connection so lets check
+ * If device is connected or in connecting state just update list of
+ * clients
+ */
+ dev = find_device(&addr);
+ if (dev) {
+
+ status = HAL_STATUS_SUCCESS;
+
+ /* Remeber to send dummy notification event if we area
+ * connected
+ */
+ if (dev->conn_id)
+ send_notify = true;
+
+ if (queue_find(dev->clients, match_by_value,
+ INT_TO_PTR(cmd->client_if)))
+ goto reply;
+
+ /* Store another client */
+ if (!queue_push_tail(dev->clients,
+ INT_TO_PTR(cmd->client_if))) {
+ error("gatt: Cannot push client on gatt device list");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ goto reply;
+ }
+
+ /* Lets create new gatt device and put it on conn_wait_queue.
+ * Once it is connected we move it to conn_list
+ */
+ dev = new0(struct gatt_device, 1);
+ if (!dev) {
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ memcpy(&dev->bdaddr, &addr, sizeof(bdaddr_t));
+
+ /* Create queue to keep list of clients for given device*/
+ dev->clients = queue_new();
+ if (!dev->clients) {
+ error("gatt: Cannot create client queue");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ /* Update client list of device */
+ if (!queue_push_tail(dev->clients, INT_TO_PTR(cmd->client_if))) {
+ error("gatt: Cannot push client on the client queue!?");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ /* Start le scan if not started */
+ if (queue_isempty(scan_clients)) {
+ if (!bt_le_discovery_start(le_device_found_handler)) {
+ error("gatt: Could not start scan");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+ }
+
+ if (!queue_push_tail(conn_wait_queue, dev)) {
+ error("gatt: Cannot push device on conn_wait_queue");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+
+reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_CONNECT,
- HAL_STATUS_FAILED);
+ status);
+
+ /* Send dummy notification since ACL is already up*/
+ if (send_notify) {
+ struct hal_ev_gatt_client_connect ev;
+
+ ev.conn_id = dev->conn_id;
+ ev.status = HAL_STATUS_SUCCESS;
+ ev.client_if = cmd->client_if;
+ bdaddr2android(&addr, &ev.bda);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_CONNECT,
+ sizeof(ev), &ev);
+ }
+
+ if (status && dev)
+ destroy_device(dev);
}
static void handle_client_disconnect(const void *buf, uint16_t len)
@@ -610,6 +1032,18 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
hal_ipc = ipc;
+ conn_list = queue_new();
+ if (!conn_list) {
+ error("gatt: Can not create conn queue");
+ return false;
+ }
+
+ conn_wait_queue = queue_new();
+ if (!conn_wait_queue) {
+ error("gatt: Can not create conn queue");
+ return false;
+ }
+
ipc_register(hal_ipc, HAL_SERVICE_ID_GATT, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -637,4 +1071,7 @@ void bt_gatt_unregister(void)
ipc_unregister(hal_ipc, HAL_SERVICE_ID_GATT);
hal_ipc = NULL;
+
+ queue_destroy(conn_list, NULL);
+ queue_destroy(conn_wait_queue, NULL);
}
--
1.8.4
Disconnect scenarios:
1. If there is more then one client for a given gatt_device then
client id is removed from dev->clients, success response is sent
together with success disconnect event.
2. If there is only one client for a given remote device then we
do what is decribed above plus clean of gattrib stuff
3. In case client_if or conn_id is incorrect, response failed is sent
---
android/gatt.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/android/gatt.c b/android/gatt.c
index c342a7d..0c9d87d 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -112,6 +112,14 @@ static bool match_dev_connect_ready(const void *data, const void *user_data)
return dev->connect_ready;
}
+static bool match_dev_by_conn_id(const void *data, const void *user_data)
+{
+ const struct gatt_device *dev = data;
+ const int32_t conn_id = PTR_TO_INT(user_data);
+
+ return dev->conn_id == conn_id;
+}
+
static void destroy_device(struct gatt_device *dev)
{
queue_destroy(dev->clients, NULL);
@@ -661,10 +669,48 @@ reply:
static void handle_client_disconnect(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_disconnect *cmd = buf;
+ struct gatt_device *dev;
+ uint8_t status;
+
DBG("");
+ dev = queue_find(conn_list, match_dev_by_conn_id,
+ INT_TO_PTR(cmd->conn_id));
+ if (!dev) {
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ /*Check if client owns this connection */
+ if (!queue_remove_if(dev->clients, match_by_value,
+ INT_TO_PTR(cmd->client_if)))
+ status = HAL_STATUS_FAILED;
+ else
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_CLIENT_DISCONNECT, HAL_STATUS_FAILED);
+ HAL_OP_GATT_CLIENT_DISCONNECT, status);
+
+ if (status == HAL_STATUS_FAILED)
+ return;
+
+ /* Just send disconnect event. If there is more clients on this
+ * device then this is what we shall to do.
+ * If this is last client, this is still OK to do because on connect
+ * request we do le scan and wait until remote device start
+ * advertisement */
+ send_disconnect_notify((void *)&cmd->client_if, (void *)dev);
+
+ /* If there is more clients just return */
+ if (!queue_isempty(dev->clients))
+ return;
+
+ /* If this is last client do more cleaning */
+ connection_cleanup(dev);
+ dev = queue_remove_if(conn_list, match_dev_by_bdaddr, &dev->bdaddr);
+ destroy_device(dev);
}
static void handle_client_listen(const void *buf, uint16_t len)
--
1.8.4
From: Jakub Tyszkowski <[email protected]>
This is needed for next patch
---
android/bluetooth.c | 62 ++++++++++++++++++++++++++---------------------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 8f66dd1..a28fb01 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -999,6 +999,37 @@ static void clear_device_found(gpointer data, gpointer user_data)
dev->found = false;
}
+static uint8_t get_adapter_discovering_type(void)
+{
+ uint8_t type;
+
+ if (adapter.current_settings & MGMT_SETTING_BREDR)
+ type = SCAN_TYPE_BREDR;
+ else
+ type = 0;
+
+ if (adapter.current_settings & MGMT_SETTING_LE)
+ type |= SCAN_TYPE_LE;
+
+ return type;
+}
+
+static bool start_discovery(uint8_t type)
+{
+ struct mgmt_cp_start_discovery cp;
+
+ cp.type = get_adapter_discovering_type() & type;
+
+ DBG("type=0x%x", cp.type);
+
+ if (mgmt_send(mgmt_if, MGMT_OP_START_DISCOVERY, adapter.index,
+ sizeof(cp), &cp, NULL, NULL, NULL) > 0)
+ return true;
+
+ error("Failed to start discovery");
+ return false;
+}
+
static void mgmt_discovering_event(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
@@ -2452,37 +2483,6 @@ static void get_adapter_properties(void)
get_adapter_discoverable_timeout();
}
-static uint8_t get_adapter_discovering_type(void)
-{
- uint8_t type;
-
- if (adapter.current_settings & MGMT_SETTING_BREDR)
- type = SCAN_TYPE_BREDR;
- else
- type = 0;
-
- if (adapter.current_settings & MGMT_SETTING_LE)
- type |= SCAN_TYPE_LE;
-
- return type;
-}
-
-static bool start_discovery(uint8_t type)
-{
- struct mgmt_cp_start_discovery cp;
-
- cp.type = get_adapter_discovering_type() & type;
-
- DBG("type=0x%x", cp.type);
-
- if (mgmt_send(mgmt_if, MGMT_OP_START_DISCOVERY, adapter.index,
- sizeof(cp), &cp, NULL, NULL, NULL) > 0)
- return true;
-
- error("Failed to start discovery");
- return false;
-}
-
static void cancel_pending_confirm_name(gpointer data, gpointer user_data)
{
struct device *dev = data;
--
1.8.4
From: Jakub Tyszkowski <[email protected]>
This patch introduce API which GATT can use to start/stop discovery
and register for required events.
This is because GATT needs to get from GAP notifications about
founded devices and also notification when discovery has been stopped.
GATT will need it explicity when GATT client calls scan, and also in
case of connect device, as before le connect is sent we do scan first
to make sure that device is available.
For now on adapter have two variables tracing discovery.
1. cur_discovery_type which show type of ongoing discovery type.
2. exp_discovery_type which shows type of next discovery session.
We need this because of scenarion when GATT is interesting in scan and
in the same time HAL wants to do scanning.
---
android/bluetooth.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++-----
android/bluetooth.h | 7 +++
2 files changed, 125 insertions(+), 12 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index a28fb01..ffec791 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -84,6 +84,8 @@
#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
+#define BDADDR_LE (BDADDR_LE_RANDOM | BDADDR_LE_PUBLIC)
+
struct device {
bdaddr_t bdaddr;
uint8_t bdaddr_type;
@@ -122,7 +124,8 @@ static struct {
uint32_t current_settings;
- bool discovering;
+ uint8_t cur_discovery_type;
+ uint8_t exp_discovery_type;
uint32_t discoverable_timeout;
GSList *uuids;
@@ -131,7 +134,8 @@ static struct {
.dev_class = 0,
.name = NULL,
.current_settings = 0,
- .discovering = false,
+ .cur_discovery_type = 0,
+ .exp_discovery_type = 0,
.discoverable_timeout = DEFAULT_DISCOVERABLE_TIMEOUT,
.uuids = NULL,
};
@@ -149,6 +153,10 @@ static struct mgmt *mgmt_if = NULL;
static GSList *bonded_devices = NULL;
static GSList *cached_devices = NULL;
+
+static bt_le_device_found gatt_device_found_cb = NULL;
+static bt_le_discovery_stopped gatt_discovery_stopped_cb = NULL;
+
/* This list contains addresses which are asked for records */
static GSList *browse_reqs;
@@ -999,6 +1007,32 @@ static void clear_device_found(gpointer data, gpointer user_data)
dev->found = false;
}
+static void mgmt_start_discovery_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_cp_start_discovery *rp = param;
+ uint8_t hal_status;
+ DBG("status 0x%02x", status);
+
+ /* Send HAL rsp only when interleave scan has been performed */
+ if (rp->type == SCAN_TYPE_LE)
+ return;
+
+ if (length < sizeof(*rp)) {
+ error("Wrong size of start scanning return parameters");
+ return;
+ }
+
+
+ if (status == MGMT_STATUS_SUCCESS)
+ hal_status = HAL_STATUS_SUCCESS;
+ else
+ hal_status = HAL_STATUS_FAILED;
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_START_DISCOVERY,
+ hal_status);
+}
+
static uint8_t get_adapter_discovering_type(void)
{
uint8_t type;
@@ -1023,7 +1057,8 @@ static bool start_discovery(uint8_t type)
DBG("type=0x%x", cp.type);
if (mgmt_send(mgmt_if, MGMT_OP_START_DISCOVERY, adapter.index,
- sizeof(cp), &cp, NULL, NULL, NULL) > 0)
+ sizeof(cp), &cp, mgmt_start_discovery_complete,
+ NULL, NULL) > 0)
return true;
error("Failed to start discovery");
@@ -1035,6 +1070,7 @@ static void mgmt_discovering_event(uint16_t index, uint16_t length,
{
const struct mgmt_ev_discovering *ev = param;
struct hal_ev_discovery_state_changed cp;
+ bool is_discovering = adapter.cur_discovery_type;
if (length < sizeof(*ev)) {
error("Too small discovering event");
@@ -1044,14 +1080,14 @@ static void mgmt_discovering_event(uint16_t index, uint16_t length,
DBG("hci%u type %u discovering %u", index, ev->type,
ev->discovering);
- if (adapter.discovering == !!ev->discovering)
+ if (is_discovering == !!ev->discovering)
return;
- adapter.discovering = !!ev->discovering;
+ adapter.cur_discovery_type = ev->discovering ? ev->type : 0;
DBG("new discovering state %u", ev->discovering);
- if (adapter.discovering) {
+ if (adapter.cur_discovery_type) {
cp.state = HAL_DISCOVERY_STATE_STARTED;
} else {
g_slist_foreach(bonded_devices, clear_device_found, NULL);
@@ -1061,6 +1097,23 @@ static void mgmt_discovering_event(uint16_t index, uint16_t length,
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_BLUETOOTH,
HAL_EV_DISCOVERY_STATE_CHANGED, sizeof(cp), &cp);
+
+ if (gatt_discovery_stopped_cb && !adapter.cur_discovery_type) {
+ /* One shot notification about discovery stopped send to gatt*/
+ gatt_discovery_stopped_cb();
+ gatt_discovery_stopped_cb = NULL;
+ return;
+ }
+
+ /* If discovery is ON or there is no expected next discovery session
+ * then just return
+ */
+ if (adapter.cur_discovery_type || !adapter.exp_discovery_type)
+ return;
+
+ start_discovery(adapter.exp_discovery_type);
+ /* Maintain expected discovery type if there is gatt client registered */
+ adapter.exp_discovery_type = gatt_device_found_cb ? SCAN_TYPE_LE : 0;
}
static void confirm_device_name_cb(uint8_t status, uint16_t length,
@@ -1142,7 +1195,7 @@ static void update_new_device(struct device *dev, int8_t rssi,
memset(buf, 0, sizeof(buf));
- if (adapter.discovering)
+ if (adapter.cur_discovery_type)
dev->found = true;
size = sizeof(*ev);
@@ -1250,6 +1303,11 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
update_device(dev, rssi, &eir);
}
+ /* Notify Gatt if its registered for LE events */
+ if (gatt_device_found_cb && (dev->bdaddr_type & BDADDR_LE))
+ gatt_device_found_cb(&dev->bdaddr, dev->bdaddr_type,
+ dev->rssi, sizeof(eir), &eir);
+
eir_data_free(&eir);
if (dev->bond_state != HAL_BOND_STATE_BONDED)
@@ -2510,6 +2568,38 @@ static bool stop_discovery(uint8_t type)
return false;
}
+bool bt_le_discovery_stop(bt_le_discovery_stopped cb)
+{
+ if (!adapter.cur_discovery_type) {
+ if (cb)
+ cb();
+ return true;
+ }
+
+ gatt_discovery_stopped_cb = cb;
+ /* Remove device found callback */
+ gatt_device_found_cb = NULL;
+ adapter.exp_discovery_type &= ~SCAN_TYPE_LE;
+
+ return stop_discovery(adapter.cur_discovery_type);
+}
+
+bool bt_le_discovery_start(bt_le_device_found cb)
+{
+ if (!(adapter.current_settings & MGMT_SETTING_POWERED))
+ return false;
+
+ gatt_device_found_cb = cb;
+
+ adapter.exp_discovery_type |= SCAN_TYPE_LE;
+
+ /* If core is discovering, don't bother */
+ if (adapter.cur_discovery_type)
+ return true;
+
+ return start_discovery(adapter.exp_discovery_type);
+}
+
static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
{
const uint8_t *mode = buf;
@@ -3179,7 +3269,8 @@ static void handle_start_discovery_cmd(const void *buf, uint16_t len)
{
uint8_t status;
- if (adapter.discovering) {
+ /* Check if there is discovery with BREDR type */
+ if (adapter.cur_discovery_type & SCAN_TYPE_BREDR) {
status = HAL_STATUS_SUCCESS;
goto reply;
}
@@ -3189,12 +3280,24 @@ static void handle_start_discovery_cmd(const void *buf, uint16_t len)
goto reply;
}
- if (!start_discovery(SCAN_TYPE_DUAL)) {
+ adapter.exp_discovery_type |= SCAN_TYPE_DUAL;
+
+ /* If there is no discovery ongoing, try to start discovery */
+ if (!adapter.cur_discovery_type &&
+ !start_discovery(adapter.exp_discovery_type)) {
status = HAL_STATUS_FAILED;
goto reply;
}
- status = HAL_STATUS_SUCCESS;
+ /* Stop discovery here. Once it is stop we will rester it in continue
+ * and also will reply then
+ */
+ if (!stop_discovery(adapter.cur_discovery_type)) {
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ return;
reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_START_DISCOVERY,
status);
@@ -3204,7 +3307,7 @@ static void handle_cancel_discovery_cmd(const void *buf, uint16_t len)
{
uint8_t status;
- if (!adapter.discovering) {
+ if (!adapter.cur_discovery_type) {
status = HAL_STATUS_SUCCESS;
goto reply;
}
@@ -3214,7 +3317,10 @@ static void handle_cancel_discovery_cmd(const void *buf, uint16_t len)
goto reply;
}
- if (!stop_discovery(SCAN_TYPE_DUAL)) {
+ /* Take into account that gatt might want to keep discover */
+ adapter.exp_discovery_type = gatt_device_found_cb ? SCAN_TYPE_LE : 0;
+
+ if (!stop_discovery(adapter.cur_discovery_type)) {
status = HAL_STATUS_FAILED;
goto reply;
}
diff --git a/android/bluetooth.h b/android/bluetooth.h
index f436178..a03305d 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -34,3 +34,10 @@ void bt_bluetooth_unregister(void);
int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint);
void bt_adapter_remove_record(uint32_t handle);
+
+typedef void (*bt_le_device_found)(bdaddr_t *addr, uint8_t addr_type, int rssi,
+ uint16_t eir_len, const void *eir);
+bool bt_le_discovery_start(bt_le_device_found cb);
+
+typedef void (*bt_le_discovery_stopped)(void);
+bool bt_le_discovery_stop(bt_le_discovery_stopped cb);
--
1.8.4
From: Jakub Tyszkowski <[email protected]>
---
android/gatt.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 9ac89fb..54325a0 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -48,7 +48,7 @@ static struct ipc *hal_ipc = NULL;
static bdaddr_t adapter_addr;
static struct queue *gatt_clients = NULL;
-static bool find_client_by_uuid(const void *data, const void *user_data)
+static bool match_client_by_uuid(const void *data, const void *user_data)
{
const uint8_t *exp_uuid = user_data;
const struct gatt_client *client = data;
@@ -56,7 +56,7 @@ static bool find_client_by_uuid(const void *data, const void *user_data)
return !memcmp(exp_uuid, client->uuid, sizeof(client->uuid));
}
-static bool find_client_by_id(const void *data, const void *user_data)
+static bool match_client_by_id(const void *data, const void *user_data)
{
int32_t exp_id = PTR_TO_INT(user_data);
const struct gatt_client *client = data;
@@ -80,7 +80,7 @@ static void handle_client_register(const void *buf, uint16_t len)
goto failed;
}
- if (queue_find(gatt_clients, find_client_by_uuid, &cmd->uuid)) {
+ if (queue_find(gatt_clients, match_client_by_uuid, &cmd->uuid)) {
error("gatt: client uuid is already on list");
status = HAL_STATUS_FAILED;
goto failed;
@@ -116,7 +116,7 @@ static void handle_client_unregister(const void *buf, uint16_t len)
DBG("");
- cl = queue_remove_if(gatt_clients, find_client_by_id,
+ cl = queue_remove_if(gatt_clients, match_client_by_id,
INT_TO_PTR(cmd->client_if));
if (!cl) {
error("gatt: client_if=%d not found", cmd->client_if);
--
1.8.4
From: Jakub Tyszkowski <[email protected]>
Pass discovery type to discovery stop/start routine so it can be used
also for LE only scan.
---
android/bluetooth.c | 37 ++++++++++++++++++++++---------------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index acd2dd2..8f66dd1 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -80,6 +80,10 @@
#define BASELEN_REMOTE_DEV_PROP (sizeof(struct hal_ev_remote_device_props) \
+ sizeof(struct hal_property))
+#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
+#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
+#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
+
struct device {
bdaddr_t bdaddr;
uint8_t bdaddr_type;
@@ -2448,17 +2452,26 @@ static void get_adapter_properties(void)
get_adapter_discoverable_timeout();
}
-static bool start_discovery(void)
+static uint8_t get_adapter_discovering_type(void)
{
- struct mgmt_cp_start_discovery cp;
+ uint8_t type;
if (adapter.current_settings & MGMT_SETTING_BREDR)
- cp.type = 1 << BDADDR_BREDR;
+ type = SCAN_TYPE_BREDR;
else
- cp.type = 0;
+ type = 0;
if (adapter.current_settings & MGMT_SETTING_LE)
- cp.type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+ type |= SCAN_TYPE_LE;
+
+ return type;
+}
+
+static bool start_discovery(uint8_t type)
+{
+ struct mgmt_cp_start_discovery cp;
+
+ cp.type = get_adapter_discovering_type() & type;
DBG("type=0x%x", cp.type);
@@ -2478,17 +2491,11 @@ static void cancel_pending_confirm_name(gpointer data, gpointer user_data)
dev->confirm_id = 0;
}
-static bool stop_discovery(void)
+static bool stop_discovery(uint8_t type)
{
struct mgmt_cp_stop_discovery cp;
- if (adapter.current_settings & MGMT_SETTING_BREDR)
- cp.type = 1 << BDADDR_BREDR;
- else
- cp.type = 0;
-
- if (adapter.current_settings & MGMT_SETTING_LE)
- cp.type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+ cp.type = get_adapter_discovering_type() & type;
DBG("type=0x%x", cp.type);
@@ -3182,7 +3189,7 @@ static void handle_start_discovery_cmd(const void *buf, uint16_t len)
goto reply;
}
- if (!start_discovery()) {
+ if (!start_discovery(SCAN_TYPE_DUAL)) {
status = HAL_STATUS_FAILED;
goto reply;
}
@@ -3207,7 +3214,7 @@ static void handle_cancel_discovery_cmd(const void *buf, uint16_t len)
goto reply;
}
- if (!stop_discovery()) {
+ if (!stop_discovery(SCAN_TYPE_DUAL)) {
status = HAL_STATUS_FAILED;
goto reply;
}
--
1.8.4
From: Grzegorz Kolodziejczyk <[email protected]>
This patch changes using glib to queues, stdlib operators.
---
android/gatt.c | 38 +++++++++++++++++++++++---------------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index a874737..9ac89fb 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -37,6 +37,7 @@
#include "src/log.h"
#include "hal-msg.h"
#include "src/shared/util.h"
+#include "src/shared/queue.h"
struct gatt_client {
int32_t id;
@@ -45,22 +46,22 @@ struct gatt_client {
static struct ipc *hal_ipc = NULL;
static bdaddr_t adapter_addr;
-static GSList *gatt_clients = NULL;
+static struct queue *gatt_clients = NULL;
-static int find_client_by_uuid(gconstpointer data, gconstpointer user_data)
+static bool find_client_by_uuid(const void *data, const void *user_data)
{
const uint8_t *exp_uuid = user_data;
const struct gatt_client *client = data;
- return memcmp(exp_uuid, client->uuid, sizeof(client->uuid));
+ return !memcmp(exp_uuid, client->uuid, sizeof(client->uuid));
}
-static int find_client_by_id(gconstpointer data, gconstpointer user_data)
+static bool find_client_by_id(const void *data, const void *user_data)
{
int32_t exp_id = PTR_TO_INT(user_data);
const struct gatt_client *client = data;
- return client->id != exp_id;
+ return client->id == exp_id;
}
static void handle_client_register(const void *buf, uint16_t len)
@@ -79,19 +80,19 @@ static void handle_client_register(const void *buf, uint16_t len)
goto failed;
}
- if (g_slist_find_custom(gatt_clients, &cmd->uuid,
- find_client_by_uuid)) {
+ if (queue_find(gatt_clients, find_client_by_uuid, &cmd->uuid)) {
error("gatt: client uuid is already on list");
status = HAL_STATUS_FAILED;
goto failed;
}
- client = g_new0(struct gatt_client, 1);
+ client = (struct gatt_client *) new0(struct gatt_client, 1);
+
memcpy(client->uuid, cmd->uuid, sizeof(client->uuid));
client->id = client_cnt++;
- gatt_clients = g_slist_prepend(gatt_clients, client);
+ queue_push_head(gatt_clients, client);
status = HAL_STATUS_SUCCESS;
@@ -110,21 +111,20 @@ failed:
static void handle_client_unregister(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_unregister *cmd = buf;
- GSList *l;
uint8_t status;
+ struct gatt_client *cl;
DBG("");
- l = g_slist_find_custom(gatt_clients, INT_TO_PTR(cmd->client_if),
- find_client_by_id);
- if (!l) {
+ cl = queue_remove_if(gatt_clients, find_client_by_id,
+ INT_TO_PTR(cmd->client_if));
+ if (!cl) {
error("gatt: client_if=%d not found", cmd->client_if);
status = HAL_STATUS_FAILED;
goto failed;
}
- gatt_clients = g_slist_remove(gatt_clients, l->data);
-
+ free(cl);
status = HAL_STATUS_SUCCESS;
failed:
@@ -524,6 +524,12 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
ipc_register(hal_ipc, HAL_SERVICE_ID_GATT, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
+ gatt_clients = queue_new();
+ if (!gatt_clients) {
+ error("gatt: Cannot allocate gatt_clients");
+ return false;
+ }
+
return true;
}
@@ -531,6 +537,8 @@ void bt_gatt_unregister(void)
{
DBG("");
+ queue_destroy(gatt_clients, free);
+
ipc_unregister(hal_ipc, HAL_SERVICE_ID_GATT);
hal_ipc = NULL;
}
--
1.8.4