* Re: [PATCH_v2 1/2] android/hidhost: Fix miscalculation of get report event notification length
From: Szymon Janc @ 2014-01-21 15:20 UTC (permalink / raw)
To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <1390307059-7772-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Hi Ravi,
On Tuesday 21 of January 2014 14:24:18 Ravi kumar Veeramally wrote:
> Event length is size of struct + data len (if any). It is miscalulated.
> ---
> android/hidhost.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/android/hidhost.c b/android/hidhost.c
> index 3da77c8..108493a 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -371,7 +371,7 @@ static void bt_hid_notify_get_report(struct hid_device *dev, uint8_t *buf,
> ba2str(&dev->dst, address);
> DBG("device %s", address);
>
> - ev_len = sizeof(*ev) + sizeof(struct hal_ev_hidhost_get_report) + 1;
> + ev_len = sizeof(*ev);
>
> if (!((buf[0] == (HID_MSG_DATA | HID_DATA_TYPE_INPUT)) ||
> (buf[0] == (HID_MSG_DATA | HID_DATA_TYPE_OUTPUT)) ||
>
Both patches applied, thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* [PATCH 5/5] android/bluetooth: Add support for loading caches devices from storage
From: Szymon Janc @ 2014-01-21 15:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390316497-18451-1-git-send-email-szymon.janc@tieto.com>
Info is now stored for all devices and bond state depends on linkkey
being stored. Based on that devices loaded from storage are put either
to cache or to bonded_devices list.
---
android/bluetooth.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 6afde35..80490f1 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1688,7 +1688,8 @@ static void clear_uuids(void)
sizeof(cp), &cp, NULL, NULL, NULL);
}
-static void create_device_from_info(GKeyFile *key_file, const char *peer)
+static struct device *create_device_from_info(GKeyFile *key_file,
+ const char *peer)
{
struct device *dev;
uint8_t type;
@@ -1703,7 +1704,7 @@ static void create_device_from_info(GKeyFile *key_file, const char *peer)
str2ba(peer, &bdaddr);
dev = create_device(&bdaddr, type);
- dev->bond_state = HAL_BOND_STATE_BONDED;
+ dev->bond_state = HAL_BOND_STATE_NONE;
str = g_key_file_get_string(key_file, peer, "Name", NULL);
if (str) {
@@ -1739,6 +1740,8 @@ static void create_device_from_info(GKeyFile *key_file, const char *peer)
g_strfreev(uuids);
}
+
+ return dev;
}
static struct mgmt_link_key_info *get_key_info(GKeyFile *key_file, const char *peer)
@@ -1771,6 +1774,14 @@ failed:
return info;
}
+static int device_timestamp_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct device *deva = a;
+ const struct device *devb = b;
+
+ return deva->timestamp < devb->timestamp;
+}
+
static void load_devices_info(bt_bluetooth_ready cb)
{
GKeyFile *key_file;
@@ -1787,16 +1798,24 @@ static void load_devices_info(bt_bluetooth_ready cb)
for (i = 0; i < len; i++) {
struct mgmt_link_key_info *key_info;
+ struct device *dev;
- create_device_from_info(key_file, devs[i]);
+ dev = create_device_from_info(key_file, devs[i]);
key_info = get_key_info(key_file, devs[i]);
- if (key_info)
+ if (key_info) {
keys = g_slist_prepend(keys, key_info);
+ bonded_devices = g_slist_prepend(bonded_devices, dev);
+ dev->bond_state = HAL_BOND_STATE_BONDED;
+ } else {
+ devices = g_slist_prepend(devices, dev);
+ }
/* TODO ltk */
}
+ devices = g_slist_sort(devices, device_timestamp_cmp);
+
load_link_keys(keys, cb);
g_strfreev(devs);
g_slist_free_full(keys, g_free);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/5] android/bluetooth: Add support for caching remote device info
From: Szymon Janc @ 2014-01-21 15:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390316497-18451-1-git-send-email-szymon.janc@tieto.com>
Cache is limited to DEVICES_CACHE_MAX. Devices are sorted with
timestamp so if cache is full olderst device is removed.
---
android/bluetooth.c | 72 +++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 56 insertions(+), 16 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index f32dd91..6afde35 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -70,6 +70,8 @@
/* Default discoverable timeout 120sec as in Android */
#define DEFAULT_DISCOVERABLE_TIMEOUT 120
+#define DEVICES_CACHE_MAX 300
+
#define BASELEN_PROP_CHANGED (sizeof(struct hal_ev_adapter_props_changed) \
+ (sizeof(struct hal_property)))
@@ -260,6 +262,27 @@ static void store_device_info(struct device *dev)
g_strfreev(uuids);
}
+static void remove_device_info(struct device *dev)
+{
+ GKeyFile *key_file;
+ gsize length = 0;
+ char addr[18];
+ char *str;
+
+ ba2str(&dev->bdaddr, addr);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL);
+
+ g_key_file_remove_group(key_file, addr, NULL);
+
+ str = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(DEVICES_FILE, str, length, NULL);
+ g_free(str);
+
+ g_key_file_free(key_file);
+}
+
static int device_match(gconstpointer a, gconstpointer b)
{
const struct device *dev = a;
@@ -283,6 +306,35 @@ static struct device *find_device(const bdaddr_t *bdaddr)
return NULL;
}
+static void free_device(struct device *dev)
+{
+ g_free(dev->name);
+ g_free(dev->friendly_name);
+ g_slist_free_full(dev->uuids, g_free);
+ g_free(dev);
+}
+
+static void cache_device(struct device *new_dev)
+{
+ struct device *dev;
+ GSList *l;
+
+ if (g_slist_length(devices) < DEVICES_CACHE_MAX)
+ goto done;
+
+ l = g_slist_last(devices);
+ dev = l->data;
+
+ devices = g_slist_remove(bonded_devices, dev);
+ remove_device_info(dev);
+ free_device(dev);
+
+done:
+ new_dev->timestamp = time(NULL);
+ devices = g_slist_prepend(devices, new_dev);
+ store_device_info(new_dev);
+}
+
static struct device *create_device(const bdaddr_t *bdaddr, uint8_t type)
{
struct device *dev;
@@ -301,19 +353,10 @@ static struct device *create_device(const bdaddr_t *bdaddr, uint8_t type)
/* use address for name, will be change if one is present
* eg. in EIR or set by set_property. */
dev->name = g_strdup(addr);
- devices = g_slist_prepend(devices, dev);
return dev;
}
-static void free_device(struct device *dev)
-{
- g_free(dev->name);
- g_free(dev->friendly_name);
- g_slist_free_full(dev->uuids, g_free);
- g_free(dev);
-}
-
static struct device *get_device(const bdaddr_t *bdaddr, uint8_t type)
{
struct device *dev;
@@ -585,7 +628,8 @@ static void set_device_bond_state(const bdaddr_t *addr, uint8_t status,
case HAL_BOND_STATE_NONE:
if (dev->bond_state == HAL_BOND_STATE_BONDED) {
bonded_devices = g_slist_remove(bonded_devices, dev);
- devices = g_slist_prepend(devices, dev);
+ remove_stored_link_key(&dev->bdaddr);
+ cache_device(dev);
}
break;
case HAL_BOND_STATE_BONDED:
@@ -599,8 +643,6 @@ static void set_device_bond_state(const bdaddr_t *addr, uint8_t status,
dev->bond_state = state;
- store_device_info(dev);
-
send_bond_state_change(&dev->bdaddr, status, state);
}
@@ -1071,8 +1113,6 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
ev->status = HAL_STATUS_SUCCESS;
bdaddr2android(bdaddr, ev->bdaddr);
-
- dev->timestamp = time(NULL);
}
if (eir.class) {
@@ -1100,6 +1140,8 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
(*num_prop)++;
}
+ cache_device(dev);
+
if (*num_prop)
ipc_send_notif(HAL_SERVICE_ID_BLUETOOTH, opcode, size, buf);
@@ -2457,8 +2499,6 @@ static void unpair_device_complete(uint8_t status, uint16_t length,
if (status != MGMT_STATUS_SUCCESS)
return;
- remove_stored_link_key(&rp->addr.bdaddr);
-
set_device_bond_state(&rp->addr.bdaddr, HAL_STATUS_SUCCESS,
HAL_BOND_STATE_NONE);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/5] android/bluetooth: Always store device info
From: Szymon Janc @ 2014-01-21 15:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390316497-18451-1-git-send-email-szymon.janc@tieto.com>
This allows to cache remote device informations.
---
android/bluetooth.c | 42 +++++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 3314267..f32dd91 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -207,23 +207,11 @@ static void store_device_info(struct device *dev)
char **uuids = NULL;
char *str;
- /* We only store bonded devices and need to modify the storage
- * if the state is either NONE or BONDED.
- */
- if (dev->bond_state != HAL_BOND_STATE_BONDED &&
- dev->bond_state != HAL_BOND_STATE_NONE)
- return;
-
ba2str(&dev->bdaddr, addr);
key_file = g_key_file_new();
g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL);
- if (dev->bond_state == HAL_BOND_STATE_NONE) {
- g_key_file_remove_group(key_file, addr, NULL);
- goto done;
- }
-
g_key_file_set_integer(key_file, addr, "Type", dev->bdaddr_type);
g_key_file_set_string(key_file, addr, "Name", dev->name);
@@ -264,7 +252,6 @@ static void store_device_info(struct device *dev)
g_key_file_remove_key(key_file, addr, "Services", NULL);
}
-done:
str = g_key_file_to_data(key_file, &length, NULL);
g_file_set_contents(DEVICES_FILE, str, length, NULL);
g_free(str);
@@ -542,6 +529,33 @@ static void store_link_key(const bdaddr_t *dst, const uint8_t *key,
g_key_file_free(key_file);
}
+static void remove_stored_link_key(const bdaddr_t *dst)
+{
+ GKeyFile *key_file;
+ gsize length = 0;
+ char addr[18];
+ char *data;
+
+ key_file = g_key_file_new();
+
+ if (!g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL))
+ return;
+
+ ba2str(dst, addr);
+
+ DBG("%s", addr);
+
+ g_key_file_remove_key(key_file, addr, "LinkKey", NULL);
+ g_key_file_remove_key(key_file, addr, "LinkKeyType", NULL);
+ g_key_file_remove_key(key_file, addr, "LinkKeyPinLength", NULL);
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(DEVICES_FILE, data, length, NULL);
+ g_free(data);
+
+ g_key_file_free(key_file);
+}
+
static void send_bond_state_change(const bdaddr_t *addr, uint8_t status,
uint8_t state)
{
@@ -2443,6 +2457,8 @@ static void unpair_device_complete(uint8_t status, uint16_t length,
if (status != MGMT_STATUS_SUCCESS)
return;
+ remove_stored_link_key(&rp->addr.bdaddr);
+
set_device_bond_state(&rp->addr.bdaddr, HAL_STATUS_SUCCESS,
HAL_BOND_STATE_NONE);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/5] android/bluetooth: Use defines for settings and devices files paths
From: Szymon Janc @ 2014-01-21 15:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390316497-18451-1-git-send-email-szymon.janc@tieto.com>
From: Szymon Janc <szymon.janc@gmail.com>
---
android/bluetooth.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 8f08122..3314267 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -54,6 +54,9 @@
#define DUT_MODE_FILE "/sys/kernel/debug/bluetooth/hci%u/dut_mode"
+#define SETTINGS_FILE ANDROID_STORAGEDIR"/settings"
+#define DEVICES_FILE ANDROID_STORAGEDIR"/devices"
+
#define DEVICE_ID_SOURCE 0x0002 /* USB */
#define DEVICE_ID_VENDOR 0x1d6b /* Linux Foundation */
#define DEVICE_ID_PRODUCT 0x0247 /* BlueZ for Android */
@@ -148,8 +151,7 @@ static void store_adapter_config(void)
key_file = g_key_file_new();
- g_key_file_load_from_file(key_file, ANDROID_STORAGEDIR"/settings", 0,
- NULL);
+ g_key_file_load_from_file(key_file, SETTINGS_FILE, 0, NULL);
ba2str(&adapter.bdaddr, addr);
@@ -160,7 +162,7 @@ static void store_adapter_config(void)
data = g_key_file_to_data(key_file, &length, NULL);
- g_file_set_contents(ANDROID_STORAGEDIR"/settings", data, length, NULL);
+ g_file_set_contents(SETTINGS_FILE, data, length, NULL);
g_free(data);
g_key_file_free(key_file);
@@ -173,8 +175,7 @@ static void load_adapter_config(void)
char *str;
key_file = g_key_file_new();
- g_key_file_load_from_file(key_file, ANDROID_STORAGEDIR"/settings", 0,
- NULL);
+ g_key_file_load_from_file(key_file, SETTINGS_FILE, 0, NULL);
str = g_key_file_get_string(key_file, "General", "Address", NULL);
if (!str) {
@@ -216,8 +217,7 @@ static void store_device_info(struct device *dev)
ba2str(&dev->bdaddr, addr);
key_file = g_key_file_new();
- g_key_file_load_from_file(key_file, ANDROID_STORAGEDIR"/devices", 0,
- NULL);
+ g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL);
if (dev->bond_state == HAL_BOND_STATE_NONE) {
g_key_file_remove_group(key_file, addr, NULL);
@@ -266,7 +266,7 @@ static void store_device_info(struct device *dev)
done:
str = g_key_file_to_data(key_file, &length, NULL);
- g_file_set_contents(ANDROID_STORAGEDIR"/devices", str, length, NULL);
+ g_file_set_contents(DEVICES_FILE, str, length, NULL);
g_free(str);
g_key_file_free(key_file);
@@ -521,8 +521,7 @@ static void store_link_key(const bdaddr_t *dst, const uint8_t *key,
key_file = g_key_file_new();
- if (!g_key_file_load_from_file(key_file, ANDROID_STORAGEDIR"/devices",
- 0, NULL))
+ if (!g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL))
return;
ba2str(dst, addr);
@@ -537,7 +536,7 @@ static void store_link_key(const bdaddr_t *dst, const uint8_t *key,
g_key_file_set_integer(key_file, addr, "LinkKeyPinLength", pin_length);
data = g_key_file_to_data(key_file, &length, NULL);
- g_file_set_contents(ANDROID_STORAGEDIR"/devices", data, length, NULL);
+ g_file_set_contents(DEVICES_FILE, data, length, NULL);
g_free(data);
g_key_file_free(key_file);
@@ -1726,8 +1725,7 @@ static void load_devices_info(bt_bluetooth_ready cb)
key_file = g_key_file_new();
- g_key_file_load_from_file(key_file, ANDROID_STORAGEDIR"/devices", 0,
- NULL);
+ g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL);
devs = g_key_file_get_groups(key_file, &len);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/5] android/bluetooth: Split devices list to devices and bonded_devices
From: Szymon Janc @ 2014-01-21 15:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390316497-18451-1-git-send-email-szymon.janc@tieto.com>
From: Szymon Janc <szymon.janc@gmail.com>
Bonded devices are permament until unbondedn. Non-bonded devices will
be held in (size limited) cache based on timestamp property so split
list to ease separation.
---
android/bluetooth.c | 47 +++++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 12 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 4849dab..8f08122 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -132,6 +132,8 @@ static const uint16_t uuid_list[] = {
static uint16_t option_index = MGMT_INDEX_NONE;
static struct mgmt *mgmt_if = NULL;
+
+static GSList *bonded_devices = NULL;
static GSList *devices = NULL;
/* This list contains addresses which are asked for records */
@@ -283,6 +285,10 @@ static struct device *find_device(const bdaddr_t *bdaddr)
{
GSList *l;
+ l = g_slist_find_custom(bonded_devices, bdaddr, device_match);
+ if (l)
+ return l->data;
+
l = g_slist_find_custom(devices, bdaddr, device_match);
if (l)
return l->data;
@@ -559,12 +565,30 @@ static void set_device_bond_state(const bdaddr_t *addr, uint8_t status,
if (!dev)
return;
- if (dev->bond_state != state) {
- dev->bond_state = state;
- send_bond_state_change(&dev->bdaddr, status, state);
+ if (dev->bond_state == state)
+ return;
- store_device_info(dev);
+ switch (state) {
+ case HAL_BOND_STATE_NONE:
+ if (dev->bond_state == HAL_BOND_STATE_BONDED) {
+ bonded_devices = g_slist_remove(bonded_devices, dev);
+ devices = g_slist_prepend(devices, dev);
+ }
+ break;
+ case HAL_BOND_STATE_BONDED:
+ devices = g_slist_remove(devices, dev);
+ bonded_devices = g_slist_prepend(bonded_devices, dev);
+ break;
+ case HAL_BOND_STATE_BONDING:
+ default:
+ break;
}
+
+ dev->bond_state = state;
+
+ store_device_info(dev);
+
+ send_bond_state_change(&dev->bdaddr, status, state);
}
static void send_device_property(const bdaddr_t *bdaddr, uint8_t type,
@@ -2128,18 +2152,15 @@ static uint8_t get_adapter_scan_mode(void)
static uint8_t get_adapter_bonded_devices(void)
{
- uint8_t buf[sizeof(bdaddr_t) * g_slist_length(devices)];
+ uint8_t buf[sizeof(bdaddr_t) * g_slist_length(bonded_devices)];
int i = 0;
GSList *l;
DBG("");
- for (l = devices; l; l = g_slist_next(l)) {
+ for (l = bonded_devices; l; l = g_slist_next(l)) {
struct device *dev = l->data;
- if (dev->bond_state != HAL_BOND_STATE_BONDED)
- continue;
-
bdaddr2android(&dev->bdaddr, buf + (i * sizeof(bdaddr_t)));
i++;
}
@@ -2691,11 +2712,10 @@ static void send_bonded_devices_props(void)
{
GSList *l;
- for (l = devices; l; l = g_slist_next(l)) {
+ for (l = bonded_devices; l; l = g_slist_next(l)) {
struct device *dev = l->data;
- if (dev->bond_state == HAL_BOND_STATE_BONDED)
- get_remote_device_props(dev);
+ get_remote_device_props(dev);
}
}
@@ -3093,6 +3113,9 @@ void bt_bluetooth_unregister(void)
{
DBG("");
+ g_slist_free_full(bonded_devices, (GDestroyNotify) free_device);
+ bonded_devices = NULL;
+
g_slist_free_full(devices, (GDestroyNotify) free_device);
devices = NULL;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 0/5] Remote device cache support
From: Szymon Janc @ 2014-01-21 15:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
Changes since RFC:
- set cache limit to 300
- update timestamp of cached device
- rebased to master
- other minor fixes
Szymon Janc (5):
android/bluetooth: Split devices list to devices and bonded_devices
android/bluetooth: Use defines for settings and devices files paths
android/bluetooth: Always store device info
android/bluetooth: Add support for caching remote device info
android/bluetooth: Add support for loading caches devices from storage
android/bluetooth.c | 202 ++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 149 insertions(+), 53 deletions(-)
--
1.8.3.2
^ permalink raw reply
* [PATCH BlueZ 2/2] android/ipc: Leave the connect callback to handle errors
From: Luiz Augusto von Dentz @ 2014-01-21 14:00 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1390312859-27349-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
It is not necessary to check connect errors since there is a watch
created for that.
---
android/ipc.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/android/ipc.c b/android/ipc.c
index 8098409..4f2428c 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -166,12 +166,7 @@ GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb,
memcpy(addr.sun_path, path, size);
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- error("IPC: failed to connect HAL socket %s: %d (%s)", &path[1],
- errno, strerror(errno));
- g_io_channel_unref(io);
- return NULL;
- }
+ connect(sk, (struct sockaddr *) &addr, sizeof(addr));
cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ 1/2] android/A2DP: Add retry logic to Audio IPC
From: Luiz Augusto von Dentz @ 2014-01-21 14:00 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
In case the audio HAL disconnects without cleaning up its endpoints treat
it as unclean disconnection and attempt to reconnect.
---
android/a2dp.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++---
android/audio-ipc.c | 13 +++++++---
android/audio-ipc.h | 2 +-
android/ipc.c | 9 +++----
android/ipc.h | 3 ++-
5 files changed, 83 insertions(+), 12 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 5569691..a996f79 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -51,6 +51,7 @@
#define L2CAP_PSM_AVDTP 0x19
#define SVC_HINT_CAPTURING 0x08
#define IDLE_TIMEOUT 1
+#define AUDIO_RETRY_TIMEOUT 2
static GIOChannel *server = NULL;
static GSList *devices = NULL;
@@ -58,6 +59,8 @@ static GSList *endpoints = NULL;
static GSList *setups = NULL;
static bdaddr_t adapter_addr;
static uint32_t record_id = 0;
+static guint audio_retry_id = 0;
+static bool audio_retrying = false;
struct a2dp_preset {
void *data;
@@ -1232,6 +1235,8 @@ static void bt_audio_open(const void *buf, uint16_t len)
DBG("");
+ audio_retrying = false;
+
if (cmd->presets == 0) {
error("No audio presets found");
goto failed;
@@ -1424,6 +1429,65 @@ static const struct ipc_handler audio_handlers[] = {
{ bt_stream_suspend, false, sizeof(struct audio_cmd_suspend_stream) },
};
+static void bt_audio_unregister(void)
+{
+ DBG("");
+
+ if (audio_retry_id > 0)
+ g_source_remove(audio_retry_id);
+
+ g_slist_free_full(setups, setup_free);
+ setups = NULL;
+
+ g_slist_free_full(endpoints, unregister_endpoint);
+ endpoints = NULL;
+
+ audio_ipc_cleanup();
+}
+
+static void bt_audio_register(GDestroyNotify destroy)
+{
+ DBG("");
+
+ audio_ipc_init(destroy);
+
+ audio_ipc_register(audio_handlers, G_N_ELEMENTS(audio_handlers));
+}
+
+static gboolean audio_retry_register(void *data)
+{
+ GDestroyNotify destroy = data;
+
+ audio_retry_id = 0;
+ audio_retrying = true;
+
+ bt_audio_register(destroy);
+
+ return FALSE;
+}
+
+static void audio_disconnected(void *data)
+{
+ bool restart;
+
+ DBG("");
+
+ if (audio_retrying)
+ goto retry;
+
+ restart = endpoints != NULL ? true : false;
+
+ bt_audio_unregister();
+
+ if (!restart)
+ return;
+
+retry:
+ audio_retry_id = g_timeout_add_seconds(AUDIO_RETRY_TIMEOUT,
+ audio_retry_register,
+ audio_disconnected);
+}
+
bool bt_a2dp_register(const bdaddr_t *addr)
{
GError *err = NULL;
@@ -1431,8 +1495,6 @@ bool bt_a2dp_register(const bdaddr_t *addr)
DBG("");
- audio_ipc_init();
-
bacpy(&adapter_addr, addr);
server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
@@ -1462,7 +1524,7 @@ bool bt_a2dp_register(const bdaddr_t *addr)
ipc_register(HAL_SERVICE_ID_A2DP, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
- audio_ipc_register(audio_handlers, G_N_ELEMENTS(audio_handlers));
+ bt_audio_register(audio_disconnected);
return true;
diff --git a/android/audio-ipc.c b/android/audio-ipc.c
index f4b55e3..ee444cf 100644
--- a/android/audio-ipc.c
+++ b/android/audio-ipc.c
@@ -46,6 +46,7 @@ static struct service_handler service;
static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
+ GDestroyNotify destroy = user_data;
char buf[BLUEZ_AUDIO_MTU];
ssize_t ret;
int fd, err;
@@ -74,33 +75,39 @@ static gboolean audio_watch_cb(GIOChannel *io, GIOCondition cond,
fail:
audio_ipc_cleanup();
+ if (destroy)
+ destroy(NULL);
return FALSE;
}
static gboolean audio_connect_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
+ GDestroyNotify destroy = user_data;
+
DBG("");
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
error("Audio IPC: socket connect failed");
audio_ipc_cleanup();
+ if (destroy)
+ destroy(NULL);
return FALSE;
}
cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch(audio_io, cond, audio_watch_cb, NULL);
+ g_io_add_watch(audio_io, cond, audio_watch_cb, user_data);
info("Audio IPC: successfully connected");
return FALSE;
}
-void audio_ipc_init(void)
+void audio_ipc_init(GDestroyNotify destroy)
{
audio_io = ipc_connect(BLUEZ_AUDIO_SK_PATH, sizeof(BLUEZ_AUDIO_SK_PATH),
- audio_connect_cb);
+ audio_connect_cb, destroy);
}
void audio_ipc_cleanup(void)
diff --git a/android/audio-ipc.h b/android/audio-ipc.h
index 0b5f216..ddff01e 100644
--- a/android/audio-ipc.h
+++ b/android/audio-ipc.h
@@ -21,7 +21,7 @@
*
*/
-void audio_ipc_init(void);
+void audio_ipc_init(GDestroyNotify destroy);
void audio_ipc_cleanup(void);
void audio_ipc_register(const struct ipc_handler *handlers, uint8_t size);
diff --git a/android/ipc.c b/android/ipc.c
index ed3ef3c..8098409 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -141,7 +141,8 @@ static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
-GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb)
+GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb,
+ void *user_data)
{
struct sockaddr_un addr;
GIOCondition cond;
@@ -174,7 +175,7 @@ GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb)
cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch(io, cond, connect_cb, NULL);
+ g_io_add_watch(io, cond, connect_cb, user_data);
return io;
}
@@ -215,7 +216,7 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
}
notif_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- notif_connect_cb);
+ notif_connect_cb, NULL);
if (!notif_io)
raise(SIGTERM);
@@ -225,7 +226,7 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
void ipc_init(void)
{
cmd_io = ipc_connect(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- cmd_connect_cb);
+ cmd_connect_cb, NULL);
if (!cmd_io)
raise(SIGTERM);
}
diff --git a/android/ipc.h b/android/ipc.h
index b1cc5c5..0ba9c67 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -34,7 +34,8 @@ struct service_handler {
void ipc_init(void);
void ipc_cleanup(void);
-GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb);
+GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb,
+ void *user_data);
int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
const void *buf, ssize_t len);
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ v2 18/18] bluetooth.conf: Add ObjectManager interface
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
---
src/bluetooth.conf | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 0495200..ad8891a 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -18,6 +18,7 @@
<allow send_interface="org.bluez.Profile1"/>
<allow send_interface="org.bluez.HeartRateWatcher1"/>
<allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+ <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
</policy>
<policy at_console="true">
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 17/18] gatttool: Add unix socket support for interactive mode
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch allows running GATT operations over unix socket on
interactive mode.
---
attrib/interactive.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 9826a4b..febebaa 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -84,7 +84,7 @@ static char *get_prompt(void)
if (opt_dst)
g_string_append_printf(prompt, "[%17s]", opt_dst);
else
- g_string_append_printf(prompt, "[%17s]", "");
+ g_string_append_printf(prompt, "[LOCAL]");
if (conn_state == STATE_CONNECTED)
g_string_append(prompt, COLOR_OFF);
@@ -405,15 +405,18 @@ static void cmd_connect(int argcp, char **argvp)
opt_dst_type = g_strdup("public");
}
- if (opt_dst == NULL) {
- error("Remote Bluetooth address required\n");
- return;
+ if (opt_dst) {
+
+ rl_printf("Attempting to connect to %s\n", opt_dst);
+ set_state(STATE_CONNECTING);
+ iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type,
+ opt_sec_level, opt_psm, opt_mtu,
+ connect_cb, &gerr);
+ } else {
+ rl_printf("Local connection\n");
+ iochannel = unix_connect(connect_cb, &gerr);
}
- rl_printf("Attempting to connect to %s\n", opt_dst);
- set_state(STATE_CONNECTING);
- iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
- opt_psm, opt_mtu, connect_cb, &gerr);
if (iochannel == NULL) {
set_state(STATE_DISCONNECTED);
error("%s\n", gerr->message);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 16/18] gatttool: Add unix socket connect
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds the initial support for GATT procedures over unix
socket transport on command line mode (one-shot command). Temporary
solution to allow local GATT procedures testing.
---
attrib/gatttool.c | 27 ++++++++++++++++++++-------
attrib/gatttool.h | 1 +
attrib/utils.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+), 7 deletions(-)
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index ebc8123..d701f7b 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -29,7 +29,6 @@
#include <errno.h>
#include <glib.h>
#include <stdlib.h>
-#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
@@ -53,6 +52,7 @@ static int opt_end = 0xffff;
static int opt_handle = -1;
static int opt_mtu = 0;
static int opt_psm = 0;
+static gboolean opt_local = FALSE;
static gboolean opt_primary = FALSE;
static gboolean opt_characteristics = FALSE;
static gboolean opt_char_read = FALSE;
@@ -511,6 +511,8 @@ static GOptionEntry options[] = {
"Specify local adapter interface", "hciX" },
{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
"Specify remote Bluetooth address", "MAC" },
+ { "local", 'L', 0, G_OPTION_ARG_NONE, &opt_local,
+ "Use unix socket transport (local communication)", NULL },
{ "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type,
"Set LE address type. Default: public", "[public | random]"},
{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
@@ -563,6 +565,11 @@ int main(int argc, char *argv[])
g_clear_error(&gerr);
}
+ if (opt_local) {
+ opt_src = NULL;
+ opt_dst = NULL;
+ }
+
if (opt_interactive) {
interactive(opt_src, opt_dst, opt_dst_type, opt_psm);
goto done;
@@ -588,14 +595,20 @@ int main(int argc, char *argv[])
goto done;
}
- if (opt_dst == NULL) {
- g_print("Remote Bluetooth address required\n");
- got_error = TRUE;
- goto done;
+ if (opt_local)
+ chan = unix_connect(connect_cb, &gerr);
+ else {
+ if (opt_dst == NULL) {
+ g_print("Remote Bluetooth address required\n");
+ got_error = TRUE;
+ goto done;
+ }
+
+ chan = gatt_connect(opt_src, opt_dst, opt_dst_type,
+ opt_sec_level, opt_psm, opt_mtu,
+ connect_cb, &gerr);
}
- chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
- opt_psm, opt_mtu, connect_cb, &gerr);
if (chan == NULL) {
g_printerr("%s\n", gerr->message);
g_clear_error(&gerr);
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 8f0913c..be8e236 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -27,4 +27,5 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
const char *dst_type, const char *sec_level,
int psm, int mtu, BtIOConnect connect_cb,
GError **gerr);
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr);
size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/utils.c b/attrib/utils.c
index 77bab27..de7b00a 100644
--- a/attrib/utils.c
+++ b/attrib/utils.c
@@ -25,7 +25,12 @@
#include "config.h"
#endif
+#include <errno.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
#include <glib.h>
#include <bluetooth/bluetooth.h>
@@ -101,6 +106,55 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
return chan;
}
+static gboolean unix_connect_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ BtIOConnect connect_cb = user_data;
+ GError *gerr;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ gerr = g_error_new_literal(G_IO_CHANNEL_ERROR,
+ G_IO_CHANNEL_ERROR_FAILED,
+ "connection attempt failed");
+ connect_cb(io, gerr, user_data);
+ g_clear_error(&gerr);
+ } else {
+ connect_cb(io, NULL, user_data);
+ }
+
+ return FALSE;
+}
+
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr)
+{
+ GIOChannel *io;
+ struct sockaddr_un uaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0/bluetooth/unix_att",
+ };
+ int sk;
+
+ sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC , 0);
+ if (sk < 0) {
+ g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+ G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+ return NULL;
+ }
+
+ if (connect(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+ g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+ G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+ close(sk);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ unix_connect_cb, connect_cb);
+
+ return io;
+}
+
size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
{
char tmp[3];
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 15/18] test: Add registering external service
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch extends gatt-service to call RegisterService() when org.bluez
service gets connected to the system bus.
---
test/gatt-service.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/test/gatt-service.c b/test/gatt-service.c
index e9d73c0..bad3ffe 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -114,6 +114,65 @@ static void create_services(DBusConnection *conn)
printf("Registered service: %s\n", service_path);
}
+static void register_external_service_reply(DBusPendingCall *call,
+ void *user_data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+
+ dbus_error_init(&derr);
+ dbus_set_error_from_message(&derr, reply);
+
+ if (dbus_error_is_set(&derr))
+ fprintf(stderr, "RegisterService: %s\n", derr.message);
+ else
+ printf("RegisterService: OK\n");
+
+ dbus_message_unref(reply);
+ dbus_error_free(&derr);
+}
+
+static void register_external_service(gpointer a, gpointer b)
+{
+ DBusConnection *conn = b;
+ const char *path = a;
+ DBusMessage *msg;
+ DBusPendingCall *call;
+ DBusMessageIter iter, dict;
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ SERVICE_MGR_IFACE, "RegisterService");
+ if (msg == NULL) {
+ fprintf(stderr, "Couldn't allocate D-Bus message\n");
+ return;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+ /* TODO: Add options dictionary */
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+ dbus_message_unref(msg);
+ return;
+ }
+
+ dbus_pending_call_set_notify(call, register_external_service_reply,
+ NULL, NULL);
+
+ dbus_pending_call_unref(call);
+}
+
+static void connect_handler(DBusConnection *conn, void *user_data)
+{
+ g_slist_foreach(services, register_external_service, conn);
+}
+
static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
@@ -159,6 +218,7 @@ static guint setup_signalfd(void)
int main(int argc, char *argv[])
{
+ GDBusClient *client;
DBusConnection *dbus_conn;
guint signal;
@@ -177,8 +237,14 @@ int main(int argc, char *argv[])
create_services(dbus_conn);
+ client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+ g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+
g_main_loop_run(main_loop);
+ g_dbus_client_unref(client);
+
g_source_remove(signal);
g_slist_free_full(services, g_free);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 14/18] test: Add signal handling for gatt-service
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch implements signal handling to run cleanup tasks before
exiting.
---
test/gatt-service.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/test/gatt-service.c b/test/gatt-service.c
index bf5cba9..e9d73c0 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -27,12 +27,14 @@
#include <errno.h>
#include <stdio.h>
+#include <sys/signalfd.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <gdbus/gdbus.h>
#define SERVICE_IFACE "org.bluez.GattService1"
+#define SERVICE_MGR_IFACE "org.bluez.GattServiceManager1"
/* Immediate Alert Service UUID */
#define IAS_UUID "00001802-0000-1000-8000-00805f9b34fb"
@@ -112,9 +114,57 @@ static void create_services(DBusConnection *conn)
printf("Registered service: %s\n", service_path);
}
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ g_main_loop_quit(main_loop);
+
+ return FALSE;
+}
+
+static guint setup_signalfd(void)
+{
+ GIOChannel *channel;
+ guint source;
+ sigset_t mask;
+ int fd;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+ perror("Failed to set signal mask");
+ return 0;
+ }
+
+ fd = signalfd(-1, &mask, 0);
+ if (fd < 0) {
+ perror("Failed to create signal descriptor");
+ return 0;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ signal_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
int main(int argc, char *argv[])
{
DBusConnection *dbus_conn;
+ guint signal;
+
+ signal = setup_signalfd();
+ if (signal == 0)
+ return -errno;
dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
@@ -129,6 +179,8 @@ int main(int argc, char *argv[])
g_main_loop_run(main_loop);
+ g_source_remove(signal);
+
g_slist_free_full(services, g_free);
dbus_connection_unref(dbus_conn);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 13/18] gitignore: Add test/gatt-service
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 67e9850..48fcf57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,6 +73,7 @@ tools/3dsp
tools/obexctl
test/sap_client.pyc
test/bluezutils.pyc
+test/gatt-service
unit/test-eir
unit/test-uuid
unit/test-crc
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 12/18] test: Add external service GATT skeleton
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds the initial code for an external GATT service example.
It implements the API defined at doc/gatt-api.txt
---
Makefile.tools | 5 ++
test/gatt-service.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 141 insertions(+)
create mode 100644 test/gatt-service.c
diff --git a/Makefile.tools b/Makefile.tools
index cd2d1ca..7beeeb6 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -367,3 +367,8 @@ test_scripts += test/sap_client.py test/bluezutils.py \
test/test-heartrate test/test-alert test/test-hfp \
test/test-cyclingspeed test/opp-client test/ftp-client \
test/pbap-client test/map-client
+
+noinst_PROGRAMS += test/gatt-service
+
+test_gatt_service_SOURCES = test/gatt-service.c
+test_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
diff --git a/test/gatt-service.c b/test/gatt-service.c
new file mode 100644
index 0000000..bf5cba9
--- /dev/null
+++ b/test/gatt-service.c
@@ -0,0 +1,136 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2013 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#define SERVICE_IFACE "org.bluez.GattService1"
+
+/* Immediate Alert Service UUID */
+#define IAS_UUID "00001802-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static GSList *services;
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *uuid = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+ return TRUE;
+}
+
+static gboolean service_get_includes(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ return TRUE;
+}
+
+static gboolean service_exist_includes(const GDBusPropertyTable *property,
+ void *user_data)
+{
+ return FALSE;
+}
+
+static DBusMessage *service_release(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ fprintf(stderr, "Terminating...\n");
+
+ g_main_loop_quit(main_loop);
+
+ return NULL;
+}
+
+static const GDBusMethodTable service_methods[] = {
+ { GDBUS_NOREPLY_METHOD("Release", NULL, NULL, service_release) },
+ { }
+};
+
+static const GDBusPropertyTable service_properties[] = {
+ { "UUID", "s", service_get_uuid },
+ { "Includes", "ao", service_get_includes, NULL,
+ service_exist_includes },
+ { }
+};
+
+static char *register_service(DBusConnection *conn, const char *uuid)
+{
+ static int id = 1;
+ char *path;
+
+ path = g_strdup_printf("/service%d", id++);
+ if (g_dbus_register_interface(conn, path, SERVICE_IFACE,
+ service_methods, NULL, service_properties,
+ g_strdup(uuid), g_free) == FALSE) {
+ fprintf(stderr, "Couldn't register service interface\n");
+ g_free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+static void create_services(DBusConnection *conn)
+{
+ char *service_path;
+
+ service_path = register_service(conn, IAS_UUID);
+
+ services = g_slist_prepend(services, service_path);
+
+ printf("Registered service: %s\n", service_path);
+}
+
+int main(int argc, char *argv[])
+{
+ DBusConnection *dbus_conn;
+
+ dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+ g_dbus_attach_object_manager(dbus_conn);
+
+ printf("gatt-service unique name: %s\n",
+ dbus_bus_get_unique_name(dbus_conn));
+
+ create_services(dbus_conn);
+
+ g_main_loop_run(main_loop);
+
+ g_slist_free_full(services, g_free);
+ dbus_connection_unref(dbus_conn);
+
+ return 0;
+}
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 11/18] gatt: Add Discover All Primary Services
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch adds ATT Read By Group request handling to the attribute
server. It is the primitive to implement Discover All Primary Services
procedure.
---
src/gatt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 1 deletion(-)
diff --git a/src/gatt.c b/src/gatt.c
index 33c3b6a..b204f9c 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -112,6 +112,130 @@ static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
}
+static void read_by_group_resp(GAttrib *attrib, uint16_t start,
+ uint16_t end, bt_uuid_t *pattern)
+{
+ uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ GList *list;
+ struct btd_attribute *last = NULL;
+ uint8_t *group_start, *group_end = NULL, *group_uuid;
+ unsigned int uuid_type = BT_UUID_UNSPEC;
+ size_t group_len = 0, plen = 0;
+
+ /*
+ * Read By Group Type Response format:
+ * Attribute Opcode: 1 byte
+ * Length: 1 byte (size of each group)
+ * Group: start | end | <<UUID>>
+ */
+
+ opdu[0] = ATT_OP_READ_BY_GROUP_RESP;
+ group_start = &opdu[2];
+ group_uuid = &opdu[6];
+
+ for (list = local_attribute_db; list;
+ last = list->data, list = g_list_next(list)) {
+ struct btd_attribute *attr = list->data;
+
+ if (attr->handle < start)
+ continue;
+
+ if (attr->handle > end)
+ break;
+
+ if (bt_uuid_cmp(&attr->type, pattern) != 0)
+ continue;
+
+ if (uuid_type != BT_UUID_UNSPEC &&
+ uuid_type != attr->type.type) {
+ /*
+ * Groups should contain the same length: UUID16 and
+ * UUID128 should be sent on different ATT PDUs
+ */
+ break;
+ }
+
+ /*
+ * MTU checking should not be shifted up, otherwise the
+ * handle of last end group will not be set properly.
+ */
+ if ((plen + group_len) >= ATT_DEFAULT_LE_MTU)
+ break;
+
+ /* Start Grouping handle */
+ att_put_u16(attr->handle, group_start);
+
+ /* Grouping <<UUID>>: Value is little endian */
+ memcpy(group_uuid, attr->value, attr->value_len);
+
+ if (last && group_end) {
+ att_put_u16(last->handle, group_end);
+ group_end += group_len;
+ plen += group_len;
+ }
+
+ /* Grouping initial settings: First grouping */
+ if (uuid_type == BT_UUID_UNSPEC) {
+ uuid_type = attr->type.type;
+
+ /* start(0xXXXX) | end(0xXXXX) | <<UUID>> */
+ group_len = 2 + 2 + bt_uuid_len(&attr->type);
+
+ /* 2: ATT Opcode and Length */
+ plen = 2 + group_len;
+
+ /* Size of each Attribute Data */
+ opdu[1] = group_len;
+
+ group_end = &opdu[4];
+ }
+
+ group_start += group_len;
+ group_uuid += group_len;
+ }
+
+ if (plen == 0) {
+ send_error(attrib, ATT_OP_READ_BY_GROUP_REQ, start,
+ ATT_ECODE_ATTR_NOT_FOUND);
+ return;
+ }
+
+ if (group_end)
+ att_put_u16(last->handle, group_end);
+
+ g_attrib_send(attrib, 0, opdu, plen, NULL, NULL, NULL);
+}
+
+static void read_by_group(GAttrib *attrib, const uint8_t *ipdu, size_t ilen)
+{
+ uint16_t decoded, start, end;
+ bt_uuid_t pattern;
+
+ decoded = dec_read_by_grp_req(ipdu, ilen, &start, &end, &pattern);
+ if (decoded == 0) {
+ send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_INVALID_PDU);
+ return;
+ }
+
+ if (start > end || start == 0x0000) {
+ send_error(attrib, ipdu[0], start, ATT_ECODE_INVALID_HANDLE);
+ return;
+ }
+
+ /*
+ * Restricting Read By Group Type to <<Primary>>.
+ * Removing the checking below requires changes to support
+ * dynamic values(defined in the upper layer) and additional
+ * security verification.
+ */
+ if (bt_uuid_cmp(&pattern, &primary_uuid) != 0) {
+ send_error(attrib, ipdu[0], start, ATT_ECODE_UNSUPP_GRP_TYPE);
+ return;
+ }
+
+ read_by_group_resp(attrib, start, end, &pattern);
+}
+
static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
gpointer user_data)
{
@@ -133,11 +257,14 @@ static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
case ATT_OP_READ_MULTI_REQ:
case ATT_OP_PREP_WRITE_REQ:
case ATT_OP_EXEC_WRITE_REQ:
- case ATT_OP_READ_BY_GROUP_REQ:
case ATT_OP_SIGNED_WRITE_CMD:
send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
break;
+ case ATT_OP_READ_BY_GROUP_REQ:
+ read_by_group(attrib, ipdu, ilen);
+ break;
+
/* Responses */
case ATT_OP_MTU_RESP:
case ATT_OP_FIND_INFO_RESP:
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 10/18] gatt: Register ATT command/event handler
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch registers the ATT channel handler to manage incoming ATT
commands and events.
---
src/gatt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/src/gatt.c b/src/gatt.c
index 4806205..33c3b6a 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -38,6 +38,7 @@
#include "log.h"
#include "lib/uuid.h"
#include "attrib/att.h"
+#include "attrib/gattrib.h"
#include "gatt-dbus.h"
#include "gatt.h"
@@ -100,12 +101,83 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
return attr;
}
+static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
+ uint8_t ecode)
+{
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ size_t plen;
+
+ plen = enc_error_resp(opcode, handle, ecode, pdu, sizeof(pdu));
+
+ g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
+}
+
+static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
+ gpointer user_data)
+{
+ GAttrib *attrib = user_data;
+
+ switch (ipdu[0]) {
+ case ATT_OP_ERROR:
+ break;
+
+ /* Requests */
+ case ATT_OP_WRITE_CMD:
+ case ATT_OP_WRITE_REQ:
+ case ATT_OP_READ_REQ:
+ case ATT_OP_READ_BY_TYPE_REQ:
+ case ATT_OP_MTU_REQ:
+ case ATT_OP_FIND_INFO_REQ:
+ case ATT_OP_FIND_BY_TYPE_REQ:
+ case ATT_OP_READ_BLOB_REQ:
+ case ATT_OP_READ_MULTI_REQ:
+ case ATT_OP_PREP_WRITE_REQ:
+ case ATT_OP_EXEC_WRITE_REQ:
+ case ATT_OP_READ_BY_GROUP_REQ:
+ case ATT_OP_SIGNED_WRITE_CMD:
+ send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
+ break;
+
+ /* Responses */
+ 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:
+ break;
+
+ /* Notification & Indication */
+ case ATT_OP_HANDLE_NOTIFY:
+ case ATT_OP_HANDLE_IND:
+ break;
+ }
+}
+
+static gboolean unix_hup_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ GAttrib *attrib = user_data;
+
+ g_attrib_unregister_all(attrib);
+ g_attrib_unref(attrib);
+
+ return FALSE;
+}
+
static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
struct sockaddr_un uaddr;
socklen_t len = sizeof(uaddr);
GIOChannel *nio;
+ GAttrib *attrib;
int err, nsk, sk;
sk = g_io_channel_unix_get_fd(io);
@@ -120,6 +192,14 @@ static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
nio = g_io_channel_unix_new(nsk);
g_io_channel_set_close_on_unref(nio, TRUE);
DBG("ATT UNIX socket: %p new client", nio);
+
+ attrib = g_attrib_new(nio);
+
+ g_attrib_register(attrib, GATTRIB_ALL_EVENTS, GATTRIB_ALL_HANDLES,
+ channel_handler_cb, attrib, NULL);
+
+ g_io_add_watch(nio, G_IO_HUP, unix_hup_cb, attrib);
+
g_io_channel_unref(nio);
return TRUE;
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 09/18] gattrib: Use default ATT LE MTU for non-standard sockets
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch forces the MTU to 23 (default ATT MTU) if the transport
is not Bluetooth. This is a development purpose change to allow
testing GATT procedures over non-Bluetooth sockets.
---
attrib/gattrib.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 609b908..fccb2bf 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -468,18 +468,18 @@ GAttrib *g_attrib_new(GIOChannel *io)
struct _GAttrib *attrib;
uint16_t imtu;
uint16_t att_mtu;
- uint16_t cid;
- GError *gerr = NULL;
+ uint16_t cid = 0;
g_io_channel_set_encoding(io, NULL, NULL);
g_io_channel_set_buffered(io, FALSE);
- bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu,
- BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s", gerr->message);
- g_error_free(gerr);
- return NULL;
+ if (bt_io_get(io, NULL, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid,
+ BT_IO_OPT_INVALID) == FALSE) {
+ /*
+ * Use default ATT LE MTU for non-standard transports. Used
+ * for testing purpose only. eg: Unix sockets
+ */
+ imtu = ATT_DEFAULT_LE_MTU;
}
attrib = g_try_new0(struct _GAttrib, 1);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 08/18] gatt: Add server unix socket
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds a server unix socket to handle local ATT traffic. This
is a development purpose feature used to allow local testing without
breaking the current attribute server.
---
src/gatt.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/src/gatt.c b/src/gatt.c
index ee045b1..4806205 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,6 +25,11 @@
#include <config.h>
#endif
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
#include <glib.h>
#include "adapter.h"
@@ -50,6 +55,7 @@ struct btd_attribute {
static GList *local_attribute_db;
static uint16_t next_handle = 0x0001;
+static guint unix_watch;
static int local_database_add(uint16_t handle, struct btd_attribute *attr)
{
@@ -94,11 +100,71 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
return attr;
}
+static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct sockaddr_un uaddr;
+ socklen_t len = sizeof(uaddr);
+ GIOChannel *nio;
+ int err, nsk, sk;
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ nsk = accept(sk, (struct sockaddr *) &uaddr, &len);
+ if (nsk < 0) {
+ err = errno;
+ error("ATT UNIX socket accept: %s(%d)", strerror(err), err);
+ return TRUE;
+ }
+
+ nio = g_io_channel_unix_new(nsk);
+ g_io_channel_set_close_on_unref(nio, TRUE);
+ DBG("ATT UNIX socket: %p new client", nio);
+ g_io_channel_unref(nio);
+
+ return TRUE;
+}
+
void gatt_init(void)
{
+ struct sockaddr_un uaddr = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0/bluetooth/unix_att",
+ };
+ GIOChannel *io;
+ int sk, err;
+
DBG("Starting GATT server");
gatt_dbus_manager_register();
+
+ sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC , 0);
+ if (sk < 0) {
+ err = errno;
+ error("ATT UNIX socket: %s(%d)", strerror(err), err);
+ return;
+ }
+
+ if (bind(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+ err = errno;
+ error("binding ATT UNIX socket: %s(%d)", strerror(err), err);
+ close(sk);
+ return;
+ }
+
+ if (listen(sk, 5) < 0) {
+ err = errno;
+ error("listen ATT UNIX socket: %s(%d)", strerror(err), err);
+ close(sk);
+ return;
+ }
+
+ io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(io, TRUE);
+ unix_watch = g_io_add_watch(io,
+ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ unix_accept_cb, NULL);
+ g_io_channel_unref(io);
}
void gatt_cleanup(void)
@@ -106,4 +172,5 @@ void gatt_cleanup(void)
DBG("Stopping GATT server");
gatt_dbus_manager_unregister();
+ g_source_remove(unix_watch);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 07/18] gatt: Add external services tracking
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
All primary services declarations provided by an external application
will be automatically inserted in the attribute database.
---
src/gatt-dbus.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index b4d32cd..2196dc7 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -39,15 +39,21 @@
#include "log.h"
#include "error.h"
+#include "gatt.h"
#include "gatt-dbus.h"
#define SERVICE_MGR_IFACE "org.bluez.GattServiceManager1"
+#define SERVICE_IFACE "org.bluez.GattService1"
+
+#define REGISTER_TIMER 1
struct external_app {
char *owner;
char *path;
GDBusClient *client;
+ GSList *proxies;
unsigned int watch;
+ guint register_timer;
};
static GSList *external_apps;
@@ -60,6 +66,36 @@ static int external_app_path_cmp(gconstpointer a, gconstpointer b)
return g_strcmp0(eapp->path, path);
}
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ struct external_app *eapp = user_data;
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ DBG("path %s iface %s", path, interface);
+
+ if (g_strcmp0(interface, SERVICE_IFACE) != 0)
+ return;
+
+ eapp->proxies = g_slist_append(eapp->proxies, proxy);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+ struct external_app *eapp = user_data;
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ DBG("path %s iface %s", path, interface);
+
+ eapp->proxies = g_slist_remove(eapp->proxies, proxy);
+}
+
+
static void external_app_watch_destroy(gpointer user_data)
{
struct external_app *eapp = user_data;
@@ -70,6 +106,9 @@ static void external_app_watch_destroy(gpointer user_data)
g_dbus_client_unref(eapp->client);
+ if (eapp->register_timer)
+ g_source_remove(eapp->register_timer);
+
g_free(eapp->owner);
g_free(eapp->path);
g_free(eapp);
@@ -99,9 +138,75 @@ static struct external_app *new_external_app(DBusConnection *conn,
eapp->client = client;
eapp->path = g_strdup(path);
+ g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+ NULL, eapp);
+
return eapp;
}
+static int register_external_service(GDBusProxy *proxy)
+{
+ DBusMessageIter iter;
+ const char *uuid;
+ bt_uuid_t btuuid;
+
+ if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+ return -EINVAL;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (bt_string_to_uuid(&btuuid, uuid) < 0)
+ return -EINVAL;
+
+ if (btd_gatt_add_service(&btuuid) == NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static gboolean finish_register(gpointer user_data)
+{
+ struct external_app *eapp = user_data;
+ GSList *list;
+
+ /*
+ * It is not possible to detect when the last proxy object
+ * was reported. "Proxy added" handler reports objects
+ * added on demand or returned by GetManagedObjects().
+ * This timer helps to register all the GATT declarations
+ * (services, characteristics and descriptors) after fetching
+ * all the D-Bus objects.
+ */
+
+ eapp->register_timer = 0;
+
+ for (list = eapp->proxies; list; list = g_slist_next(list)) {
+ const char *interface, *path;
+ GDBusProxy *proxy = list->data;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+ path = g_dbus_proxy_get_path(proxy);
+
+ if (g_strcmp0(SERVICE_IFACE, interface) != 0)
+ continue;
+
+ if (g_strcmp0(path, eapp->path) != 0)
+ continue;
+
+ if (register_external_service(proxy) < 0) {
+ DBG("Inconsistent external service: %s", path);
+ continue;
+ }
+
+ DBG("External service: %s", path);
+ }
+
+ return FALSE;
+}
+
static DBusMessage *register_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -109,6 +214,8 @@ static DBusMessage *register_service(DBusConnection *conn,
DBusMessageIter iter;
const char *path;
+ DBG("Registering GATT Service");
+
if (!dbus_message_iter_init(msg, &iter))
return btd_error_invalid_args(msg);
@@ -127,6 +234,8 @@ static DBusMessage *register_service(DBusConnection *conn,
external_apps = g_slist_prepend(external_apps, eapp);
DBG("New app %p: %s", eapp, path);
+ eapp->register_timer = g_timeout_add_seconds(REGISTER_TIMER,
+ finish_register, eapp);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 06/18] gatt: Add helper for creating GATT services
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Andre Guedes
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
From: Andre Guedes <andre.guedes@openbossa.org>
This patch adds the btd_gatt_add_service() helper which adds a
GATT Service declaration to the local attribute database.
---
lib/uuid.h | 5 +++++
src/gatt.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt.h | 10 ++++++++++
3 files changed, 77 insertions(+)
diff --git a/lib/uuid.h b/lib/uuid.h
index c24cee5..237145b 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -158,6 +158,11 @@ void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
+static inline int bt_uuid_len(const bt_uuid_t *uuid)
+{
+ return uuid->type / 8;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gatt.c b/src/gatt.c
index e8b691a..ee045b1 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -27,11 +27,73 @@
#include <glib.h>
+#include "adapter.h"
+#include "device.h"
+
#include "log.h"
+#include "lib/uuid.h"
+#include "attrib/att.h"
#include "gatt-dbus.h"
#include "gatt.h"
+/* Common GATT UUIDs */
+static const bt_uuid_t primary_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_PRIM_SVC_UUID };
+
+struct btd_attribute {
+ uint16_t handle;
+ bt_uuid_t type;
+ uint16_t value_len;
+ uint8_t value[0];
+};
+
+static GList *local_attribute_db;
+static uint16_t next_handle = 0x0001;
+
+static int local_database_add(uint16_t handle, struct btd_attribute *attr)
+{
+ attr->handle = handle;
+
+ local_attribute_db = g_list_append(local_attribute_db, attr);
+
+ return 0;
+}
+
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
+{
+ uint16_t len = bt_uuid_len(uuid);
+ struct btd_attribute *attr = g_malloc0(sizeof(struct btd_attribute) +
+ len);
+
+ /*
+ * Service DECLARATION
+ *
+ * TYPE ATTRIBUTE VALUE
+ * +-------+---------------------------------+
+ * |0x2800 | 0xYYYY... |
+ * | (1) | (2) |
+ * +------+----------------------------------+
+ * (1) - 2 octets: Primary/Secondary Service UUID
+ * (2) - 2 or 16 octets: Service UUID
+ */
+
+ attr->type = primary_uuid;
+
+ att_put_uuid(*uuid, attr->value);
+ attr->value_len = len;
+
+ if (local_database_add(next_handle, attr) < 0) {
+ g_free(attr);
+ return NULL;
+ }
+
+ /* TODO: missing overflow checking */
+ next_handle = next_handle + 1;
+
+ return attr;
+}
+
void gatt_init(void)
{
DBG("Starting GATT server");
diff --git a/src/gatt.h b/src/gatt.h
index 3a320b4..8dd1312 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -21,6 +21,16 @@
*
*/
+struct btd_attribute;
+
void gatt_init(void);
void gatt_cleanup(void);
+
+/* btd_gatt_add_service - Add a service declaration to local attribute database.
+ * @uuid: Service UUID.
+ *
+ * Returns a reference to service declaration attribute. In case of error,
+ * NULL is returned.
+ */
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 05/18] lib: Move GATT UUID to uuid.h
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
This patch moves GATT UUIDs definitions to a common header. uuid.h contains
helper functions to manipulate Bluetooth UUIDs and some common BR/EDR services
UUIDs.
---
attrib/gatt.h | 25 -------------------------
lib/uuid.h | 25 +++++++++++++++++++++++++
2 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 0f113e7..4fea3eb 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -24,31 +24,6 @@
#include <bluetooth/sdp.h>
-/* GATT Profile Attribute types */
-#define GATT_PRIM_SVC_UUID 0x2800
-#define GATT_SND_SVC_UUID 0x2801
-#define GATT_INCLUDE_UUID 0x2802
-#define GATT_CHARAC_UUID 0x2803
-
-/* GATT Characteristic Types */
-#define GATT_CHARAC_DEVICE_NAME 0x2A00
-#define GATT_CHARAC_APPEARANCE 0x2A01
-#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
-#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
-#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
-#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
-
-/* GATT Characteristic Descriptors */
-#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
-#define GATT_CHARAC_USER_DESC_UUID 0x2901
-#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
-#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
-#define GATT_CHARAC_FMT_UUID 0x2904
-#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
-#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
-#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
-#define GATT_REPORT_REFERENCE 0x2908
-
/* Client Characteristic Configuration bit field */
#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002
diff --git a/lib/uuid.h b/lib/uuid.h
index 95e5a9a..c24cee5 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -105,6 +105,31 @@ extern "C" {
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
+/* GATT UUIDs section */
+#define GATT_PRIM_SVC_UUID 0x2800
+#define GATT_SND_SVC_UUID 0x2801
+#define GATT_INCLUDE_UUID 0x2802
+#define GATT_CHARAC_UUID 0x2803
+
+/* GATT Characteristic Types */
+#define GATT_CHARAC_DEVICE_NAME 0x2A00
+#define GATT_CHARAC_APPEARANCE 0x2A01
+#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
+#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
+#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
+#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
+
+/* GATT Characteristic Descriptors */
+#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
+#define GATT_CHARAC_USER_DESC_UUID 0x2901
+#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
+#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
+#define GATT_CHARAC_FMT_UUID 0x2904
+#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
+#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
+#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
+#define GATT_REPORT_REFERENCE 0x2908
+
typedef struct {
enum {
BT_UUID_UNSPEC = 0,
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 04/18] gatt: Add registering external service
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch allows external applications register a given service on
Bluez. Applications must provide an object path and a dictionary of
options. Options dictionary will be used later to provide additional
service information.
---
src/gatt-dbus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 88 insertions(+), 1 deletion(-)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 95c47de..b4d32cd 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -26,22 +26,109 @@
#endif
#include <stdint.h>
+#include <errno.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <gdbus/gdbus.h>
+#include "adapter.h"
+#include "device.h"
+#include "lib/uuid.h"
#include "dbus-common.h"
#include "log.h"
+#include "error.h"
#include "gatt-dbus.h"
#define SERVICE_MGR_IFACE "org.bluez.GattServiceManager1"
+struct external_app {
+ char *owner;
+ char *path;
+ GDBusClient *client;
+ unsigned int watch;
+};
+
+static GSList *external_apps;
+
+static int external_app_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct external_app *eapp = a;
+ const char *path = b;
+
+ return g_strcmp0(eapp->path, path);
+}
+
+static void external_app_watch_destroy(gpointer user_data)
+{
+ struct external_app *eapp = user_data;
+
+ /* TODO: Remove from the database */
+
+ external_apps = g_slist_remove(external_apps, eapp);
+
+ g_dbus_client_unref(eapp->client);
+
+ g_free(eapp->owner);
+ g_free(eapp->path);
+ g_free(eapp);
+}
+
+static struct external_app *new_external_app(DBusConnection *conn,
+ const char *sender, const char *path)
+{
+ struct external_app *eapp;
+ GDBusClient *client;
+
+ client = g_dbus_client_new(conn, sender, "/");
+ if (client == NULL)
+ return NULL;
+
+ eapp = g_new0(struct external_app, 1);
+
+ eapp->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+ sender, NULL, eapp, external_app_watch_destroy);
+ if (eapp->watch == 0) {
+ g_dbus_client_unref(client);
+ g_free(eapp);
+ return NULL;
+ }
+
+ eapp->owner = g_strdup(sender);
+ eapp->client = client;
+ eapp->path = g_strdup(path);
+
+ return eapp;
+}
+
static DBusMessage *register_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
- return dbus_message_new_method_return(msg);
+ struct external_app *eapp;
+ DBusMessageIter iter;
+ const char *path;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return btd_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ if (g_slist_find_custom(external_apps, path, external_app_path_cmp))
+ return btd_error_already_exists(msg);
+
+ eapp = new_external_app(conn, dbus_message_get_sender(msg), path);
+ if (eapp == NULL)
+ return btd_error_failed(msg, "Not enough resources");
+
+ external_apps = g_slist_prepend(external_apps, eapp);
+
+ DBG("New app %p: %s", eapp, path);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static DBusMessage *unregister_service(DBusConnection *conn,
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ v2 03/18] gatt: Register Manager D-Bus Interface
From: Claudio Takahasi @ 2014-01-21 13:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390310814-19880-1-git-send-email-claudio.takahasi@openbossa.org>
From: Alvaro Silva <alvaro.silva@openbossa.org>
This patch registers the Service Manager D-Bus Interface. This
interface implements the methods to allow external application register
and unregister GATT Services.
---
Makefile.am | 1 +
src/gatt-dbus.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/gatt-dbus.h | 25 +++++++++++++++++++
src/gatt.c | 9 +++++++
4 files changed, 110 insertions(+)
create mode 100644 src/gatt-dbus.c
create mode 100644 src/gatt-dbus.h
diff --git a/Makefile.am b/Makefile.am
index 45c9f16..ed9083e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -146,6 +146,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src/adapter.h src/adapter.c \
src/profile.h src/profile.c \
src/service.h src/service.c \
+ src/gatt-dbus.h src/gatt-dbus.c \
src/gatt.h src/gatt.c \
src/device.h src/device.c src/attio.h \
src/dbus-common.c src/dbus-common.h \
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
new file mode 100644
index 0000000..95c47de
--- /dev/null
+++ b/src/gatt-dbus.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * 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 <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "dbus-common.h"
+#include "log.h"
+
+#include "gatt-dbus.h"
+
+#define SERVICE_MGR_IFACE "org.bluez.GattServiceManager1"
+
+static DBusMessage *register_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_service(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+ { GDBUS_EXPERIMENTAL_METHOD("RegisterService",
+ GDBUS_ARGS({ "service", "o"},
+ { "options", "a{sv}"}),
+ NULL, register_service) },
+ { GDBUS_EXPERIMENTAL_METHOD("UnregisterService",
+ GDBUS_ARGS({"service", "o"}),
+ NULL, unregister_service) },
+ { }
+};
+
+gboolean gatt_dbus_manager_register(void)
+{
+ return g_dbus_register_interface(btd_get_dbus_connection(),
+ "/org/bluez", SERVICE_MGR_IFACE,
+ methods, NULL, NULL, NULL, NULL);
+}
+
+void gatt_dbus_manager_unregister(void)
+{
+ g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
+ SERVICE_MGR_IFACE);
+}
diff --git a/src/gatt-dbus.h b/src/gatt-dbus.h
new file mode 100644
index 0000000..310cfa9
--- /dev/null
+++ b/src/gatt-dbus.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * 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
+ *
+ */
+
+gboolean gatt_dbus_manager_register(void);
+void gatt_dbus_manager_unregister(void);
diff --git a/src/gatt.c b/src/gatt.c
index 06619f0..e8b691a 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,14 +25,23 @@
#include <config.h>
#endif
+#include <glib.h>
+
+#include "log.h"
+
+#include "gatt-dbus.h"
#include "gatt.h"
void gatt_init(void)
{
+ DBG("Starting GATT server");
+ gatt_dbus_manager_register();
}
void gatt_cleanup(void)
{
+ DBG("Stopping GATT server");
+ gatt_dbus_manager_unregister();
}
--
1.8.3.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox