2010-11-11 23:39:26

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v3 1/4] Initial advertising data parsing implementation

From: Bruna Moreira <[email protected]>

Implement adapter_update_adv() function to parse advertising data
received by btd_event_adv() function. Add some fields for advertising
data in remote_device_info struct.
---
plugins/hciops.c | 9 +++------
src/adapter.c | 26 ++++++++++++++++++++++++++
src/adapter.h | 6 ++++++
src/event.c | 13 +++++++++++++
src/event.h | 1 +
5 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 418c824..6a88294 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -1011,7 +1011,7 @@ static inline void le_metaevent(int index, void *ptr)
{
evt_le_meta_event *meta = ptr;
le_advertising_info *info;
- uint8_t *rssi, num, i;
+ uint8_t num, i;

DBG("LE Meta Event");

@@ -1022,11 +1022,8 @@ static inline void le_metaevent(int index, void *ptr)
info = (le_advertising_info *) (meta->data + 1);

for (i = 0; i < num; i++) {
- /* RSSI is last byte of the advertising report event */
- rssi = info->data + info->length;
- btd_event_inquiry_result(&BDADDR(index), &info->bdaddr, 0,
- *rssi, NULL);
- info = (le_advertising_info *) (rssi + 1);
+ btd_event_advertising_report(&BDADDR(index), info);
+ info = (le_advertising_info *) (info->data + info->length + 1);
}
}

diff --git a/src/adapter.c b/src/adapter.c
index 1f39bcc..4ebf953 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3136,6 +3136,31 @@ static struct remote_dev_info *get_found_dev(struct btd_adapter *adapter,
return dev;
}

+void adapter_update_device_from_info(struct btd_adapter *adapter,
+ le_advertising_info *info)
+{
+ struct remote_dev_info *dev;
+ bdaddr_t bdaddr;
+ gboolean new_dev;
+ int8_t rssi;
+
+ rssi = *(info->data + info->length);
+ bdaddr = info->bdaddr;
+
+ dev = get_found_dev(adapter, &bdaddr, &new_dev);
+
+ if (new_dev) {
+ dev->le = TRUE;
+ dev->evt_type = info->evt_type;
+ } else if (dev->rssi == rssi)
+ return;
+
+ dev->rssi = rssi;
+
+ adapter->found_devices = g_slist_sort(adapter->found_devices,
+ (GCompareFunc) dev_rssi_cmp);
+}
+
void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
int8_t rssi, uint32_t class, const char *name,
const char *alias, gboolean legacy,
@@ -3153,6 +3178,7 @@ void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
if (alias)
dev->alias = g_strdup(alias);

+ dev->le = FALSE;
dev->class = class;
dev->legacy = legacy;
dev->name_status = name_status;
diff --git a/src/adapter.h b/src/adapter.h
index b0eedb6..e6d2fe6 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -69,6 +69,10 @@ struct remote_dev_info {
char *alias;
dbus_bool_t legacy;
name_status_t name_status;
+ gboolean le;
+ /* LE adv data */
+ uint8_t evt_type;
+ uint8_t bdaddr_type;
};

struct hci_dev {
@@ -118,6 +122,8 @@ int adapter_get_discover_type(struct btd_adapter *adapter);
gboolean adapter_is_ready(struct btd_adapter *adapter);
struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
struct remote_dev_info *match);
+void adapter_update_device_from_info(struct btd_adapter *adapter,
+ le_advertising_info *info);
void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
int8_t rssi, uint32_t class, const char *name,
const char *alias, gboolean legacy,
diff --git a/src/event.c b/src/event.c
index a057306..b6a851e 100644
--- a/src/event.c
+++ b/src/event.c
@@ -322,6 +322,19 @@ static char *extract_eir_name(uint8_t *data, uint8_t *type)
return NULL;
}

+void btd_event_advertising_report(bdaddr_t *local, le_advertising_info *info)
+{
+ struct btd_adapter *adapter;
+
+ adapter = manager_find_adapter(local);
+ if (adapter == NULL) {
+ error("No matching adapter found");
+ return;
+ }
+
+ adapter_update_device_from_info(adapter, info);
+}
+
void btd_event_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
int8_t rssi, uint8_t *data)
{
diff --git a/src/event.h b/src/event.h
index 4a7b9c9..66f3b56 100644
--- a/src/event.h
+++ b/src/event.h
@@ -23,6 +23,7 @@
*/

int btd_event_request_pin(bdaddr_t *sba, struct hci_conn_info *ci);
+void btd_event_advertising_report(bdaddr_t *local, le_advertising_info *info);
void btd_event_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, int8_t rssi, uint8_t *data);
void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy);
void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
--
1.7.3.2



2010-11-15 14:07:59

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v3 2/4] Advertising data: extract local name

Hi,

On Thu, Nov 11, 2010, Vinicius Costa Gomes wrote:
> @@ -3159,6 +3160,12 @@ void adapter_update_device_from_info(struct btd_adapter *adapter,
>
> adapter->found_devices = g_slist_sort(adapter->found_devices,
> (GCompareFunc) dev_rssi_cmp);
> +
> + if (info->length) {
> + char *tmp_name = bt_extract_eir_name(info->data, &type);
> + if (tmp_name)
> + dev->name = tmp_name;
> + }
> }

This looks like a potential memory leak to me. What if dev->name was
already set (e.g. by a previous event for the same device)?

Johan

2010-11-15 14:05:33

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v3 1/4] Initial advertising data parsing implementation

Hi,

On Thu, Nov 11, 2010, Vinicius Costa Gomes wrote:
> Implement adapter_update_adv() function to parse advertising data
> received by btd_event_adv() function. Add some fields for advertising
> data in remote_device_info struct.
> ---
> plugins/hciops.c | 9 +++------
> src/adapter.c | 26 ++++++++++++++++++++++++++
> src/adapter.h | 6 ++++++
> src/event.c | 13 +++++++++++++
> src/event.h | 1 +
> 5 files changed, 49 insertions(+), 6 deletions(-)

Pushed upstream. Thanks.

Johan

2010-11-11 23:39:29

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v3 4/4] Emit "DeviceFound" signal for LE devices

From: Bruna Moreira <[email protected]>

The adapter_emit_device_found() function was modified to emit
DeviceFound signal for LE devices as well.
---
src/adapter.c | 30 +++++++++++++++++++++++++-----
1 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 49ba5fc..92087f6 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3110,6 +3110,27 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
if (device)
paired = device_is_paired(device);

+ /* Extract UUIDs from extended inquiry response if any */
+ dev->services = get_eir_uuids(eir_data, eir_length, dev->services);
+ uuid_count = g_slist_length(dev->services);
+
+ if (dev->services)
+ uuids = strlist2array(dev->services);
+
+ if (dev->le) {
+ emit_device_found(adapter->path, paddr,
+ "Address", DBUS_TYPE_STRING, &paddr,
+ "RSSI", DBUS_TYPE_INT16, &rssi,
+ "Name", DBUS_TYPE_STRING, &dev->name,
+ "Paired", DBUS_TYPE_BOOLEAN, &paired,
+ "UUIDs", DBUS_TYPE_ARRAY, &uuids, uuid_count,
+ NULL);
+
+ g_strfreev(uuids);
+
+ return;
+ }
+
icon = class_to_icon(dev->class);

if (!dev->alias) {
@@ -3121,12 +3142,7 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
} else
alias = g_strdup(dev->alias);

- /* Extract UUIDs from extended inquiry response if any */
- dev->services = get_eir_uuids(eir_data, eir_length, dev->services);
- uuid_count = g_slist_length(dev->services);
-
if (dev->services) {
- uuids = strlist2array(dev->services);
g_slist_foreach(dev->services, (GFunc) g_free, NULL);
g_slist_free(dev->services);
dev->services = NULL;
@@ -3205,6 +3221,10 @@ void adapter_update_device_from_info(struct btd_adapter *adapter,
if (tmp_name)
dev->name = tmp_name;
}
+
+ /* FIXME: check if other information was changed before emitting the
+ * signal */
+ adapter_emit_device_found(adapter, dev, info->data, info->length);
}

void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
--
1.7.3.2


2010-11-11 23:39:28

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v3 3/4] Extract service UUIDs from advertising data

From: Bruna Moreira <[email protected]>

Make get_eir_uuids() return a GSList of strings, so it can be reused to
extract UUIDs from LE advertising data. The bt_strlist2array() helper
function was created to convert a GSList into a plain array of strings
(needed to send through D-Bus).
---
src/adapter.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-------------
src/adapter.h | 1 +
2 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 724ea74..49ba5fc 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -202,6 +202,8 @@ static void dev_info_free(struct remote_dev_info *dev)
{
g_free(dev->name);
g_free(dev->alias);
+ g_slist_foreach(dev->services, (GFunc) g_free, NULL);
+ g_slist_free(dev->services);
g_free(dev);
}

@@ -2962,11 +2964,27 @@ static void emit_device_found(const char *path, const char *address,
g_dbus_send_message(connection, signal);
}

-static char **get_eir_uuids(uint8_t *eir_data, size_t eir_length,
- size_t *uuid_count)
+static char **strlist2array(GSList *list)
+{
+ GSList *l;
+ unsigned int i, n;
+ char **array;
+
+ if (list == NULL)
+ return NULL;
+
+ n = g_slist_length(list);
+ array = g_new0(char *, n + 1);
+
+ for (l = list, i = 0; l; l = l->next, i++)
+ array[i] = g_strdup((const gchar *) l->data);
+
+ return array;
+}
+
+static GSList *get_eir_uuids(uint8_t *eir_data, size_t eir_length, GSList *list)
{
uint16_t len = 0;
- char **uuids;
size_t total;
size_t uuid16_count = 0;
size_t uuid32_count = 0;
@@ -2975,10 +2993,11 @@ static char **get_eir_uuids(uint8_t *eir_data, size_t eir_length,
uint8_t *uuid32;
uint8_t *uuid128;
uuid_t service;
+ char *uuid_str;
unsigned int i;

if (eir_data == NULL || eir_length == 0)
- return NULL;
+ return list;

while (len < eir_length - 1) {
uint8_t field_len = eir_data[0];
@@ -3011,15 +3030,12 @@ static char **get_eir_uuids(uint8_t *eir_data, size_t eir_length,

/* Bail out if got incorrect length */
if (len > eir_length)
- return NULL;
+ return list;

total = uuid16_count + uuid32_count + uuid128_count;
- *uuid_count = total;

if (!total)
- return NULL;
-
- uuids = g_new0(char *, total + 1);
+ return list;

/* Generate uuids in SDP format (EIR data is Little Endian) */
service.type = SDP_UUID16;
@@ -3028,7 +3044,12 @@ static char **get_eir_uuids(uint8_t *eir_data, size_t eir_length,

val16 = (val16 << 8) + uuid16[0];
service.value.uuid16 = val16;
- uuids[i] = bt_uuid2string(&service);
+ uuid_str = bt_uuid2string(&service);
+ if (g_slist_find_custom(list, uuid_str,
+ (GCompareFunc) strcmp) == NULL)
+ list = g_slist_append(list, uuid_str);
+ else
+ g_free(uuid_str);
uuid16 += 2;
}

@@ -3041,7 +3062,12 @@ static char **get_eir_uuids(uint8_t *eir_data, size_t eir_length,
val32 = (val32 << 8) + uuid32[k];

service.value.uuid32 = val32;
- uuids[i] = bt_uuid2string(&service);
+ uuid_str = bt_uuid2string(&service);
+ if (g_slist_find_custom(list, uuid_str,
+ (GCompareFunc) strcmp) == NULL)
+ list = g_slist_append(list, uuid_str);
+ else
+ g_free(uuid_str);
uuid32 += 4;
}

@@ -3052,11 +3078,16 @@ static char **get_eir_uuids(uint8_t *eir_data, size_t eir_length,
for (k = 0; k < 16; k++)
service.value.uuid128.data[k] = uuid128[16 - k - 1];

- uuids[i] = bt_uuid2string(&service);
+ uuid_str = bt_uuid2string(&service);
+ if (g_slist_find_custom(list, uuid_str,
+ (GCompareFunc) strcmp) == NULL)
+ list = g_slist_append(list, uuid_str);
+ else
+ g_free(uuid_str);
uuid128 += 16;
}

- return uuids;
+ return list;
}

void adapter_emit_device_found(struct btd_adapter *adapter,
@@ -3070,7 +3101,7 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
dbus_int16_t rssi = dev->rssi;
char *alias;
char **uuids = NULL;
- size_t uuid_count = 0;
+ size_t uuid_count;

ba2str(&dev->bdaddr, peer_addr);
ba2str(&adapter->bdaddr, local_addr);
@@ -3090,8 +3121,16 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
} else
alias = g_strdup(dev->alias);

- /* Extract UUIDs from extended inquiry response if any*/
- uuids = get_eir_uuids(eir_data, eir_length, &uuid_count);
+ /* Extract UUIDs from extended inquiry response if any */
+ dev->services = get_eir_uuids(eir_data, eir_length, dev->services);
+ uuid_count = g_slist_length(dev->services);
+
+ if (dev->services) {
+ uuids = strlist2array(dev->services);
+ g_slist_foreach(dev->services, (GFunc) g_free, NULL);
+ g_slist_free(dev->services);
+ dev->services = NULL;
+ }

emit_device_found(adapter->path, paddr,
"Address", DBUS_TYPE_STRING, &paddr,
diff --git a/src/adapter.h b/src/adapter.h
index e6d2fe6..25fd3c8 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -71,6 +71,7 @@ struct remote_dev_info {
name_status_t name_status;
gboolean le;
/* LE adv data */
+ GSList *services;
uint8_t evt_type;
uint8_t bdaddr_type;
};
--
1.7.3.2


2010-11-11 23:39:27

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v3 2/4] Advertising data: extract local name

From: Bruna Moreira <[email protected]>

Move extract_eir_name() to glib-helper.c file and rename function to
bt_extract_eir_name(). The local name is extracted from the advertising
data.
---
src/adapter.c | 7 +++++++
src/event.c | 23 +----------------------
src/glib-helper.c | 22 ++++++++++++++++++++++
src/glib-helper.h | 1 +
4 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 4ebf953..724ea74 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3143,6 +3143,7 @@ void adapter_update_device_from_info(struct btd_adapter *adapter,
bdaddr_t bdaddr;
gboolean new_dev;
int8_t rssi;
+ uint8_t type;

rssi = *(info->data + info->length);
bdaddr = info->bdaddr;
@@ -3159,6 +3160,12 @@ void adapter_update_device_from_info(struct btd_adapter *adapter,

adapter->found_devices = g_slist_sort(adapter->found_devices,
(GCompareFunc) dev_rssi_cmp);
+
+ if (info->length) {
+ char *tmp_name = bt_extract_eir_name(info->data, &type);
+ if (tmp_name)
+ dev->name = tmp_name;
+ }
}

void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
diff --git a/src/event.c b/src/event.c
index b6a851e..833b208 100644
--- a/src/event.c
+++ b/src/event.c
@@ -301,27 +301,6 @@ void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
device_simple_pairing_complete(device, status);
}

-static char *extract_eir_name(uint8_t *data, uint8_t *type)
-{
- if (!data || !type)
- return NULL;
-
- if (data[0] == 0)
- return NULL;
-
- *type = data[1];
-
- switch (*type) {
- case 0x08:
- case 0x09:
- if (!g_utf8_validate((char *) (data + 2), data[0] - 1, NULL))
- return strdup("");
- return strndup((char *) (data + 2), data[0] - 1);
- }
-
- return NULL;
-}
-
void btd_event_advertising_report(bdaddr_t *local, le_advertising_info *info)
{
struct btd_adapter *adapter;
@@ -410,7 +389,7 @@ void btd_event_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
} else
legacy = TRUE;

- tmp_name = extract_eir_name(data, &name_type);
+ tmp_name = bt_extract_eir_name(data, &name_type);
if (tmp_name) {
if (name_type == 0x09) {
write_device_name(local, peer, tmp_name);
diff --git a/src/glib-helper.c b/src/glib-helper.c
index 9d76626..33668d7 100644
--- a/src/glib-helper.c
+++ b/src/glib-helper.c
@@ -43,6 +43,7 @@
#include <glib.h>

#include "glib-helper.h"
+#include "sdpd.h"

/* Number of seconds to keep a sdp_session_t in the cache */
#define CACHE_TIMEOUT 2
@@ -576,3 +577,24 @@ GSList *bt_string2list(const gchar *str)

return l;
}
+
+char *bt_extract_eir_name(uint8_t *data, uint8_t *type)
+{
+ if (!data || !type)
+ return NULL;
+
+ if (data[0] == 0)
+ return NULL;
+
+ *type = data[1];
+
+ switch (*type) {
+ case EIR_NAME_SHORT:
+ case EIR_NAME_COMPLETE:
+ if (!g_utf8_validate((char *) (data + 2), data[0] - 1, NULL))
+ return strdup("");
+ return strndup((char *) (data + 2), data[0] - 1);
+ }
+
+ return NULL;
+}
diff --git a/src/glib-helper.h b/src/glib-helper.h
index e89c2c6..dfe4123 100644
--- a/src/glib-helper.h
+++ b/src/glib-helper.h
@@ -38,3 +38,4 @@ char *bt_name2string(const char *string);
int bt_string2uuid(uuid_t *uuid, const char *string);
gchar *bt_list2string(GSList *list);
GSList *bt_string2list(const gchar *str);
+char *bt_extract_eir_name(uint8_t *data, uint8_t *type);
--
1.7.3.2