2014-11-13 17:39:13

by Marie Janssen

[permalink] [raw]
Subject: [PATCH BlueZ v2 0/4] android fixes and bt_att shim

This patchset fixes some issues with Android GATT testing, a minor
issue with Android GATT exposed by the shim, and provides a
GAttrib shim using bt_att.

Passes all android/android-tester, unit/test-gattrib

v1 -> v2:
* Address comments by Szymon Janc, Arman Uguray

Michael Janssen (4):
android/tester-gatt: Fix search single PDUs
android/tester-gatt: deduplicate read-by-type PDUs
android/gatt: dummy callback for indications
GATT shim to src/shared bt_att

android/gatt.c | 17
android/tester-gatt.c | 169 ++-----
attrib/gattrib.c | 1096 +++++++++++++++-----------------------------------
3 files changed, 395 insertions(+), 887 deletions(-)

--
2.1.0.rc2.206.gedb03e5



2014-11-14 12:51:24

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v2 4/4] GATT shim to src/shared bt_att

Hi Michael,

On Thu, Nov 13, 2014 at 7:39 PM, Michael Janssen <[email protected]> wrote:
> This patch implements a version of GAttrib which is backed by
> bt_att, which enables the simultaneous use of GAttrib and bt_att.
>
> This should enable smooth transition of profiles from the GAttrib
> API to the src/shared bt_att API.
> ---

Lets not mix glib and shared code here, so please use new0, queue,
etc. Also there are a few coding style problems like mixing tabs and
spaces, you should never use spaces for indentation.


--
Luiz Augusto von Dentz

2014-11-14 12:46:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v2 0/4] android fixes and bt_att shim

Hi Michael,

On Thu, Nov 13, 2014 at 7:39 PM, Michael Janssen <[email protected]> wrote:
> This patchset fixes some issues with Android GATT testing, a minor
> issue with Android GATT exposed by the shim, and provides a
> GAttrib shim using bt_att.
>
> Passes all android/android-tester, unit/test-gattrib
>
> v1 -> v2:
> * Address comments by Szymon Janc, Arman Uguray
>
> Michael Janssen (4):
> android/tester-gatt: Fix search single PDUs
> android/tester-gatt: deduplicate read-by-type PDUs
> android/gatt: dummy callback for indications
> GATT shim to src/shared bt_att
>
> android/gatt.c | 17
> android/tester-gatt.c | 169 ++-----
> attrib/gattrib.c | 1096 +++++++++++++++-----------------------------------
> 3 files changed, 395 insertions(+), 887 deletions(-)
>
> --
> 2.1.0.rc2.206.gedb03e5

Ive applied 1-3, please check the comments about 4/4.


--
Luiz Augusto von Dentz

2014-11-13 17:39:17

by Marie Janssen

[permalink] [raw]
Subject: [PATCH BlueZ v2 4/4] GATT shim to src/shared bt_att

This patch implements a version of GAttrib which is backed by
bt_att, which enables the simultaneous use of GAttrib and bt_att.

This should enable smooth transition of profiles from the GAttrib
API to the src/shared bt_att API.
---
attrib/gattrib.c | 1096 +++++++++++++++++-------------------------------------
1 file changed, 338 insertions(+), 758 deletions(-)
rewrite attrib/gattrib.c (80%)

