diff --git a/android/gatt.c b/android/gatt.c
index 8c7909a..b224c28 100644
--- a/android/gatt.c
+++ b/android/gatt.c
#define GATT_SUCCESS 0x00000000
#define GATT_FAILURE 0x00000101
+typedef enum {
+ DEVICE_DISCONNECTED = 0,
+ DEVICE_CONNECT_INIT, /* connection procedure initiated */
+ DEVICE_CONNECT_READY, /* dev found during LE scan */
+ DEVICE_CONNECTED, /* connection has been established */
+} gatt_device_state_t;
+
+static const char const *device_state_str[] = {
+ "DISCONNECTED",
+ "CONNECT INIT",
+ "CONNECT READY",
+ "CONNECTED",
+};
+
struct gatt_client {
int32_t id;
uint8_t uuid[16];
struct notification_data {
struct hal_gatt_srvc_id service;
struct hal_gatt_gatt_id ch;
- struct gatt_client *client;
- struct gatt_device *dev;
+ struct connection *conn;
guint notif_id;
guint ind_id;
int ref;
bdaddr_t bdaddr;
uint8_t bdaddr_type;
- struct queue *clients;
-
- bool connect_ready;
- int32_t conn_id;
+ gatt_device_state_t state;
GAttrib *attrib;
GIOChannel *att_io;
struct queue *services;
guint watch_id;
+
+ int ref;
+ int conn_cnt;
+};
+
+struct connection {
+ struct gatt_device *device;
+ struct gatt_client *client;
+ int32_t id;
};
static struct ipc *hal_ipc = NULL;
static struct queue *gatt_clients = NULL;
static struct queue *gatt_servers = NULL;
-static struct queue *conn_list = NULL; /* Connected devices */
-static struct queue *conn_wait_queue = NULL; /* Devs waiting to connect */
-static struct queue *disc_dev_list = NULL; /* Disconnected devices */
+static struct queue *gatt_devices = NULL;
+static struct queue *client_connections = NULL;
static struct queue *listen_clients = NULL;
return data == user_data;
}
-static bool match_dev_by_bdaddr(const void *data, const void *user_data)
+static bool match_device_by_bdaddr(const void *data, const void *user_data)
{
const struct gatt_device *dev = data;
const bdaddr_t *addr = user_data;
return !bacmp(&dev->bdaddr, addr);
}
-static bool match_dev_connect_ready(const void *data, const void *user_data)
+static bool match_device_by_state(const void *data, const void *user_data)
{
const struct gatt_device *dev = data;
- return dev->connect_ready;
+ if (dev->state != PTR_TO_UINT(user_data))
+ return false;
+
+ return true;
}
-static bool match_dev_by_conn_id(const void *data, const void *user_data)
+static bool match_pending_device(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;
+ if ((dev->state == DEVICE_CONNECT_INIT) ||
+ (dev->state == DEVICE_CONNECT_READY))
+ return true;
+
+ return false;
}
-static bool match_dev_without_client(const void *data, const void *user_data)
+static bool match_connection_by_id(const void *data, const void *user_data)
{
- const struct gatt_device *dev = data;
+ const struct connection *conn = data;
+ const int32_t id = PTR_TO_INT(user_data);
+
+ return conn->id == id;
+}
- return queue_isempty(dev->clients);
+static bool match_connection_by_device_and_client(const void *data,
+ const void *user_data)
+{
+ const struct connection *conn = data;
+ const struct connection *match = user_data;
+
+ return conn->device == match->device && conn->client == match->client;
+}
+
+static struct connection *find_connection_by_id(int32_t conn_id)
+{
+ return queue_find(client_connections, match_connection_by_id,
+ INT_TO_PTR(conn_id));
+}
+
+static bool match_connection_by_device(const void *data, const void *user_data)
+{
+ const struct connection *conn = data;
+ const struct gatt_device *dev = user_data;
+
+ return conn->device == dev;
+}
+
+static bool match_connection_by_client(const void *data, const void *user_data)
+{
+ const struct connection *conn = data;
+ const struct gatt_client *client = user_data;
+
+ return conn->client == client;
+}
+
+static struct gatt_device *find_device_by_addr(const bdaddr_t *addr)
+{
+ return queue_find(gatt_devices, match_device_by_bdaddr, (void *)addr);
+}
+
+static struct gatt_device *find_pending_device()
+{
+ return queue_find(gatt_devices, match_pending_device, NULL);
+}
+
+static struct gatt_device *find_device_by_state(uint32_t state)
+{
+ return queue_find(gatt_devices, match_device_by_state,
+ UINT_TO_PTR(state));
}
static bool match_srvc_by_element_id(const void *data, const void *user_data)
const struct notification_data *a1 = a;
const struct notification_data *b1 = b;
- if (bacmp(&a1->dev->bdaddr, &b1->dev->bdaddr))
+ if (a1->conn != b1->conn)
return false;
if (memcmp(&a1->ch, &b1->ch, sizeof(a1->ch)))
static void destroy_notification(void *data)
{
struct notification_data *notification = data;
+ struct gatt_client *client;
if (--notification->ref)
return;
- queue_remove_if(notification->client->notifications, match_notification,
+ client = notification->conn->client;
+ queue_remove_if(client->notifications, match_notification,
notification);
free(notification);
}
static void unregister_notification(void *data)
{
struct notification_data *notification = data;
+ struct gatt_device *dev = notification->conn->device;
- if (notification->notif_id)
- g_attrib_unregister(notification->dev->attrib,
- notification->notif_id);
+ /* No device means it was already disconnected and client cleanup was
+ * triggered afterwards, but once client unregisters, device stays if
+ * used by others. Then just unregister single handle.
+ */
+ if (!queue_find(gatt_devices, match_by_value, dev))
+ return;
+
+ if (notification->notif_id && dev)
+ g_attrib_unregister(dev->attrib, notification->notif_id);
+
+ if (notification->ind_id && dev)
+ g_attrib_unregister(dev->attrib, notification->ind_id);
+}
+
+static void device_set_state(struct gatt_device *dev, uint32_t state)
+{
+ char bda[18];
+
+ ba2str(&dev->bdaddr, bda);
+ DBG("gatt: Device %s state changed %s -> %s", bda,
+ device_state_str[dev->state], device_state_str[state]);
- if (notification->ind_id)
- g_attrib_unregister(notification->dev->attrib,
- notification->ind_id);
+ dev->state = state;
}
static void connection_cleanup(struct gatt_device *device)
g_attrib_cancel_all(attrib);
g_attrib_unref(attrib);
}
-}
-
-static void destroy_device(void *data)
-{
- struct gatt_device *dev = data;
- if (!dev)
- return;
-
- if (dev->conn_id)
- connection_cleanup(dev);
+ /* If device was in connection_pending or connectable state we
+ * search device list if we should stop the scan.
+ */
+ if (!scanning && (device->state == DEVICE_CONNECT_INIT ||
+ device->state == DEVICE_CONNECT_READY)) {
+ if (!find_pending_device())
+ bt_le_discovery_stop(NULL);
+ }
- queue_destroy(dev->clients, NULL);
- queue_destroy(dev->services, destroy_service);
- free(dev);
+ device_set_state(device, DEVICE_DISCONNECTED);
}
static void destroy_gatt_client(void *data)
status);
}
-static void send_client_disconnect_notify(int32_t id, struct gatt_device *dev,
+static void send_client_disconnection_notify(struct connection *connection,
int32_t status)
{
struct hal_ev_gatt_client_disconnect ev;
- ev.client_if = id;
- ev.conn_id = dev->conn_id;
+ ev.client_if = connection->client->id;
+ ev.conn_id = connection->id;
ev.status = status;
- bdaddr2android(&dev->bdaddr, &ev.bda);
+
+ bdaddr2android(&connection->device->bdaddr, &ev.bda);
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
+ HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
}
-static void send_client_connect_notify(int32_t id, struct gatt_device *dev,
+static void send_client_connection_notify(struct connection *connection,
int32_t status)
{
struct hal_ev_gatt_client_connect ev;
- ev.client_if = id;
+ ev.client_if = connection->client->id;
+ ev.conn_id = connection->id;
ev.status = status;
- bdaddr2android(&dev->bdaddr, &ev.bda);
- ev.conn_id = status == GATT_SUCCESS ? dev->conn_id : 0;
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_CONNECT, sizeof(ev), &ev);
+ bdaddr2android(&connection->device->bdaddr, &ev.bda);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT, HAL_EV_GATT_CLIENT_CONNECT,
+ sizeof(ev), &ev);
}
-static void remove_client_from_device_list(void *data, void *user_data)
+static void send_client_disconnect_notify(struct connection *connection,
+ int32_t status)
{
- struct gatt_device *dev = data;
-
- queue_remove_if(dev->clients, match_by_value, user_data);
+ send_client_disconnection_notify(connection, status);
}
-static void put_device_on_disc_list(struct gatt_device *dev)
+static void send_client_connect_notify(struct connection *connection,
+ int32_t status)
{
- dev->conn_id = 0;
- queue_remove_all(dev->clients, NULL, NULL, NULL);
- queue_push_tail(disc_dev_list, dev);
+ send_client_connection_notify(connection, status);
}
-static void cleanup_conn_list(int32_t id)
+static void disconnect_notify_by_device(void *data, void *user_data)
{
- struct gatt_device *dev;
+ struct connection *conn = data;
+ struct gatt_device *dev = user_data;
- /* Find device without client */
- dev = queue_remove_if(conn_list, match_dev_without_client, NULL);
- while (dev) {
- /* Device is connected, lets disconnect and notify client */
- connection_cleanup(dev);
- send_client_disconnect_notify(id, dev, GATT_SUCCESS);
+ if (dev != conn->device)
+ return;
- /* Put device on disconnected device list */
- put_device_on_disc_list(dev);
- dev = queue_remove_if(conn_list, match_dev_without_client,
- NULL);
- };
+ if (dev->state == DEVICE_CONNECTED)
+ send_client_disconnect_notify(conn, GATT_SUCCESS);
+ else if (dev->state == DEVICE_CONNECT_INIT ||
+ dev->state == DEVICE_CONNECT_READY)
+ send_client_connect_notify(conn, GATT_FAILURE);
}
-static void cleanup_conn_wait_queue(int32_t id)
+static void destroy_device(void *data)
{
- struct gatt_device *dev;
+ struct gatt_device *dev = data;
- /* Find device without client */
- dev = queue_remove_if(conn_wait_queue, match_dev_without_client, NULL);
- while (dev) {
- send_client_connect_notify(id, dev, GATT_FAILURE);
+ if (!dev)
+ return;
- /* Put device on disconnected device list */
- put_device_on_disc_list(dev);
- dev = queue_remove_if(conn_wait_queue,
- match_dev_without_client, NULL);
- };
+ queue_destroy(dev->services, destroy_service);
- /* Stop scan we had for connecting devices */
- if (queue_isempty(conn_wait_queue) && !scanning)
- bt_le_discovery_stop(NULL);
+ free(dev);
}
-static void remove_client_from_devices(int32_t id)
+static struct gatt_device *device_ref(struct gatt_device *device)
{
- DBG("");
+ if (!device)
+ return NULL;
- queue_foreach(conn_list, remove_client_from_device_list,
- INT_TO_PTR(id));
- cleanup_conn_list(id);
+ device->ref++;
- queue_foreach(conn_wait_queue, remove_client_from_device_list,
- INT_TO_PTR(id));
- cleanup_conn_wait_queue(id);
+ return device;
}
-static void handle_client_unregister(const void *buf, uint16_t len)
+static void device_unref(struct gatt_device *device)
{
- const struct hal_cmd_gatt_client_unregister *cmd = buf;
- uint8_t status;
- struct gatt_client *cl;
+ if (!device)
+ return;
- DBG("");
+ if (--device->ref)
+ return;
- 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);
- status = HAL_STATUS_FAILED;
- } else {
- /* Check if there is any connect request or connected device for this
- * client. If so, remove this client from those lists.
- */
- remove_client_from_devices(cl->id);
- destroy_gatt_client(cl);
- status = HAL_STATUS_SUCCESS;
- }
+ destroy_device(device);
+}
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_CLIENT_UNREGISTER, status);
+static void destroy_connection(void *data)
+{
+ struct connection *conn = data;
+
+ if (!queue_find(gatt_devices, match_by_value, conn->device))
+ goto cleanup;
+
+ conn->device->conn_cnt--;
+ if (conn->device->conn_cnt == 0)
+ connection_cleanup(conn->device);
+
+cleanup:
+ device_unref(conn->device);
+ free(conn);
+}
+
+static void device_disconnect_clients(struct gatt_device *dev)
+{
+ /* Notify disconnection to all clients */
+ queue_foreach(client_connections, disconnect_notify_by_device, dev);
+
+ /* Remove all clients by given device's */
+ queue_remove_all(client_connections, match_connection_by_device, dev,
+ destroy_connection);
}
static void send_client_primary_notify(void *data, void *user_data)
sizeof(ev), &ev);
}
-static void send_client_all_primary(int32_t status, struct queue *services,
- int32_t conn_id)
+static void send_client_all_primary(struct connection *connection,
+ int32_t status)
{
struct hal_ev_gatt_client_search_complete ev;
if (!status)
- queue_foreach(services, send_client_primary_notify,
- INT_TO_PTR(conn_id));
+ queue_foreach(connection->device->services,
+ send_client_primary_notify,
+ INT_TO_PTR(connection->id));
ev.status = status;
- ev.conn_id = conn_id;
+ ev.conn_id = connection->id;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
HAL_EV_GATT_CLIENT_SEARCH_COMPLETE, sizeof(ev), &ev);
static void primary_cb(uint8_t status, GSList *services, void *user_data)
{
- struct gatt_device *dev = user_data;
+ struct connection *conn = user_data;
GSList *l;
int32_t gatt_status;
uint8_t instance_id;
goto done;
}
- if (!queue_isempty(dev->services)) {
+ if (!queue_isempty(conn->device->services)) {
info("gatt: Services already cached");
gatt_status = GATT_SUCCESS;
goto done;
if (!p)
continue;
- if (!queue_push_tail(dev->services, p)) {
+ if (!queue_push_tail(conn->device->services, p)) {
error("gatt: Cannot push primary service to the list");
free(p);
continue;
gatt_status = GATT_SUCCESS;
done:
- send_client_all_primary(gatt_status, dev->services, dev->conn_id);
-}
-
-static void client_disconnect_notify(void *data, void *user_data)
-{
- struct gatt_device *dev = user_data;
- int32_t id = PTR_TO_INT(data);
-
- send_client_disconnect_notify(id, dev, GATT_SUCCESS);
-}
-
-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;
+ send_client_all_primary(conn, gatt_status);
}
static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
{
uint8_t buf[IPC_MTU];
struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
+ struct gatt_device *dev;
char bda[18];
if (!scanning || !discoverable)
sizeof(*ev) + ev->len, ev);
connect:
- if (!is_device_wating_for_connect(addr, addr_type))
+ dev = find_device_by_addr(addr);
+ if (!dev || (dev->state != DEVICE_CONNECT_INIT))
return;
+ device_set_state(dev, DEVICE_CONNECT_READY);
+ dev->bdaddr_type = addr_type;
+
/* We are ok to perform connect now. Stop discovery
* and once it is stopped continue with creating ACL
*/
int sock, err = 0;
socklen_t len;
- queue_remove(conn_list, dev);
-
sock = g_io_channel_unix_get_fd(io);
len = sizeof(err);
if (!getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len))
DBG("%s (%d)", strerror(err), err);
- connection_cleanup(dev);
-
- queue_foreach(dev->clients, client_disconnect_notify, dev);
-
- /* Reset conn_id and put on disconnected list. */
- put_device_on_disc_list(dev);
+ device_disconnect_clients(dev);
return FALSE;
}
static void send_client_connect_notifications(void *data, void *user_data)
{
- int32_t id = PTR_TO_INT(data);
- struct connect_data *c = user_data;
+ struct connection *conn = data;
+ struct connect_data *con_data = user_data;
- send_client_connect_notify(id, c->dev, c->status);
+ if (conn->device == con_data->dev)
+ send_client_connect_notify(conn, con_data->status);
}
static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
{
struct gatt_device *dev = user_data;
struct connect_data data;
+ uint32_t status;
GAttrib *attrib;
- static uint32_t conn_id = 0;
- /* Take device from conn waiting queue */
- if (!queue_remove(conn_wait_queue, dev)) {
- error("gatt: Device not on the connect wait queue!?");
+ if (dev->state != DEVICE_CONNECT_READY) {
+ error("gatt: Device not in a connecting state!?");
g_io_channel_shutdown(io, TRUE, NULL);
return;
}
if (gerr) {
error("gatt: connection failed %s", gerr->message);
- data.status = GATT_FAILURE;
+ device_set_state(dev, DEVICE_DISCONNECTED);
+ status = GATT_FAILURE;
goto reply;
}
attrib = g_attrib_new(io);
if (!attrib) {
error("gatt: unable to create new GAttrib instance");
- data.status = GATT_FAILURE;
+ device_set_state(dev, DEVICE_DISCONNECTED);
+ status = GATT_FAILURE;
goto reply;
}
dev->attrib = attrib;
dev->watch_id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
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);
- data.status = GATT_FAILURE;
- goto reply;
- }
+ device_set_state(dev, DEVICE_CONNECTED);
- data.status = GATT_SUCCESS;
+ status = GATT_SUCCESS;
reply:
data.dev = dev;
- queue_foreach(dev->clients, send_client_connect_notifications, &data);
-
- /* If connection did not succeed, destroy device */
- if (data.status)
- destroy_device(dev);
+ data.status = status;
+ queue_foreach(client_connections, send_client_connect_notifications,
+ &data);
+ device_unref(dev);
/* Check if we should restart scan */
if (scanning)
/* This connection will help us catch any PDUs that comes before
* pairing finishes
*/
- io = bt_io_connect(connect_cb, dev, NULL, &gerr,
+ io = bt_io_connect(connect_cb, device_ref(dev), NULL, &gerr,
BT_IO_OPT_SOURCE_BDADDR,
&adapter_addr,
BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
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);
+ dev = find_device_by_state(DEVICE_CONNECT_READY);
if (!dev)
- /* Lets try again. */
- return -1;
-
- dev->connect_ready = false;
+ return -ENODEV;
return connect_le(dev);
}
bt_le_discovery_start(le_device_found_handler);
}
-static struct gatt_device *find_device(bdaddr_t *addr)
+static struct gatt_device *create_device(const bdaddr_t *addr)
{
struct gatt_device *dev;
- dev = queue_find(conn_list, match_dev_by_bdaddr, addr);
- if (dev)
- return dev;
+ dev = new0(struct gatt_device, 1);
+ if (!dev)
+ return NULL;
+
+ bacpy(&dev->bdaddr, addr);
+
+ dev->services = queue_new();
+ if (!dev->services) {
+ error("gatt: Failed to allocate memory for client");
+ destroy_device(dev);
+ return NULL;
+ }
+
+ if (!queue_push_head(gatt_devices, dev)) {
+ error("gatt: Cannot push device to queue");
+ destroy_device(dev);
+ return NULL;
+ }
+
+ return device_ref(dev);
+}
+
+static struct connection *create_connection(struct gatt_device *device,
+ struct gatt_client *client)
+{
+ struct connection *new_conn;
+ static int32_t last_conn_id = 1;
+
+ /* Check if already connected */
+ new_conn = new0(struct connection, 1);
+ if (!new_conn)
+ return NULL;
+
+ /* Make connection id unique to connection record
+ * (client, device) pair.
+ */
+ new_conn->client = client;
+ new_conn->id = last_conn_id++;
+
+ if (!queue_push_head(client_connections, new_conn)) {
+ error("gatt: Cannot push client on the client queue!?");
+
+ free(new_conn);
+ return NULL;
+ }
+
+ new_conn->device = device_ref(device);
+ new_conn->device->conn_cnt++;
- return queue_find(conn_wait_queue, match_dev_by_bdaddr, addr);
+ return new_conn;
}
-static struct gatt_device *find_device_by_conn_id(int32_t conn_id)
+static void trigger_disconnection(struct connection *connection)
{
- return queue_find(conn_list, match_dev_by_conn_id, INT_TO_PTR(conn_id));
+ /* Notify client */
+ if (queue_remove(client_connections, connection))
+ send_client_disconnect_notify(connection, GATT_SUCCESS);
+
+ destroy_connection(connection);
}
-static struct gatt_device *create_device(bdaddr_t *addr)
+static void client_disconnect_devices(struct gatt_client *client)
{
- struct gatt_device *dev;
+ struct connection *conn;
- dev = new0(struct gatt_device, 1);
- if (!dev)
- return NULL;
+ /* find every connection for client record and trigger disconnect */
+ conn = queue_remove_if(client_connections, match_connection_by_client,
+ client);
+ while (conn) {
+ trigger_disconnection(conn);
- bacpy(&dev->bdaddr, addr);
+ conn = queue_remove_if(client_connections,
+ match_connection_by_client, client);
+ }
+}
- dev->clients = queue_new();
- dev->services = queue_new();
+static bool trigger_connection(struct connection *connection)
+{
+ switch (connection->device->state) {
+ case DEVICE_DISCONNECTED:
+ device_set_state(connection->device, DEVICE_CONNECT_INIT);
+ break;
+ case DEVICE_CONNECTED:
+ send_client_connect_notify(connection, GATT_SUCCESS);
+ break;
+ default:
+ break;
+ }
- if (!dev->clients || !dev->services) {
- error("gatt: Failed to allocate memory for client");
- destroy_device(dev);
+ /* after state change trigger discovering */
+ if (!scanning && (connection->device->state == DEVICE_CONNECT_INIT))
+ if (!bt_le_discovery_start(le_device_found_handler)) {
+ error("gatt: Could not start scan");
+
+ return false;
+ }
+
+ return true;
+}
+
+static void handle_client_unregister(const void *buf, uint16_t len)
+{
+ const struct hal_cmd_gatt_client_unregister *cmd = buf;
+ uint8_t status;
+ struct gatt_client *cl;
+
+ DBG("");
+
+ 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);
+ status = HAL_STATUS_FAILED;
+ } else {
+ /* Check if there is any connect request or connected device
+ * for this client. If so, remove this client from those lists.
+ */
+ client_disconnect_devices(cl);
+ destroy_gatt_client(cl);
+ status = HAL_STATUS_SUCCESS;
+ }
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_OP_GATT_CLIENT_UNREGISTER, status);
+}
+
+static struct connection *find_connection_by_addr_and_client_id(bdaddr_t *addr,
+ int32_t client_id)
+{
+ struct connection conn_match;
+ struct gatt_device *dev = NULL;
+ struct gatt_client *client;
+
+ /* Check if client is registered */
+ client = find_client_by_id(client_id);
+ if (!client) {
+ error("gatt: Client id %d not found", client_id);
return NULL;
}
- return dev;
+ /* Check if device is known */
+ dev = find_device_by_addr(addr);
+ if (!dev) {
+ error("gatt: Client id %d not found", client_id);
+ return NULL;
+ }
+
+ conn_match.device = dev;
+ conn_match.client = client;
+
+ return queue_find(client_connections,
+ match_connection_by_device_and_client,
+ &conn_match);
}
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;
+ struct connection conn_match;
+ struct connection *conn;
+ struct gatt_device *device;
+ struct gatt_client *client;
bdaddr_t addr;
uint8_t status;
- bool send_notify = false;
DBG("");
- /* Check if client is registered */
- l = find_client_by_id(cmd->client_if);
- if (!l) {
- error("gatt: Client id %d not found", cmd->client_if);
+ client = find_client_by_id(cmd->client_if);
+ if (!client) {
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) {
- /* 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))) {
- status = HAL_STATUS_SUCCESS;
- 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");
+ device = find_device_by_addr(&addr);
+ if (!device) {
+ device = create_device(&addr);
+ if (!device) {
status = HAL_STATUS_FAILED;
goto reply;
}
-
- status = HAL_STATUS_SUCCESS;
- goto reply;
}
- /* Let's check if we know device already */
- dev = queue_remove_if(disc_dev_list, match_dev_by_bdaddr, &addr);
- if (!dev) {
- /* New device, create it. */
- dev = create_device(&addr);
- if (!dev) {
- status = HAL_STATUS_FAILED;
+ conn_match.device = device;
+ conn_match.client = client;
+
+ conn = queue_find(client_connections,
+ match_connection_by_device_and_client,
+ &conn_match);
+ if (!conn) {
+ conn = create_connection(device, client);
+ if (!conn) {
+ status = HAL_STATUS_NOMEM;
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 (!scanning && !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");
+ if (!trigger_connection(conn)) {
status = HAL_STATUS_FAILED;
goto reply;
}
reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_CONNECT,
status);
-
- /* If there is an error here we should make sure dev is out. */
- if ((status != HAL_STATUS_SUCCESS) && dev) {
- destroy_device(dev);
- return;
- }
-
- /* 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 = GATT_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);
- }
}
static void handle_client_disconnect(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_disconnect *cmd = buf;
- struct gatt_device *dev;
- bdaddr_t bdaddr;
+ struct connection *conn;
uint8_t status;
- char addr[18];
DBG("");
- android2bdaddr(cmd->bdaddr, &bdaddr);
- ba2str(&bdaddr, addr);
+ /* TODO: should we care to match also bdaddr when conn_id is unique? */
+ conn = find_connection_by_id(cmd->conn_id);
+ if (conn)
+ trigger_disconnection(conn);
- dev = find_device_by_conn_id(cmd->conn_id);
- if (!dev) {
- error("gatt: dev %s with conn_id=%d not found",
- addr, cmd->conn_id);
- 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))) {
- error("gatt: cannot remove conn_id=%d", cmd->client_if);
- status = HAL_STATUS_FAILED;
- } else {
- status = HAL_STATUS_SUCCESS;
- }
+ status = HAL_STATUS_SUCCESS;
-reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
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_client_disconnect_notify(cmd->client_if, dev, GATT_SUCCESS);
-
- /* If there is more clients just return */
- if (!queue_isempty(dev->clients))
- return;
-
- /* If this is last client do more cleaning */
- connection_cleanup(dev);
- queue_remove(conn_list, dev);
- put_device_on_disc_list(dev);
}
static void send_client_listen_notify(int32_t id, int32_t status)
DBG("");
android2bdaddr(&cmd->bdaddr, &bda);
- dev = find_device(&bda);
+ dev = find_device_by_addr(&bda);
if (!dev) {
status = HAL_STATUS_FAILED;
goto done;
static void handle_client_search_service(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_search_service *cmd = buf;
- struct gatt_device *dev;
+ struct connection *conn;
uint8_t status;
DBG("");
return;
}
- dev = find_device_by_conn_id(cmd->conn_id);
- if (!dev) {
+ conn = find_connection_by_id(cmd->conn_id);
+ if (!conn) {
error("gatt: dev with conn_id=%d not found", cmd->conn_id);
+
status = HAL_STATUS_FAILED;
goto reply;
}
/* TODO: Handle filter uuid */
/* Use cache if possible */
- if (!queue_isempty(dev->services)) {
+ if (!queue_isempty(conn->device->services)) {
+ send_client_all_primary(conn, GATT_SUCCESS);
+
status = HAL_STATUS_SUCCESS;
- send_client_all_primary(GATT_SUCCESS, dev->services,
- dev->conn_id);
goto reply;
}
- if (!gatt_discover_primary(dev->attrib, NULL, primary_cb, dev)) {
+ if (conn->device->state != DEVICE_CONNECTED) {
+ char bda[18];
+
+ ba2str(&conn->device->bdaddr, bda);
+ error("gatt: device %s not connected", bda);
+
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ if (!gatt_discover_primary(conn->device->attrib, NULL, primary_cb,
+ conn)) {
status = HAL_STATUS_FAILED;
goto reply;
}
struct get_included_data {
struct service *prim;
- struct gatt_device *device;
+ struct connection *conn;
};
static int get_inst_id_of_prim_services(const struct gatt_device *dev)
static void get_included_cb(uint8_t status, GSList *included, void *user_data)
{
struct get_included_data *data = user_data;
- struct gatt_device *device = data->device;
+ struct connection *conn = data->conn;
struct service *service = data->prim;
struct service *incl;
int instance_id;
* id of primary service and start iterate included services from this
* point.
*/
- instance_id = get_inst_id_of_prim_services(device);
+ instance_id = get_inst_id_of_prim_services(conn->device);
if (instance_id < 0)
goto failed;
* 2. on special queue inside primary service
*/
if (!queue_push_tail(service->included, incl) ||
- !queue_push_tail(device->services, incl)) {
+ !queue_push_tail(conn->device->services, incl)) {
error("gatt: Cannot push incl service to the list");
destroy_service(incl);
continue;
incl = queue_peek_head(service->included);
if (incl) {
- send_client_incl_service_notify(service, incl, device->conn_id,
+ send_client_incl_service_notify(service, incl, conn->id,
GATT_SUCCESS);
return;
}
failed:
- send_client_incl_service_notify(service, NULL, device->conn_id,
+ send_client_incl_service_notify(service, NULL, conn->id,
GATT_FAILURE);
}
-static bool search_included_services(struct gatt_device *dev,
- struct service *prim)
+static bool search_included_services(struct connection *connection,
+ struct service *service)
{
struct get_included_data *data;
return false;
}
- data->prim = prim;
- data->device = dev;
+ data->prim = service;
+ data->conn = connection;
- gatt_find_included(dev->attrib, prim->prim.range.start,
- prim->prim.range.end,
- get_included_cb, data);
+ gatt_find_included(connection->device->attrib,
+ service->prim.range.start,
+ service->prim.range.end, get_included_cb, data);
return true;
}
static bool find_service(int32_t conn_id, struct element_id *service_id,
- struct gatt_device **dev, struct service **srvc)
+ struct connection **connection,
+ struct service **service)
{
- struct gatt_device *device;
- struct service *service;
+ struct service *srvc;
+ struct connection *conn;
- device = find_device_by_conn_id(conn_id);
- if (!device) {
+ conn = find_connection_by_id(conn_id);
+ if (!conn) {
error("gatt: conn_id=%d not found", conn_id);
return false;
}
- service = queue_find(device->services, match_srvc_by_element_id,
+ srvc = queue_find(conn->device->services, match_srvc_by_element_id,
service_id);
- if (!service) {
+ if (!srvc) {
error("gatt: Service with inst_id: %d not found",
service_id->instance);
return false;
}
- *dev = device;
- *srvc = service;
+ *connection = conn;
+ *service = srvc;
return true;
}
static void handle_client_get_included_service(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_get_included_service *cmd = buf;
- struct gatt_device *device;
+ struct connection *conn;
struct service *prim_service;
struct service *incl_service;
struct element_id match_id;
}
hal_srvc_id_to_element_id(&cmd->srvc_id, &match_id);
- if (!find_service(cmd->conn_id, &match_id, &device, &prim_service)) {
+ if (!find_service(cmd->conn_id, &match_id, &conn, &prim_service)) {
status = HAL_STATUS_FAILED;
goto reply;
}
if (!prim_service->incl_search_done) {
- if (search_included_services(device, prim_service))
+ if (search_included_services(conn, prim_service))
status = HAL_STATUS_SUCCESS;
else
status = HAL_STATUS_FAILED;
*/
if (!incl_service)
send_client_incl_service_notify(prim_service, NULL,
- device->conn_id, GATT_FAILURE);
+ conn->id, GATT_FAILURE);
else
send_client_incl_service_notify(prim_service, incl_service,
- device->conn_id, GATT_SUCCESS);
+ conn->id, GATT_SUCCESS);
status = HAL_STATUS_SUCCESS;
*/
if (status)
send_client_incl_service_notify(prim_service, NULL,
- device->conn_id, GATT_FAILURE);
+ conn->id, GATT_FAILURE);
}
static void send_client_char_notify(const struct characteristic *ch,
const struct hal_cmd_gatt_client_get_characteristic *cmd = buf;
struct characteristic *ch;
struct element_id match_id;
- struct gatt_device *dev;
+ struct connection *conn;
struct service *srvc;
uint8_t status;
}
hal_srvc_id_to_element_id(&cmd->srvc_id, &match_id);
- if (!find_service(cmd->conn_id, &match_id, &dev, &srvc)) {
+ if (!find_service(cmd->conn_id, &match_id, &conn, &srvc)) {
status = HAL_STATUS_FAILED;
goto done;
}
}
cb_data->service = srvc;
- cb_data->conn_id = dev->conn_id;
+ cb_data->conn_id = conn->id;
range = srvc->primary ? srvc->prim.range : srvc->incl.range;
- if (!gatt_discover_char(dev->attrib, range.start, range.end,
- NULL, discover_char_cb,
- cb_data)) {
+ if (!gatt_discover_char(conn->device->attrib, range.start,
+ range.end, NULL,
+ discover_char_cb, cb_data)) {
free(cb_data);
status = HAL_STATUS_FAILED;
else
ch = queue_peek_head(srvc->chars);
- send_client_char_notify(ch, dev->conn_id, srvc);
+ send_client_char_notify(ch, conn->id, srvc);
status = HAL_STATUS_SUCCESS;
}
struct discover_desc_data {
- struct gatt_device *dev;
+ struct connection *conn;
struct service *srvc;
struct characteristic *ch;
gpointer user_data)
{
struct discover_desc_data *data = user_data;
- struct gatt_device *dev = data->dev;
+ struct connection *conn = data->conn;
struct service *srvc = data->srvc;
struct characteristic *ch = data->ch;
struct descriptor *descr;
if (last_handle >= ch->end_handle)
goto reply;
- if (!gatt_discover_char_desc(dev->attrib, last_handle + 1,
- ch->end_handle,
+ if (!gatt_discover_char_desc(conn->device->attrib,
+ last_handle + 1, ch->end_handle,
gatt_discover_desc_cb, data))
goto reply;
descr = queue_peek_head(ch->descriptors);
- send_client_descr_notify(status, dev->conn_id, srvc->primary, &srvc->id,
+ send_client_descr_notify(status, conn->id, srvc->primary, &srvc->id,
&ch->id,
descr ? &descr->id : NULL);
free(data);
}
-static bool build_descr_cache(struct gatt_device *dev,
+static bool build_descr_cache(struct connection *connection,
struct service *srvc,
struct characteristic *ch)
{
if (!cb_data)
return false;
- cb_data->dev = dev;
+ cb_data->conn = connection;
cb_data->srvc = srvc;
cb_data->ch = ch;
cb_data->result = queue_new();
return false;
}
- if (!gatt_discover_char_desc(dev->attrib, start, end,
+ if (!gatt_discover_char_desc(connection->device->attrib, start, end,
gatt_discover_desc_cb, cb_data)) {
queue_destroy(cb_data->result, NULL);
free(cb_data);
struct service *srvc;
struct element_id srvc_id;
struct element_id char_id;
- struct gatt_device *dev;
+ struct connection *conn;
int32_t conn_id;
uint8_t primary;
uint8_t status;
hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
- if (!find_service(conn_id, &srvc_id, &dev, &srvc)) {
+ if (!find_service(conn_id, &srvc_id, &conn, &srvc)) {
error("gatt: Get descr. could not find service");
status = HAL_STATUS_FAILED;
}
if (queue_isempty(ch->descriptors)) {
- if (build_descr_cache(dev, srvc, ch)) {
+ if (build_descr_cache(conn, srvc, ch)) {
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
HAL_OP_GATT_CLIENT_GET_DESCRIPTOR,
HAL_STATUS_SUCCESS);
const struct hal_cmd_gatt_client_read_characteristic *cmd = buf;
struct char_op_data *cb_data;
struct characteristic *ch;
- struct gatt_device *dev;
+ struct connection *conn;
struct service *srvc;
struct element_id srvc_id;
struct element_id char_id;
hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
- if (!find_service(cmd->conn_id, &srvc_id, &dev, &srvc)) {
+ if (!find_service(cmd->conn_id, &srvc_id, &conn, &srvc)) {
status = HAL_STATUS_FAILED;
goto failed;
}
goto failed;
}
- if (!gatt_read_char(dev->attrib, ch->ch.value_handle,
+ if (!gatt_read_char(conn->device->attrib, ch->ch.value_handle,
read_char_cb, cb_data)) {
error("gatt: Cannot read characteristic with inst_id: %d",
cmd->char_id.inst_id);
const struct hal_cmd_gatt_client_write_characteristic *cmd = buf;
struct char_op_data *cb_data = NULL;
struct characteristic *ch;
- struct gatt_device *dev;
+ struct connection *conn;
struct service *srvc;
struct element_id srvc_id;
struct element_id char_id;
hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
- if (!find_service(cmd->conn_id, &srvc_id, &dev, &srvc)) {
+ if (!find_service(cmd->conn_id, &srvc_id, &conn, &srvc)) {
status = HAL_STATUS_FAILED;
goto failed;
}
switch (cmd->write_type) {
case GATT_WRITE_TYPE_NO_RESPONSE:
- res = gatt_write_cmd(dev->attrib, ch->ch.value_handle,
+ res = gatt_write_cmd(conn->device->attrib, ch->ch.value_handle,
cmd->value, cmd->len,
NULL, NULL);
break;
case GATT_WRITE_TYPE_PREPARE:
- res = gatt_reliable_write_char(dev->attrib, ch->ch.value_handle,
+ res = gatt_reliable_write_char(conn->device->attrib,
+ ch->ch.value_handle,
cmd->value, cmd->len,
write_char_cb, cb_data);
break;
case GATT_WRITE_TYPE_DEFAULT:
- res = gatt_write_char(dev->attrib, ch->ch.value_handle,
+ res = gatt_write_char(conn->device->attrib, ch->ch.value_handle,
cmd->value, cmd->len,
write_char_cb, cb_data);
break;
struct element_id char_id;
struct element_id descr_id;
struct element_id srvc_id;
- struct gatt_device *dev;
+ struct connection *conn;
int32_t conn_id = 0;
uint8_t primary;
uint8_t status;
hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
hal_gatt_id_to_element_id(&cmd->descr_id, &descr_id);
- if (!find_service(conn_id, &srvc_id, &dev, &srvc)) {
+ if (!find_service(conn_id, &srvc_id, &conn, &srvc)) {
error("gatt: Read descr. could not find service");
status = HAL_STATUS_FAILED;
goto failed;
}
- if (!gatt_read_char(dev->attrib, descr->handle, read_desc_cb,
+ if (!gatt_read_char(conn->device->attrib, descr->handle, read_desc_cb,
cb_data)) {
free(cb_data);
struct element_id srvc_id;
struct element_id char_id;
struct element_id descr_id;
- struct gatt_device *dev;
+ struct connection *conn;
int32_t conn_id;
uint8_t primary;
uint8_t status;
hal_gatt_id_to_element_id(&cmd->char_id, &char_id);
hal_gatt_id_to_element_id(&cmd->descr_id, &descr_id);
- if (!find_service(cmd->conn_id, &srvc_id, &dev, &srvc)) {
+ if (!find_service(cmd->conn_id, &srvc_id, &conn, &srvc)) {
error("gatt: Write descr. could not find service");
status = HAL_STATUS_FAILED;
switch (cmd->write_type) {
case GATT_WRITE_TYPE_NO_RESPONSE:
- res = gatt_write_cmd(dev->attrib, descr->handle, cmd->value,
- cmd->len, NULL , NULL);
+ res = gatt_write_cmd(conn->device->attrib, descr->handle,
+ cmd->value, cmd->len, NULL , NULL);
break;
case GATT_WRITE_TYPE_PREPARE:
- res = gatt_reliable_write_char(dev->attrib, descr->handle,
- cmd->value, cmd->len,
- write_descr_cb,
- cb_data);
+ res = gatt_reliable_write_char(conn->device->attrib,
+ descr->handle, cmd->value,
+ cmd->len, write_descr_cb,
+ cb_data);
break;
case GATT_WRITE_TYPE_DEFAULT:
- res = gatt_write_char(dev->attrib, descr->handle, cmd->value,
- cmd->len, write_descr_cb, cb_data);
+ res = gatt_write_char(conn->device->attrib, descr->handle,
+ cmd->value, cmd->len,
+ write_descr_cb, cb_data);
break;
default:
error("gatt: Write type %d unsupported", cmd->write_type);
static void handle_client_execute_write(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_execute_write *cmd = buf;
- struct gatt_device *dev;
+ struct connection *conn;
uint8_t status;
uint8_t flags;
DBG("");
- dev = queue_find(conn_list, match_dev_by_conn_id,
- INT_TO_PTR(cmd->conn_id));
- if (!dev) {
+ conn = find_connection_by_id(cmd->conn_id);
+ if (!conn) {
status = HAL_STATUS_FAILED;
goto reply;
}
flags = cmd->execute ? ATT_WRITE_ALL_PREP_WRITES :
ATT_CANCEL_ALL_PREP_WRITES;
- if (!gatt_execute_write(dev->attrib, flags, write_execute_cb,
+ if (!gatt_execute_write(conn->device->attrib, flags, write_execute_cb,
INT_TO_PTR(cmd->conn_id))) {
error("gatt: Could not send execute write");
status = HAL_STATUS_FAILED;
memcpy(&ev->char_id, ¬ification->ch, sizeof(ev->char_id));
memcpy(&ev->srvc_id, ¬ification->service, sizeof(ev->srvc_id));
- bdaddr2android(¬ification->dev->bdaddr, &ev->bda);
- ev->conn_id = notification->dev->conn_id;
+ bdaddr2android(¬ification->conn->device->bdaddr, &ev->bda);
+ ev->conn_id = notification->conn->id;
ev->is_notify = pdu[0] == ATT_OP_HANDLE_NOTIFY;
/* We have to cut opcode and handle from data */
uint16_t len;
size_t plen;
- res = g_attrib_get_buffer(notification->dev->attrib, &plen);
+ res = g_attrib_get_buffer(
+ notification->conn->device->attrib,
+ &plen);
len = enc_confirmation(res, plen);
if (len > 0)
- g_attrib_send(notification->dev->attrib, 0, res, len,
- NULL, NULL, NULL);
+ g_attrib_send(notification->conn->device->attrib,
+ 0, res, len, NULL, NULL, NULL);
}
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT, HAL_EV_GATT_CLIENT_NOTIFY,
{
const struct hal_cmd_gatt_client_register_for_notification *cmd = buf;
struct notification_data *notification;
- struct gatt_client *client;
struct characteristic *c;
struct element_id match_id;
- struct gatt_device *dev;
- struct service *service;
+ struct connection *conn;
int32_t conn_id = 0;
+ struct service *service;
uint8_t status;
int32_t gatt_status;
bdaddr_t addr;
DBG("");
- client = find_client_by_id(cmd->client_if);
- if (!client) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
-
android2bdaddr(&cmd->bdaddr, &addr);
- dev = queue_find(conn_list, match_dev_by_bdaddr, &addr);
- if (!dev) {
+ conn = find_connection_by_addr_and_client_id(&addr, cmd->client_if);
+ if (!conn) {
status = HAL_STATUS_FAILED;
goto failed;
}
- conn_id = dev->conn_id;
+ conn_id = conn->id;
hal_srvc_id_to_element_id(&cmd->srvc_id, &match_id);
- service = queue_find(dev->services, match_srvc_by_element_id,
+ service = queue_find(conn->device->services, match_srvc_by_element_id,
&match_id);
if (!service) {
status = HAL_STATUS_FAILED;
memcpy(¬ification->ch, &cmd->char_id, sizeof(notification->ch));
memcpy(¬ification->service, &cmd->srvc_id,
sizeof(notification->service));
- notification->dev = dev;
- notification->client = client;
+ notification->conn = conn;
- if (queue_find(client->notifications, match_notification,
+ if (queue_find(conn->client->notifications, match_notification,
notification)) {
free(notification);
status = HAL_STATUS_SUCCESS;
goto failed;
}
- notification->notif_id = g_attrib_register(dev->attrib,
+ notification->notif_id = g_attrib_register(conn->device->attrib,
ATT_OP_HANDLE_NOTIFY,
c->ch.value_handle,
handle_notification,
goto failed;
}
- notification->ind_id = g_attrib_register(dev->attrib, ATT_OP_HANDLE_IND,
+ notification->ind_id = g_attrib_register(conn->device->attrib,
+ ATT_OP_HANDLE_IND,
c->ch.value_handle,
handle_notification,
notification,
destroy_notification);
if (!notification->ind_id) {
- g_attrib_unregister(dev->attrib, notification->notif_id);
+ g_attrib_unregister(conn->device->attrib,
+ notification->notif_id);
free(notification);
status = HAL_STATUS_FAILED;
goto failed;
*/
notification->ref = 2;
- if (!queue_push_tail(client->notifications, notification)) {
+ if (!queue_push_tail(conn->client->notifications, notification)) {
unregister_notification(notification);
status = HAL_STATUS_FAILED;
goto failed;
{
const struct hal_cmd_gatt_client_deregister_for_notification *cmd = buf;
struct notification_data *notification, notif;
- struct gatt_client *client;
- struct gatt_device *dev;
+ struct connection *conn;
int32_t conn_id = 0;
uint8_t status;
int32_t gatt_status;
DBG("");
- client = find_client_by_id(cmd->client_if);
- if (!client) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
-
android2bdaddr(&cmd->bdaddr, &addr);
- dev = find_device(&addr);
- if (!dev) {
+ conn = find_connection_by_addr_and_client_id(&addr, cmd->client_if);
+ if (!conn) {
status = HAL_STATUS_FAILED;
goto failed;
}
- conn_id = dev->conn_id;
+ conn_id = conn->id;
+
memcpy(¬if.ch, &cmd->char_id, sizeof(notif.ch));
memcpy(¬if.service, &cmd->srvc_id, sizeof(notif.service));
- notif.dev = dev;
+ notif.conn = conn;
- notification = queue_find(client->notifications,
+ notification = queue_find(conn->client->notifications,
match_notification, ¬if);
if (!notification) {
status = HAL_STATUS_FAILED;
DBG("");
- if (!queue_find(gatt_clients, match_client_by_id,
- INT_TO_PTR(cmd->client_if))) {
+ if (!find_client_by_id(cmd->client_if)) {
status = HAL_STATUS_FAILED;
goto failed;
}
{
DBG("");
- conn_list = queue_new();
- conn_wait_queue = queue_new();
+ gatt_devices = queue_new();
gatt_clients = queue_new();
gatt_servers = queue_new();
- disc_dev_list = queue_new();
+ client_connections = queue_new();
listen_clients = queue_new();
- if (!conn_list || !conn_wait_queue || !gatt_clients || !gatt_servers ||
- !disc_dev_list || !listen_clients) {
+ if (!gatt_devices || !gatt_clients || !gatt_servers ||
+ !listen_clients || !client_connections) {
error("gatt: Failed to allocate memory for queues");
queue_destroy(gatt_servers, NULL);
queue_destroy(gatt_clients, NULL);
gatt_clients = NULL;
- queue_destroy(conn_list, NULL);
- conn_list = NULL;
+ queue_destroy(gatt_devices, NULL);
+ gatt_devices = NULL;
- queue_destroy(conn_wait_queue, NULL);
- conn_wait_queue = NULL;
-
- queue_destroy(disc_dev_list, NULL);
- disc_dev_list = NULL;
+ queue_destroy(client_connections, NULL);
+ client_connections = NULL;
queue_destroy(listen_clients, NULL);
listen_clients = NULL;
queue_destroy(gatt_clients, destroy_gatt_client);
gatt_clients = NULL;
- queue_destroy(conn_list, destroy_device);
- conn_list = NULL;
-
- queue_destroy(conn_wait_queue, destroy_device);
- conn_wait_queue = NULL;
+ queue_destroy(client_connections, destroy_connection);
+ client_connections = NULL;
- queue_destroy(disc_dev_list, destroy_device);
- disc_dev_list = NULL;
+ queue_destroy(gatt_devices, destroy_device);
+ gatt_devices = NULL;
queue_destroy(listen_clients, NULL);
listen_clients = NULL;