diff --git a/attrib/gattrib.c b/attrib/gattrib.c
dissimilarity index 80%
index fa51b6d..c686de0 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -1,758 +1,338 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2010 Marcel Holtmann <[email protected]>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <glib.h>
-
-#include <stdio.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include "btio/btio.h"
-#include "lib/uuid.h"
-#include "src/shared/util.h"
-#include "src/log.h"
-#include "attrib/att.h"
-#include "attrib/gattrib.h"
-
-#define GATT_TIMEOUT 30
-
-struct _GAttrib {
- GIOChannel *io;
- int refs;
- uint8_t *buf;
- size_t buflen;
- guint read_watch;
- guint write_watch;
- guint timeout_watch;
- GQueue *requests;
- GQueue *responses;
- GSList *events;
- guint next_cmd_id;
- GDestroyNotify destroy;
- gpointer destroy_user_data;
- bool stale;
-};
-
-struct command {
- guint id;
- guint8 opcode;
- guint8 *pdu;
- guint16 len;
- guint8 expected;
- bool sent;
- GAttribResultFunc func;
- gpointer user_data;
- GDestroyNotify notify;
-};
-
-struct event {
- guint id;
- guint8 expected;
- guint16 handle;
- GAttribNotifyFunc func;
- gpointer user_data;
- GDestroyNotify notify;
-};
-
-static guint8 opcode2expected(guint8 opcode)
-{
- switch (opcode) {
- case ATT_OP_MTU_REQ:
- return ATT_OP_MTU_RESP;
-
- case ATT_OP_FIND_INFO_REQ:
- return ATT_OP_FIND_INFO_RESP;
-
- case ATT_OP_FIND_BY_TYPE_REQ:
- return ATT_OP_FIND_BY_TYPE_RESP;
-
- case ATT_OP_READ_BY_TYPE_REQ:
- return ATT_OP_READ_BY_TYPE_RESP;
-
- case ATT_OP_READ_REQ:
- return ATT_OP_READ_RESP;
-
- case ATT_OP_READ_BLOB_REQ:
- return ATT_OP_READ_BLOB_RESP;
-
- case ATT_OP_READ_MULTI_REQ:
- return ATT_OP_READ_MULTI_RESP;
-
- case ATT_OP_READ_BY_GROUP_REQ:
- return ATT_OP_READ_BY_GROUP_RESP;
-
- case ATT_OP_WRITE_REQ:
- return ATT_OP_WRITE_RESP;
-
- case ATT_OP_PREP_WRITE_REQ:
- return ATT_OP_PREP_WRITE_RESP;
-
- case ATT_OP_EXEC_WRITE_REQ:
- return ATT_OP_EXEC_WRITE_RESP;
-
- case ATT_OP_HANDLE_IND:
- return ATT_OP_HANDLE_CNF;
- }
-
- return 0;
-}
-
-static bool is_response(guint8 opcode)
-{
- switch (opcode) {
- case ATT_OP_ERROR:
- case ATT_OP_MTU_RESP:
- case ATT_OP_FIND_INFO_RESP:
- case ATT_OP_FIND_BY_TYPE_RESP:
- case ATT_OP_READ_BY_TYPE_RESP:
- case ATT_OP_READ_RESP:
- case ATT_OP_READ_BLOB_RESP:
- case ATT_OP_READ_MULTI_RESP:
- case ATT_OP_READ_BY_GROUP_RESP:
- case ATT_OP_WRITE_RESP:
- case ATT_OP_PREP_WRITE_RESP:
- case ATT_OP_EXEC_WRITE_RESP:
- case ATT_OP_HANDLE_CNF:
- return true;
- }
-
- return false;
-}
-
-static bool is_request(guint8 opcode)
-{
- switch (opcode) {
- case ATT_OP_MTU_REQ:
- case ATT_OP_FIND_INFO_REQ:
- case ATT_OP_FIND_BY_TYPE_REQ:
- case ATT_OP_READ_BY_TYPE_REQ:
- case ATT_OP_READ_REQ:
- case ATT_OP_READ_BLOB_REQ:
- case ATT_OP_READ_MULTI_REQ:
- case ATT_OP_READ_BY_GROUP_REQ:
- case ATT_OP_WRITE_REQ:
- case ATT_OP_WRITE_CMD:
- case ATT_OP_PREP_WRITE_REQ:
- case ATT_OP_EXEC_WRITE_REQ:
- return true;
- }
-
- return false;
-}
-
-GAttrib *g_attrib_ref(GAttrib *attrib)
-{
- int refs;
-
- if (!attrib)
- return NULL;
-
- refs = __sync_add_and_fetch(&attrib->refs, 1);
-
- DBG("%p: ref=%d", attrib, refs);
-
- return attrib;
-}
-
-static void command_destroy(struct command *cmd)
-{
- if (cmd->notify)
- cmd->notify(cmd->user_data);
-
- g_free(cmd->pdu);
- g_free(cmd);
-}
-
-static void event_destroy(struct event *evt)
-{
- if (evt->notify)
- evt->notify(evt->user_data);
-
- g_free(evt);
-}
-
-static void attrib_destroy(GAttrib *attrib)
-{
- GSList *l;
- struct command *c;
-
- while ((c = g_queue_pop_head(attrib->requests)))
- command_destroy(c);
-
- while ((c = g_queue_pop_head(attrib->responses)))
- command_destroy(c);
-
- g_queue_free(attrib->requests);
- attrib->requests = NULL;
-
- g_queue_free(attrib->responses);
- attrib->responses = NULL;
-
- for (l = attrib->events; l; l = l->next)
- event_destroy(l->data);
-
- g_slist_free(attrib->events);
- attrib->events = NULL;
-
- if (attrib->timeout_watch > 0)
- g_source_remove(attrib->timeout_watch);
-
- if (attrib->write_watch > 0)
- g_source_remove(attrib->write_watch);
-
- if (attrib->read_watch > 0)
- g_source_remove(attrib->read_watch);
-
- if (attrib->io)
- g_io_channel_unref(attrib->io);
-
- g_free(attrib->buf);
-
- if (attrib->destroy)
- attrib->destroy(attrib->destroy_user_data);
-
- g_free(attrib);
-}
-
-void g_attrib_unref(GAttrib *attrib)
-{
- int refs;
-
- if (!attrib)
- return;
-
- refs = __sync_sub_and_fetch(&attrib->refs, 1);
-
- DBG("%p: ref=%d", attrib, refs);
-
- if (refs > 0)
- return;
-
- attrib_destroy(attrib);
-}
-
-GIOChannel *g_attrib_get_channel(GAttrib *attrib)
-{
- if (!attrib)
- return NULL;
-
- return attrib->io;
-}
-
-gboolean g_attrib_set_destroy_function(GAttrib *attrib,
- GDestroyNotify destroy, gpointer user_data)
-{
- if (attrib == NULL)
- return FALSE;
-
- attrib->destroy = destroy;
- attrib->destroy_user_data = user_data;
-
- return TRUE;
-}
-
-static gboolean disconnect_timeout(gpointer data)
-{
- struct _GAttrib *attrib = data;
- struct command *c;
-
- g_attrib_ref(attrib);
-
- c = g_queue_pop_head(attrib->requests);
- if (c == NULL)
- goto done;
-
- if (c->func)
- c->func(ATT_ECODE_TIMEOUT, NULL, 0, c->user_data);
-
- command_destroy(c);
-
- while ((c = g_queue_pop_head(attrib->requests))) {
- if (c->func)
- c->func(ATT_ECODE_ABORTED, NULL, 0, c->user_data);
- command_destroy(c);
- }
-
-done:
- attrib->stale = true;
-
- g_attrib_unref(attrib);
-
- return FALSE;
-}
-
-static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
- gpointer data)
-{
- struct _GAttrib *attrib = data;
- struct command *cmd;
- GError *gerr = NULL;
- gsize len;
- GIOStatus iostat;
- GQueue *queue;
-
- if (attrib->stale)
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
- return FALSE;
-
- queue = attrib->responses;
- cmd = g_queue_peek_head(queue);
- if (cmd == NULL) {
- queue = attrib->requests;
- cmd = g_queue_peek_head(queue);
- }
- if (cmd == NULL)
- return FALSE;
-
- /*
- * Verify that we didn't already send this command. This can only
- * happen with elementes from attrib->requests.
- */
- if (cmd->sent)
- return FALSE;
-
- iostat = g_io_channel_write_chars(io, (char *) cmd->pdu, cmd->len,
- &len, &gerr);
- if (iostat != G_IO_STATUS_NORMAL) {
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
- }
-
- return FALSE;
- }
-
- if (cmd->expected == 0) {
- g_queue_pop_head(queue);
- command_destroy(cmd);
-
- return TRUE;
- }
-
- cmd->sent = true;
-
- if (attrib->timeout_watch == 0)
- attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT,
- disconnect_timeout, attrib);
-
- return FALSE;
-}
-
-static void destroy_sender(gpointer data)
-{
- struct _GAttrib *attrib = data;
-
- attrib->write_watch = 0;
- g_attrib_unref(attrib);
-}
-
-static void wake_up_sender(struct _GAttrib *attrib)
-{
- if (attrib->write_watch > 0)
- return;
-
- attrib = g_attrib_ref(attrib);
- attrib->write_watch = g_io_add_watch_full(attrib->io,
- G_PRIORITY_DEFAULT, G_IO_OUT,
- can_write_data, attrib, destroy_sender);
-}
-
-static bool match_event(struct event *evt, const uint8_t *pdu, gsize len)
-{
- guint16 handle;
-
- if (is_request(pdu[0]) && evt->expected == GATTRIB_ALL_REQS)
- return true;
-
- if (evt->expected == pdu[0] && evt->handle == GATTRIB_ALL_HANDLES)
- return true;
-
- if (len < 3)
- return false;
-
- handle = get_le16(&pdu[1]);
-
- if (evt->expected == pdu[0] && evt->handle == handle)
- return true;
-
- return false;
-}
-
-static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
-{
- struct _GAttrib *attrib = data;
- struct command *cmd = NULL;
- GSList *l;
- uint8_t buf[512], status;
- gsize len;
- GIOStatus iostat;
-
- if (attrib->stale)
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- struct command *c;
-
- while ((c = g_queue_pop_head(attrib->requests))) {
- if (c->func)
- c->func(ATT_ECODE_IO, NULL, 0, c->user_data);
- command_destroy(c);
- }
-
- attrib->read_watch = 0;
-
- return FALSE;
- }
-
- memset(buf, 0, sizeof(buf));
-
- iostat = g_io_channel_read_chars(io, (char *) buf, sizeof(buf),
- &len, NULL);
- if (iostat != G_IO_STATUS_NORMAL) {
- status = ATT_ECODE_IO;
- goto done;
- }
-
- for (l = attrib->events; l; l = l->next) {
- struct event *evt = l->data;
-
- if (match_event(evt, buf, len))
- evt->func(buf, len, evt->user_data);
- }
-
- if (!is_response(buf[0]))
- return TRUE;
-
- if (attrib->timeout_watch > 0) {
- g_source_remove(attrib->timeout_watch);
- attrib->timeout_watch = 0;
- }
-
- cmd = g_queue_pop_head(attrib->requests);
- if (cmd == NULL) {
- /* Keep the watch if we have events to report */
- return attrib->events != NULL;
- }
-
- if (buf[0] == ATT_OP_ERROR) {
- status = buf[4];
- goto done;
- }
-
- if (cmd->expected != buf[0]) {
- status = ATT_ECODE_IO;
- goto done;
- }
-
- status = 0;
-
-done:
- if (!g_queue_is_empty(attrib->requests) ||
- !g_queue_is_empty(attrib->responses))
- wake_up_sender(attrib);
-
- if (cmd) {
- if (cmd->func)
- cmd->func(status, buf, len, cmd->user_data);
-
- command_destroy(cmd);
- }
-
- return TRUE;
-}
-
-GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
-{
- struct _GAttrib *attrib;
-
- g_io_channel_set_encoding(io, NULL, NULL);
- g_io_channel_set_buffered(io, FALSE);
-
- attrib = g_try_new0(struct _GAttrib, 1);
- if (attrib == NULL)
- return NULL;
-
- attrib->buf = g_malloc0(mtu);
- attrib->buflen = mtu;
-
- attrib->io = g_io_channel_ref(io);
- attrib->requests = g_queue_new();
- attrib->responses = g_queue_new();
-
- attrib->read_watch = g_io_add_watch(attrib->io,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- received_data, attrib);
-
- return g_attrib_ref(attrib);
-}
-
-guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
- GAttribResultFunc func, gpointer user_data,
- GDestroyNotify notify)
-{
- struct command *c;
- GQueue *queue;
- uint8_t opcode;
-
- if (attrib->stale)
- return 0;
-
- c = g_try_new0(struct command, 1);
- if (c == NULL)
- return 0;
-
- opcode = pdu[0];
-
- c->opcode = opcode;
- c->expected = opcode2expected(opcode);
- c->pdu = g_malloc(len);
- memcpy(c->pdu, pdu, len);
- c->len = len;
- c->func = func;
- c->user_data = user_data;
- c->notify = notify;
-
- if (is_response(opcode))
- queue = attrib->responses;
- else
- queue = attrib->requests;
-
- if (id) {
- c->id = id;
- if (!is_response(opcode))
- g_queue_push_head(queue, c);
- else
- /* Don't re-order responses even if an ID is given */
- g_queue_push_tail(queue, c);
- } else {
- c->id = ++attrib->next_cmd_id;
- g_queue_push_tail(queue, c);
- }
-
- /*
- * If a command was added to the queue and it was empty before, wake up
- * the sender. If the sender was already woken up by the second queue,
- * wake_up_sender will just return.
- */
- if (g_queue_get_length(queue) == 1)
- wake_up_sender(attrib);
-
- return c->id;
-}
-
-static int command_cmp_by_id(gconstpointer a, gconstpointer b)
-{
- const struct command *cmd = a;
- guint id = GPOINTER_TO_UINT(b);
-
- return cmd->id - id;
-}
-
-gboolean g_attrib_cancel(GAttrib *attrib, guint id)
-{
- GList *l = NULL;
- struct command *cmd;
- GQueue *queue;
-
- if (attrib == NULL)
- return FALSE;
-
- queue = attrib->requests;
- if (queue)
- l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
- command_cmp_by_id);
- if (l == NULL) {
- queue = attrib->responses;
- if (!queue)
- return FALSE;
- l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
- command_cmp_by_id);
- }
-
- if (l == NULL)
- return FALSE;
-
- cmd = l->data;
-
- if (cmd == g_queue_peek_head(queue) && cmd->sent)
- cmd->func = NULL;
- else {
- g_queue_remove(queue, cmd);
- command_destroy(cmd);
- }
-
- return TRUE;
-}
-
-static gboolean cancel_all_per_queue(GQueue *queue)
-{
- struct command *c, *head = NULL;
- gboolean first = TRUE;
-
- if (queue == NULL)
- return FALSE;
-
- while ((c = g_queue_pop_head(queue))) {
- if (first && c->sent) {
- /* If the command was sent ignore its callback ... */
- c->func = NULL;
- head = c;
- continue;
- }
-
- first = FALSE;
- command_destroy(c);
- }
-
- if (head) {
- /* ... and put it back in the queue */
- g_queue_push_head(queue, head);
- }
-
- return TRUE;
-}
-
-gboolean g_attrib_cancel_all(GAttrib *attrib)
-{
- gboolean ret;
-
- if (attrib == NULL)
- return FALSE;
-
- ret = cancel_all_per_queue(attrib->requests);
- ret = cancel_all_per_queue(attrib->responses) && ret;
-
- return ret;
-}
-
-uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
-{
- if (len == NULL)
- return NULL;
-
- *len = attrib->buflen;
-
- return attrib->buf;
-}
-
-gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
-{
- if (mtu < ATT_DEFAULT_LE_MTU)
- return FALSE;
-
- attrib->buf = g_realloc(attrib->buf, mtu);
-
- attrib->buflen = mtu;
-
- return TRUE;
-}
-
-guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
- GAttribNotifyFunc func, gpointer user_data,
- GDestroyNotify notify)
-{
- static guint next_evt_id = 0;
- struct event *event;
-
- event = g_try_new0(struct event, 1);
- if (event == NULL)
- return 0;
-
- event->expected = opcode;
- event->handle = handle;
- event->func = func;
- event->user_data = user_data;
- event->notify = notify;
- event->id = ++next_evt_id;
-
- attrib->events = g_slist_append(attrib->events, event);
-
- return event->id;
-}
-
-static int event_cmp_by_id(gconstpointer a, gconstpointer b)
-{
- const struct event *evt = a;
- guint id = GPOINTER_TO_UINT(b);
-
- return evt->id - id;
-}
-
-gboolean g_attrib_unregister(GAttrib *attrib, guint id)
-{
- struct event *evt;
- GSList *l;
-
- if (id == 0) {
- warn("%s: invalid id", __func__);
- return FALSE;
- }
-
- l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
- event_cmp_by_id);
- if (l == NULL)
- return FALSE;
-
- evt = l->data;
-
- attrib->events = g_slist_remove(attrib->events, evt);
-
- if (evt->notify)
- evt->notify(evt->user_data);
-
- g_free(evt);
-
- return TRUE;
-}
-
-gboolean g_attrib_unregister_all(GAttrib *attrib)
-{
- GSList *l;
-
- if (attrib->events == NULL)
- return FALSE;
-
- for (l = attrib->events; l; l = l->next) {
- struct event *evt = l->data;
-
- if (evt->notify)
- evt->notify(evt->user_data);
-
- g_free(evt);
- }
-
- g_slist_free(attrib->events);
- attrib->events = NULL;
-
- return TRUE;
-}
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010 Marcel Holtmann <[email protected]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <glib.h>
+
+#include <stdio.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "btio/btio.h"
+#include "src/log.h"
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "attrib/gattrib.h"
+
+struct _GAttrib {
+ int ref_count;
+ struct bt_att *att;
+ GIOChannel *io;
+ GDestroyNotify destroy;
+ gpointer destroy_user_data;
+ GQueue *callbacks;
+ uint8_t *buf;
+ int buflen;
+};
+
+
+struct attrib_callbacks {
+ GAttribResultFunc result_func;
+ GAttribNotifyFunc notify_func;
+ GDestroyNotify destroy_func;
+ gpointer user_data;
+ GAttrib *parent;
+ uint16_t notify_handle;
+};
+
+GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
+{
+ gint fd;
+ GAttrib *attr;
+
+ if (!io)
+ return NULL;
+
+ fd = g_io_channel_unix_get_fd(io);
+ attr = new0(GAttrib, 1);
+ if (!attr)
+ return NULL;
+
+ g_io_channel_ref(io);
+ attr->io = io;
+
+ attr->att = bt_att_new(fd);
+ if (!attr->att)
+ goto fail;
+
+ attr->buf = g_malloc0(mtu);
+ attr->buflen = mtu;
+ if (!attr->buf)
+ goto fail;
+
+ attr->callbacks = g_queue_new();
+ if (!attr->callbacks)
+ goto fail;
+
+ return g_attrib_ref(attr);
+
+fail:
+ free(attr->buf);
+ bt_att_unref(attr->att);
+ g_io_channel_unref(io);
+ free(attr);
+ return NULL;
+}
+
+GAttrib *g_attrib_ref(GAttrib *attrib)
+{
+ if (!attrib)
+ return NULL;
+
+ __sync_fetch_and_add(&attrib->ref_count, 1);
+
+ DBG("%p: g_attrib_ref=%d ", attrib, attrib->ref_count);
+
+ return attrib;
+}
+
+static void attrib_callbacks_destroy(void *user_data)
+{
+ struct attrib_callbacks *cb = user_data;
+
+ if (!user_data || !g_queue_remove(cb->parent->callbacks, user_data))
+ return;
+
+ if (cb->destroy_func)
+ cb->destroy_func(cb->user_data);
+
+ free(user_data);
+}
+
+void g_attrib_unref(GAttrib *attrib)
+{
+ struct attrib_callbacks *cb;
+
+ if (!attrib)
+ return;
+
+ DBG("%p: g_attrib_unref=%d ", attrib, attrib->ref_count - 1);
+
+ if (__sync_sub_and_fetch(&attrib->ref_count, 1))
+ return;
+
+ if (attrib->destroy)
+ attrib->destroy(attrib->destroy_user_data);
+
+ while ((cb = g_queue_peek_head(attrib->callbacks)))
+ attrib_callbacks_destroy(cb);
+
+ g_queue_free(attrib->callbacks);
+
+ g_free(attrib->buf);
+
+ bt_att_unref(attrib->att);
+
+ g_io_channel_unref(attrib->io);
+
+ g_free(attrib);
+}
+
+GIOChannel *g_attrib_get_channel(GAttrib *attrib)
+{
+ if (!attrib)
+ return NULL;
+
+ return attrib->io;
+}
+
+gboolean g_attrib_set_destroy_function(GAttrib *attrib,
+ GDestroyNotify destroy, gpointer user_data)
+{
+ if (!attrib)
+ return FALSE;
+
+ attrib->destroy = destroy;
+ attrib->destroy_user_data = user_data;
+
+ return TRUE;
+}
+
+
+static uint8_t *construct_full_pdu(uint8_t opcode, const void *pdu,
+ uint16_t length)
+{
+ uint8_t *buf = malloc0(length + 1);
+
+ if (!buf)
+ return NULL;
+
+ buf[0] = opcode;
+ memcpy(buf + 1, pdu, length);
+
+ return buf;
+}
+
+static void attrib_callback_result(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ uint8_t *buf;
+ struct attrib_callbacks *cb = user_data;
+ guint8 status = 0;
+
+ if (!cb)
+ return;
+
+ buf = construct_full_pdu(opcode, pdu, length);
+ if (!buf)
+ return;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ /* Error code is the third byte of the PDU data */
+ if (length < 4)
+ status = BT_ATT_ERROR_UNLIKELY;
+ else
+ status = ((guint8 *)pdu)[3];
+ }
+
+ if (cb->result_func)
+ cb->result_func(status, buf, length + 1, cb->user_data);
+
+ free(buf);
+}
+
+
+static void attrib_callback_notify(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ uint8_t *buf;
+ struct attrib_callbacks *cb = user_data;
+
+ if (!cb || !cb->notify_func)
+ return;
+
+ if (cb->notify_handle != GATTRIB_ALL_HANDLES && length < 2)
+ return;
+
+ if (cb->notify_handle != GATTRIB_ALL_HANDLES &&
+ cb->notify_handle != get_le16(pdu))
+ return;
+
+ buf = construct_full_pdu(opcode, pdu, length);
+ if (!buf)
+ return;
+
+ cb->notify_func(buf, length + 1, cb->user_data);
+
+ free(buf);
+}
+
+guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
+ GAttribResultFunc func, gpointer user_data,
+ GDestroyNotify notify)
+{
+ struct attrib_callbacks *cb = NULL;
+ bt_att_response_func_t response_cb = NULL;
+ bt_att_destroy_func_t destroy_cb = NULL;
+
+ if (!pdu || !len)
+ return 0;
+
+ if (func || notify) {
+ cb = new0(struct attrib_callbacks, 1);
+ if (!cb)
+ return 0;
+ cb->result_func = func;
+ cb->user_data = user_data;
+ cb->destroy_func = notify;
+ cb->parent = attrib;
+ g_queue_push_head(attrib->callbacks, cb);
+ response_cb = attrib_callback_result;
+ destroy_cb = attrib_callbacks_destroy;
+ }
+
+ return bt_att_send(attrib->att, pdu[0], (void *)pdu + 1, len - 1,
+ response_cb, cb, destroy_cb);
+}
+
+gboolean g_attrib_cancel(GAttrib *attrib, guint id)
+{
+ return bt_att_cancel(attrib->att, id);
+}
+
+gboolean g_attrib_cancel_all(GAttrib *attrib)
+{
+ return bt_att_cancel_all(attrib->att);
+}
+
+guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
+ GAttribNotifyFunc func, gpointer user_data,
+ GDestroyNotify notify)
+{
+ struct attrib_callbacks *cb = NULL;
+
+ if (func || notify) {
+ cb = new0(struct attrib_callbacks, 1);
+ if (!cb)
+ return 0;
+ cb->notify_func = func;
+ cb->notify_handle = handle;
+ cb->user_data = user_data;
+ cb->destroy_func = notify;
+ cb->parent = attrib;
+ g_queue_push_head(attrib->callbacks, cb);
+ }
+
+ if (opcode == GATTRIB_ALL_REQS)
+ opcode = BT_ATT_ALL_REQUESTS;
+
+ return bt_att_register(attrib->att, opcode, attrib_callback_notify,
+ cb, attrib_callbacks_destroy);
+}
+
+uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
+{
+ if (!len)
+ return NULL;
+
+ *len = attrib->buflen;
+ return attrib->buf;
+}
+
+gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
+{
+ /* Clients of this expect a buffer to use. */
+ if (mtu > attrib->buflen) {
+ attrib->buf = g_realloc(attrib->buf, mtu);
+ attrib->buflen = mtu;
+ }
+
+ return bt_att_set_mtu(attrib->att, mtu);
+}
+
+gboolean g_attrib_unregister(GAttrib *attrib, guint id)
+{
+ return bt_att_unregister(attrib->att, id);
+}
+
+gboolean g_attrib_unregister_all(GAttrib *attrib)
+{
+ return bt_att_unregister_all(attrib->att);
+}
--
2.1.0.rc2.206.gedb03e5


2014-11-13 17:39:16

by Marie Janssen

[permalink] [raw]
Subject: [PATCH BlueZ v2 3/4] android/gatt: dummy callback for indications

Indications require a confirmation reply, and newer APIs require that a
callback is provided. Add a dummy callback which ignores this
confirmation to ensure future compatability.
---
android/gatt.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 086bb94..f26482f 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -5414,6 +5414,12 @@ failed:
HAL_OP_GATT_SERVER_DELETE_SERVICE, status);
}

+static void ignore_confirmation_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ /* Ignored. */
+}
+
static void handle_server_send_indication(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_send_indication *cmd = buf;
@@ -5422,6 +5428,7 @@ static void handle_server_send_indication(const void *buf, uint16_t len)
uint16_t length;
uint8_t *pdu;
size_t mtu;
+ GAttribResultFunc confirmation_cb = NULL;

DBG("");

@@ -5434,22 +5441,24 @@ static void handle_server_send_indication(const void *buf, uint16_t len)

pdu = g_attrib_get_buffer(conn->device->attrib, &mtu);

- if (cmd->confirm)
+ if (cmd->confirm) {
/* TODO: Add data to track confirmation for this request */
length = enc_indication(cmd->attribute_handle,
(uint8_t *)cmd->value, cmd->len, pdu,
mtu);
- else
+ confirmation_cb = ignore_confirmation_cb;
+ } else {
length = enc_notification(cmd->attribute_handle,
(uint8_t *)cmd->value, cmd->len,
pdu, mtu);
+ }

if (length == 0) {
error("gatt: Failed to encode indication");
status = HAL_STATUS_FAILED;
} else {
- g_attrib_send(conn->device->attrib, 0, pdu, length, NULL, NULL,
- NULL);
+ g_attrib_send(conn->device->attrib, 0, pdu, length,
+ confirmation_cb, NULL, NULL);
status = HAL_STATUS_SUCCESS;
}

--
2.1.0.rc2.206.gedb03e5


2014-11-13 17:39:14

by Marie Janssen

[permalink] [raw]
Subject: [PATCH BlueZ v2 1/4] android/tester-gatt: Fix search single PDUs

The final PDU of the search single exchange was malformed on many of these:
0x11 instead of 0x10 in the "request opcode in error" slot.

This patch fixes this bug and deduplicates the repeated PDUs by using a
macro instead.
---
android/tester-gatt.c | 106 +++++++++++++-------------------------------------
1 file changed, 26 insertions(+), 80 deletions(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 13e096f..b88eeff 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -832,11 +832,14 @@ static struct send_resp_data send_resp_data_2 = {
.response = &response_2,
};

+#define SEARCH_SERVICE_SINGLE_SUCCESS_PDUS \
+ raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18), \
+ raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28), \
+ raw_pdu(0x01, 0x10, 0x11, 0x00, 0x0a) \
+
static struct iovec search_service[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x10, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
end_pdu
};

@@ -857,10 +860,7 @@ static struct iovec search_service_3[] = {
};

static struct iovec get_characteristic_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -869,10 +869,7 @@ static struct iovec get_characteristic_1[] = {
};

static struct iovec get_descriptor_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -885,10 +882,7 @@ static struct iovec get_descriptor_1[] = {
};

static struct iovec get_descriptor_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -901,10 +895,7 @@ static struct iovec get_descriptor_2[] = {
};

static struct iovec get_descriptor_3[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -915,10 +906,7 @@ static struct iovec get_descriptor_3[] = {
};

static struct iovec get_included_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x02, 0x28),
raw_pdu(0x09, 0x08, 0x02, 0x00, 0x15, 0x00, 0x19, 0x00, 0xff, 0xfe),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x02, 0x28),
@@ -927,10 +915,7 @@ static struct iovec get_included_1[] = {
};

static struct iovec get_included_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x02, 0x28),
raw_pdu(0x09, 0x06, 0x02, 0x00, 0x15, 0x00, 0x19, 0x00),
raw_pdu(0x0a, 0x15, 0x00),
@@ -942,20 +927,14 @@ static struct iovec get_included_2[] = {
};

static struct iovec get_included_3[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x02, 0x28),
raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),
end_pdu
};

static struct iovec read_characteristic_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x03, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -966,10 +945,7 @@ static struct iovec read_characteristic_1[] = {
};

static struct iovec read_characteristic_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x03, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -980,10 +956,7 @@ static struct iovec read_characteristic_2[] = {
};

static struct iovec read_descriptor_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -998,10 +971,7 @@ static struct iovec read_descriptor_1[] = {
};

static struct iovec read_descriptor_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1016,10 +986,7 @@ static struct iovec read_descriptor_2[] = {
};

static struct iovec write_characteristic_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x03, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1029,10 +996,7 @@ static struct iovec write_characteristic_1[] = {
};

static struct iovec write_characteristic_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x03, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1043,10 +1007,7 @@ static struct iovec write_characteristic_2[] = {
};

static struct iovec write_characteristic_3[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x03, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1057,10 +1018,7 @@ static struct iovec write_characteristic_3[] = {
};

static struct iovec write_descriptor_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1075,10 +1033,7 @@ static struct iovec write_descriptor_1[] = {
};

static struct iovec write_descriptor_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1093,10 +1048,7 @@ static struct iovec write_descriptor_2[] = {
};

static struct iovec notification_1[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1105,10 +1057,7 @@ static struct iovec notification_1[] = {
};

static struct iovec notification_2[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
@@ -1119,10 +1068,7 @@ static struct iovec notification_2[] = {
};

static struct iovec notification_3[] = {
- raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
- raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28),
- raw_pdu(0x01, 0x11, 0x11, 0x00, 0x0a),
+ SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
--
2.1.0.rc2.206.gedb03e5


2014-11-13 17:39:15

by Marie Janssen

[permalink] [raw]
Subject: [PATCH BlueZ v2 2/4] android/tester-gatt: deduplicate read-by-type PDUs

These read-by-type PDUs are repeated multiple times throughout the code.
---
android/tester-gatt.c | 63 +++++++++++++++------------------------------------
1 file changed, 18 insertions(+), 45 deletions(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index b88eeff..ebfa005 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -836,7 +836,13 @@ static struct send_resp_data send_resp_data_2 = {
raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18), \
raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x00, 0x28), \
- raw_pdu(0x01, 0x10, 0x11, 0x00, 0x0a) \
+ raw_pdu(0x01, 0x10, 0x11, 0x00, 0x0a)
+
+#define READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS \
+ raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28), \
+ raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00), \
+ raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28), \
+ raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a)

static struct iovec search_service[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
@@ -861,19 +867,13 @@ static struct iovec search_service_3[] = {

static struct iovec get_characteristic_1[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
end_pdu
};

static struct iovec get_descriptor_1[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x05, 0x01, 0x04, 0x00, 0x00, 0x29),
raw_pdu(0x04, 0x05, 0x00, 0x10, 0x00),
@@ -883,10 +883,7 @@ static struct iovec get_descriptor_1[] = {

static struct iovec get_descriptor_2[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x05, 0x01, 0x04, 0x00, 0x00, 0x29, 0x05, 0x00, 0x01, 0x29),
raw_pdu(0x04, 0x06, 0x00, 0x10, 0x00),
@@ -896,10 +893,7 @@ static struct iovec get_descriptor_2[] = {

static struct iovec get_descriptor_3[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x01, 0x04, 0x01, 0x00, 0x0a),
end_pdu
@@ -957,10 +951,7 @@ static struct iovec read_characteristic_2[] = {

static struct iovec read_descriptor_1[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x05, 0x01, 0x04, 0x00, 0x00, 0x29),
raw_pdu(0x04, 0x05, 0x00, 0x10, 0x00),
@@ -972,10 +963,7 @@ static struct iovec read_descriptor_1[] = {

static struct iovec read_descriptor_2[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x05, 0x01, 0x04, 0x00, 0x00, 0x29),
raw_pdu(0x04, 0x05, 0x00, 0x10, 0x00),
@@ -1019,10 +1007,7 @@ static struct iovec write_characteristic_3[] = {

static struct iovec write_descriptor_1[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x05, 0x01, 0x04, 0x00, 0x00, 0x29),
raw_pdu(0x04, 0x05, 0x00, 0x10, 0x00),
@@ -1034,10 +1019,7 @@ static struct iovec write_descriptor_1[] = {

static struct iovec write_descriptor_2[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
raw_pdu(0x05, 0x01, 0x04, 0x00, 0x00, 0x29),
raw_pdu(0x04, 0x05, 0x00, 0x10, 0x00),
@@ -1049,19 +1031,13 @@ static struct iovec write_descriptor_2[] = {

static struct iovec notification_1[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
end_pdu
};

static struct iovec notification_2[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x1d, 0x03, 0x00, 0x01),
raw_pdu(0x1e),
end_pdu
@@ -1069,10 +1045,7 @@ static struct iovec notification_2[] = {

static struct iovec notification_3[] = {
SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
- raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x09, 0x07, 0x02, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
- raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),
- raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),
+ READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
raw_pdu(0x1b, 0x03, 0x00, 0x01),
end_pdu
};
--
2.1.0.rc2.206.gedb03e5


2014-11-06 15:07:56

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v2 4/4] GATT shim to src/shared bt_att

Hi Michael

On Thu, Nov 6, 2014 at 4:15 AM, Michael Janssen <[email protected]> wrote:
> This patch implements a version of GAttrib which is backed by
> bt_att, which enables the simultaneous use of GAttrib and bt_att.
>
> This should enable smooth transition of profiles from the GAttrib
> API to the src/shared bt_att API.
> ---
> attrib/gattrib.c | 1077 ++++++++++++++++--------------------------------------
> 1 file changed, 319 insertions(+), 758 deletions(-)
> rewrite attrib/gattrib.c (80%)

I tried it and it does not pass the unit tests:

/gattrib/register: **
ERROR:unit/test-gattrib.c:479:test_register: assertion failed:
(current_pdu->received)

Also, we need to make sure it does cause any regressions to android-tester:

>sudo android/android-tester -d -p "Gatt":

Test Summary
------------
Gatt Init Passed 0.012 seconds
Gatt Client - Register Passed 0.012 seconds
Gatt Client - Unregister Passed 0.013 seconds
Gatt Client - Scan Passed 0.018 seconds
Gatt Client - LE Connect Passed 0.037 seconds
Gatt Client - LE Disconnect Passed 0.042 seconds
Gatt Client - LE Multiple Client Conn./Disc. Passed 0.036 seconds
Gatt Client - Listen and Disconnect Passed 0.035 seconds
Gatt Client - Double Listen Passed 0.065 seconds
Gatt Client - Search Service - Single Timed out 3.420 seconds
Gatt Client - Search Service - Multiple Timed out 3.004 seconds
Gatt Client - Search Service - None Passed 0.043 seconds
Gatt Client - Get Characteristic - Single Timed out 2.964 seconds
Gatt Client - Get Characteristic - None Passed 0.041 seconds
Gatt Client - Get Descriptor - Single Timed out 2.948 seconds
Gatt Client - Get Descriptor - Multiple Timed out 3.000 seconds
Gatt Client - Get Descriptor - None Timed out 3.002 seconds
Gatt Client - Get Included Service - 16 UUID Timed out 3.005 seconds
Gatt Client - Get Included Service - 128 UUID Timed out 2.999 seconds
Gatt Client - Get Included Service - None Timed out 2.996 seconds
Gatt Client - Read Characteristic - Success Timed out 2.999 seconds
Gatt Client - Read Characteristic - Insuf. Auth. Timed out 2.998 seconds
Gatt Client - Read Characteristic - Wrong params Timed out 3.001 seconds
Gatt Client - Read Descriptor - Success Timed out 3.009 seconds
Gatt Client - Read Descriptor - Insuf. Auth. Timed out 2.992 seconds
Gatt Client - Read Descriptor - Wrong params Timed out 3.006 seconds
Gatt Client - Write Characteristic Cmd - Success Timed out 3.000 seconds
Gatt Client - Write Characteristic Req - Success Timed out 3.004 seconds
Gatt Client - Write Characteristic - Insuf. Auth. Timed out 2.991 seconds
Gatt Client - Write Characteristic - Wrong Params Passed 0.018 seconds
Gatt Client - Register For Notification - Success Timed out 2.977 seconds
Gatt Client - Deregister For Notification - Success Timed out 3.010 seconds
Gatt Client - Register For Notification - Indicate Timed out 3.001 seconds
Gatt Client - Register For Notification - Notify Timed out 2.994 seconds
Gatt Client - Write Descriptor - Success Timed out 3.002 seconds
Gatt Client - Write Descriptor - Insuf. Auth. Timed out 2.999 seconds
Gatt Client - Write Descriptor - Wrong Param Timed out 3.001 seconds
Gatt Server - Register Passed 0.027 seconds
Gatt Server - Unregister Passed 0.021 seconds
Gatt Server - LE Connect Passed 0.039 seconds
Gatt Server - LE Disconnect Passed 0.036 seconds
Gatt Server - LE Multiple Server Conn./Disc Passed 0.032 seconds
Gatt Server - Add Single Service Successful Passed 0.016 seconds
Gatt Server - Add Multiple Services Successful Passed 0.016 seconds
Gatt Server - Add Service with 0 handles Passed 0.013 seconds
Gatt Server - Add Secondary Service Passed 0.012 seconds
Gatt Server - Add Included Service Successful Passed 0.015 seconds
Gatt Server - Add Inc. Service with wrong handle Passed 0.014 seconds
Gatt Server - Add Single Characteristic Successful Passed 0.018 seconds
Gatt Server - Add Char. wrong service handle Passed 0.015 seconds
Gatt Server - Add Single Descriptor Successful Passed 0.017 seconds
Gatt Server - Add Desc. wrong service handle Passed 0.015 seconds
Gatt Server - Add Desc. wrong app ID Passed 0.013 seconds
Gatt Server - Start Service Successful BREDRLE Passed 0.014 seconds
Gatt Server - Start Service Successful LE Passed 0.016 seconds
Gatt Server - Start Service wrong service handle Passed 0.014 seconds
Gatt Server - Start Service wrong server transport Passed 0.016 seconds
Gatt Server - Stop Service Successful Passed 0.015 seconds
Gatt Server - Stop Service wrong service handle Passed 0.017 seconds
Gatt Server - Delete Service Successful Passed 0.014 seconds
Gatt Server - Delete Service wrong handle Passed 0.017 seconds
Gatt Server - Send Indication Timed out 3.557 seconds
Gatt Server - Send Notification Passed 0.033 seconds
Gatt Server - Send Notification, wrong conn id Passed 0.031 seconds
Gatt Server - Send response to read char request Timed out 2.943 seconds
Gatt Server - Send response to write char request Timed out 2.997 seconds

Total: 66, Passed: 38 (57.6%), Failed: 28, Not Run: 0