Merge BlueZ 5.41 to master
Merge BlueZ 5.41 from gfiber-internal/upstream to master.
Change-Id: I6efb64b3c2ce89b4c9bdb8088acdccd53acd3c02
diff --git a/ChangeLog b/ChangeLog
index dab8141..920175e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+ver 5.41:
+ Fix issue with service state changes handling.
+ Fix issue with AVRCP and no available player.
+ Fix issue with handling discovery filters.
+ Fix issue with handling temporary addresses.
+ Fix issue with GATT MTU size and BR/EDR links.
+ Fix issue with OBEX and creating directories.
+
ver 5.40:
Fix issue with not storing GATT attributes.
Fix issue with optional GATT notifications.
diff --git a/Makefile.am b/Makefile.am
index 5510102..4ce642f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -80,7 +80,7 @@
lib_LTLIBRARIES += lib/libbluetooth.la
lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:12:18
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:13:18
lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
endif
diff --git a/client/main.c b/client/main.c
index c75b558..32341ad 100644
--- a/client/main.c
+++ b/client/main.c
@@ -50,7 +50,7 @@
#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
#define PROMPT_ON COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
-#define PROMPT_OFF "[bluetooth]# "
+#define PROMPT_OFF "Waiting to connect to bluetoothd..."
static GMainLoop *main_loop;
static DBusConnection *dbus_conn;
@@ -82,16 +82,56 @@
printf("Leaking proxy %p\n", data);
}
+static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ if (condition & G_IO_IN) {
+ rl_callback_read_char();
+ return TRUE;
+ }
+
+ if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ g_main_loop_quit(main_loop);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static guint setup_standard_input(void)
+{
+ GIOChannel *channel;
+ guint source;
+
+ channel = g_io_channel_unix_new(fileno(stdin));
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ input_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
static void connect_handler(DBusConnection *connection, void *user_data)
{
rl_set_prompt(PROMPT_ON);
printf("\r");
rl_on_new_line();
rl_redisplay();
+
+ if (!input)
+ input = setup_standard_input();
}
static void disconnect_handler(DBusConnection *connection, void *user_data)
{
+ if (input > 0) {
+ g_source_remove(input);
+ input = 0;
+ }
+
rl_set_prompt(PROMPT_OFF);
printf("\r");
rl_on_new_line();
@@ -932,6 +972,36 @@
dbus_message_iter_close_container(iter, &value);
}
+static void append_array_variant(DBusMessageIter *iter, int type, void *val,
+ int n_elements)
+{
+ DBusMessageIter variant, array;
+ char type_sig[2] = { type, '\0' };
+ char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ array_sig, &variant);
+
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+ type_sig, &array);
+
+ if (dbus_type_is_fixed(type) == TRUE) {
+ dbus_message_iter_append_fixed_array(&array, type, val,
+ n_elements);
+ } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+ const char ***str_array = val;
+ int i;
+
+ for (i = 0; i < n_elements; i++)
+ dbus_message_iter_append_basic(&array, type,
+ &((*str_array)[i]));
+ }
+
+ dbus_message_iter_close_container(&variant, &array);
+
+ dbus_message_iter_close_container(iter, &variant);
+}
+
static void dict_append_entry(DBusMessageIter *dict, const char *key,
int type, void *val)
{
@@ -954,13 +1024,37 @@
dbus_message_iter_close_container(dict, &entry);
}
+static void dict_append_basic_array(DBusMessageIter *dict, int key_type,
+ const void *key, int type, void *val,
+ int n_elements)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, key_type, key);
+
+ append_array_variant(&entry, type, val, n_elements);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
+ void *val, int n_elements)
+{
+ dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
+ n_elements);
+}
+
#define DISTANCE_VAL_INVALID 0x7FFF
struct set_discovery_filter_args {
char *transport;
dbus_uint16_t rssi;
dbus_int16_t pathloss;
- GSList *uuids;
+ char **uuids;
+ size_t uuids_len;
};
static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
@@ -974,37 +1068,8 @@
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
- if (args->uuids != NULL) {
- DBusMessageIter entry, value, arrayIter;
- char *uuids = "UUIDs";
- GSList *l;
-
- dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
- /* dict key */
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
- &uuids);
-
- dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
- "as", &value);
-
- dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, "s",
- &arrayIter);
-
- for (l = args->uuids; l != NULL; l = g_slist_next(l))
- /* list->data contains string representation of uuid */
- dbus_message_iter_append_basic(&arrayIter,
- DBUS_TYPE_STRING,
- &l->data);
-
- dbus_message_iter_close_container(&value, &arrayIter);
-
- /* close vararg*/
- dbus_message_iter_close_container(&entry, &value);
-
- /* close entry */
- dbus_message_iter_close_container(&dict, &entry);
- }
+ dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &args->uuids,
+ args->uuids_len);
if (args->pathloss != DISTANCE_VAL_INVALID)
dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
@@ -1037,7 +1102,8 @@
static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
-static GSList *filtered_scan_uuids;
+static char **filtered_scan_uuids;
+static size_t filtered_scan_uuids_len;
static char *filtered_scan_transport;
static void cmd_set_scan_filter_commit(void)
@@ -1049,6 +1115,7 @@
args.rssi = filtered_scan_rssi;
args.transport = filtered_scan_transport;
args.uuids = filtered_scan_uuids;
+ args.uuids_len = filtered_scan_uuids_len;
if (check_default_ctrl() == FALSE)
return;
@@ -1063,25 +1130,22 @@
static void cmd_set_scan_filter_uuids(const char *arg)
{
- char *uuid_str, *saveptr, *uuids, *uuidstmp;
-
- g_slist_free_full(filtered_scan_uuids, g_free);
+ g_strfreev(filtered_scan_uuids);
filtered_scan_uuids = NULL;
+ filtered_scan_uuids_len = 0;
if (!arg || !strlen(arg))
- return;
+ goto commit;
- uuids = g_strdup(arg);
- for (uuidstmp = uuids; ; uuidstmp = NULL) {
- uuid_str = strtok_r(uuidstmp, " \t", &saveptr);
- if (uuid_str == NULL)
- break;
- filtered_scan_uuids = g_slist_append(filtered_scan_uuids,
- strdup(uuid_str));
+ filtered_scan_uuids = g_strsplit(arg, " ", -1);
+ if (!filtered_scan_uuids) {
+ rl_printf("Failed to parse input\n");
+ return;
}
- g_free(uuids);
+ filtered_scan_uuids_len = g_strv_length(filtered_scan_uuids);
+commit:
cmd_set_scan_filter_commit();
}
@@ -1121,17 +1185,35 @@
cmd_set_scan_filter_commit();
}
+static void clear_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
static void cmd_set_scan_filter_clear(const char *arg)
{
/* set default values for all options */
filtered_scan_rssi = DISTANCE_VAL_INVALID;
filtered_scan_pathloss = DISTANCE_VAL_INVALID;
- g_slist_free_full(filtered_scan_uuids, g_free);
+ g_strfreev(filtered_scan_uuids);
filtered_scan_uuids = NULL;
+ filtered_scan_uuids_len = 0;
g_free(filtered_scan_transport);
filtered_scan_transport = NULL;
- cmd_set_scan_filter_commit();
+ if (g_dbus_proxy_method_call(default_ctrl, "SetDiscoveryFilter",
+ clear_discovery_filter_setup, set_discovery_filter_reply,
+ NULL, NULL) == FALSE) {
+ rl_printf("Failed to clear discovery filter\n");
+ }
}
static struct GDBusProxy *find_device(const char *arg)
@@ -1898,38 +1980,6 @@
free(input);
}
-static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
- gpointer user_data)
-{
- if (condition & G_IO_IN) {
- rl_callback_read_char();
- return TRUE;
- }
-
- if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- g_main_loop_quit(main_loop);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static guint setup_standard_input(void)
-{
- GIOChannel *channel;
- guint source;
-
- channel = g_io_channel_unix_new(fileno(stdin));
-
- source = g_io_add_watch(channel,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- input_handler, NULL);
-
- g_io_channel_unref(channel);
-
- return source;
-}
-
static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
@@ -2040,9 +2090,8 @@
static void client_ready(GDBusClient *client, void *user_data)
{
- guint *input = user_data;
-
- *input = setup_standard_input();
+ if (!input)
+ input = setup_standard_input();
}
int main(int argc, char *argv[])
@@ -2093,8 +2142,7 @@
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
property_changed, NULL);
- input = 0;
- g_dbus_client_set_ready_watch(client, client_ready, &input);
+ g_dbus_client_set_ready_watch(client, client_ready, NULL);
g_main_loop_run(main_loop);
diff --git a/configure.ac b/configure.ac
index 62c82ea..2f459cc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
-AC_INIT(bluez, 5.40)
+AC_INIT(bluez, 5.41)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
tar-pax no-dist-gzip dist-xz])
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 4dbf879..97462a3 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -80,7 +80,11 @@
When discovery filter is set, Device objects will be
created as new devices with matching criteria are
- discovered. PropertiesChanged signals will be emitted
+ discovered regardless of they are connectable or
+ discoverable which enables listening to
+ non-connectable and non-discoverable devices.
+
+ PropertiesChanged signals will be emitted
for already existing Device objects, with updated RSSI
value. If one or more discovery filters have been set,
the RSSI delta-threshold, that is imposed by
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 8393bbf..2bc2a88 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -26,7 +26,8 @@
Linux kernel v4.1 Version 1.9
Linux kernel v4.2 Version 1.10
Linux kernel v4.5 Version 1.11
-Linux kernel v4.6 Version 1.12 (not yet released)
+Linux kernel v4.6 Version 1.12
+Linux kernel v4.8 Version 1.13 (not yet released)
Version 1.1 introduces Set Device ID command.
@@ -75,6 +76,10 @@
Version 1.12 introduces a new limited privacy mode (value 0x02 passed to
the Set Privacy command).
+Version 1.13 introduces a new authentication failure reason code for the
+Device Disconnected event.
+
+
Example
=======
@@ -550,6 +555,7 @@
Invalid Parameters
Invalid Index
+
Set High Speed Command
======================
@@ -2454,6 +2460,8 @@
0x04 RS232
0x05 PCI
0x06 SDIO
+ 0x07 SPI
+ 0x08 I2C
Controllers marked as RAW only operation are currently not listed
by this command.
@@ -3061,6 +3069,7 @@
1 Connection timeout
2 Connection terminated by local host
3 Connection terminated by remote host
+ 4 Connection terminated due to authentication failure
Note that the local/remote distinction just determines which side
terminated the low-level connection, regardless of the
diff --git a/doc/supported-features.txt b/doc/supported-features.txt
index 33685d5..f04cf4a 100644
--- a/doc/supported-features.txt
+++ b/doc/supported-features.txt
@@ -14,7 +14,7 @@
GATT 4.2 Server, Client
SDAP 1.1 Server, Client
RFCOMM 1.1 Server, Client
-SPP 1.1 Server, Client
+SPP 1.2 Server, Client
PXP 1.0 Reporter, Monitor
HOGP 1.0 Host
diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 5612ff0..54e5fe4 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -13,7 +13,7 @@
test-sdp 133 SDP qualification test cases
test-uuid 30 UUID conversion handling
test-mgmt 9 Management interface handling
-test-crypto 4 Cryptographic toolbox helpers
+test-crypto 5 Cryptographic toolbox helpers
test-textfile 4 Old textfile storage format
test-ringbuf 3 Ring buffer functionality
test-queue 6 Queue handling functionality
@@ -39,7 +39,7 @@
Application Count Description
-------------------------------------------
-mgmt-tester 305 Kernel management interface testing
+mgmt-tester 307 Kernel management interface testing
l2cap-tester 33 Kernel L2CAP implementation testing
rfcomm-tester 9 Kernel RFCOMM implementation testing
bnep-tester 1 Kernel BNEP implementation testing
@@ -49,7 +49,7 @@
hci-tester 14 Controller hardware testing
userchan-tester 3 Kernel HCI User Channel testting
-----
- 382
+ 384
Android end-to-end testing
diff --git a/emulator/btdev.c b/emulator/btdev.c
index 38769d8..1e94fc3 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -3098,6 +3098,7 @@
}
cmd_status(btdev, BT_HCI_ERR_SUCCESS,
BT_HCI_CMD_LE_GENERATE_DHKEY);
+ dh_evt.status = BT_HCI_ERR_SUCCESS;
le_meta_event(btdev, BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE,
&dh_evt, sizeof(dh_evt));
break;
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 3638fe4..2bcdc31 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -2329,6 +2329,11 @@
&cmd, sizeof(cmd));
}
+bool bthost_bredr_capable(struct bthost *bthost)
+{
+ return lmp_bredr_capable(bthost);
+}
+
void bthost_request_auth(struct bthost *bthost, uint16_t handle)
{
struct btconn *conn;
diff --git a/emulator/bthost.h b/emulator/bthost.h
index 7110db8..553865a 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -108,6 +108,8 @@
void bthost_set_reject_user_confirm(struct bthost *bthost, bool reject);
bool bthost_get_reject_user_confirm(struct bthost *bthost);
+bool bthost_bredr_capable(struct bthost *bthost);
+
uint64_t bthost_conn_get_fixed_chan(struct bthost *bthost, uint16_t handle);
typedef void (*bthost_rfcomm_connect_cb) (uint16_t handle, uint16_t cid,
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 6a53499..ea1e3cf 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -243,7 +243,8 @@
}
create_req[0] = HCI_VENDOR_PKT;
- create_req[1] = HCI_BREDR;
+ create_req[1] = HCI_PRIMARY;
+
written = write(fd, create_req, sizeof(create_req));
if (written < 0) {
close(fd);
diff --git a/emulator/le.c b/emulator/le.c
index 82ae573..d7ee297 100644
--- a/emulator/le.c
+++ b/emulator/le.c
@@ -1881,7 +1881,7 @@
}
setup_cmd[0] = HCI_VENDOR_PKT;
- setup_cmd[1] = HCI_BREDR;
+ setup_cmd[1] = HCI_PRIMARY;
if (write(hci->vhci_fd, setup_cmd, sizeof(setup_cmd)) < 0) {
close(hci->vhci_fd);
diff --git a/emulator/smp.c b/emulator/smp.c
index e941141..40836cf 100644
--- a/emulator/smp.c
+++ b/emulator/smp.c
@@ -68,8 +68,6 @@
#define DIST_SIGN 0x04
#define DIST_LINK_KEY 0x08
-#define KEY_DIST (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN)
-
#define SC_NO_DIST (DIST_ENC_KEY | DIST_LINK_KEY)
#define MAX_IO_CAP 0x04
@@ -193,6 +191,14 @@
return method;
}
+static uint8_t key_dist(struct bthost *host)
+{
+ if (!bthost_bredr_capable(host))
+ return (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN);
+
+ return (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN | DIST_LINK_KEY);
+}
+
static void smp_send(struct smp_conn *conn, uint8_t smp_cmd, const void *data,
uint8_t len)
{
@@ -433,8 +439,8 @@
}
rsp.max_key_size = 0x10;
- rsp.init_key_dist = conn->preq[5] & KEY_DIST;
- rsp.resp_key_dist = conn->preq[6] & KEY_DIST;
+ rsp.init_key_dist = conn->preq[5] & key_dist(bthost);
+ rsp.resp_key_dist = conn->preq[6] & key_dist(bthost);
conn->prsp[0] = BT_L2CAP_SMP_PAIRING_RESPONSE;
memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
@@ -691,8 +697,8 @@
req.oob_data = 0x00;
req.auth_req = auth_req;
req.max_key_size = 0x10;
- req.init_key_dist = KEY_DIST;
- req.resp_key_dist = KEY_DIST;
+ req.init_key_dist = key_dist(conn->smp->bthost);
+ req.resp_key_dist = key_dist(conn->smp->bthost);
conn->preq[0] = BT_L2CAP_SMP_PAIRING_REQUEST;
memcpy(&conn->preq[1], &req, sizeof(req));
@@ -818,8 +824,8 @@
memset(&req, 0, sizeof(req));
req.max_key_size = 0x10;
- req.init_key_dist = KEY_DIST;
- req.resp_key_dist = KEY_DIST;
+ req.init_key_dist = key_dist(smp->bthost);
+ req.resp_key_dist = key_dist(smp->bthost);
smp_send(conn, BT_L2CAP_SMP_PAIRING_REQUEST, &req, sizeof(req));
}
diff --git a/emulator/vhci.c b/emulator/vhci.c
index 6bba4e2..8dec20a 100644
--- a/emulator/vhci.c
+++ b/emulator/vhci.c
@@ -105,15 +105,15 @@
switch (type) {
case VHCI_TYPE_BREDRLE:
btdev_type = BTDEV_TYPE_BREDRLE;
- ctrl_type = HCI_BREDR;
+ ctrl_type = HCI_PRIMARY;
break;
case VHCI_TYPE_BREDR:
btdev_type = BTDEV_TYPE_BREDR;
- ctrl_type = HCI_BREDR;
+ ctrl_type = HCI_PRIMARY;
break;
case VHCI_TYPE_LE:
btdev_type = BTDEV_TYPE_LE;
- ctrl_type = HCI_BREDR;
+ ctrl_type = HCI_PRIMARY;
break;
case VHCI_TYPE_AMP:
btdev_type = BTDEV_TYPE_AMP;
diff --git a/lib/bluetooth.c b/lib/bluetooth.c
index fd0b081..3726b50 100644
--- a/lib/bluetooth.c
+++ b/lib/bluetooth.c
@@ -360,7 +360,7 @@
case 48:
return "ST Microelectronics";
case 49:
- return "Synopsis";
+ return "Synopsys, Inc.";
case 50:
return "Red-M (Communications) Ltd";
case 51:
@@ -836,7 +836,7 @@
case 286:
return "Skoda Auto a.s.";
case 287:
- return "Volkswagon AG";
+ return "Volkswagen AG";
case 288:
return "Porsche AG";
case 289:
@@ -2059,6 +2059,90 @@
return "Sharp Corporation";
case 898:
return "Precision Outcomes Ltd";
+ case 899:
+ return "Kronos Incorporated";
+ case 900:
+ return "OCOSMOS Co., Ltd.";
+ case 901:
+ return "Embedded Electronic Solutions Ltd. dba e2Solutions";
+ case 902:
+ return "Aterica Inc.";
+ case 903:
+ return "BluStor PMC, Inc.";
+ case 904:
+ return "Kapsch TrafficCom AB";
+ case 905:
+ return "ActiveBlu Corporation";
+ case 906:
+ return "Kohler Mira Limited";
+ case 907:
+ return "Noke";
+ case 908:
+ return "Appion Inc.";
+ case 909:
+ return "Resmed Ltd";
+ case 910:
+ return "Crownstone B.V.";
+ case 911:
+ return "Xiaomi Inc.";
+ case 912:
+ return "INFOTECH s.r.o.";
+ case 913:
+ return "Thingsquare AB";
+ case 914:
+ return "T&D";
+ case 915:
+ return "LAVAZZA S.p.A.";
+ case 916:
+ return "Netclearance Systems, Inc.";
+ case 917:
+ return "SDATAWAY";
+ case 918:
+ return "BLOKS GmbH";
+ case 919:
+ return "LEGO System A/S";
+ case 920:
+ return "Thetatronics Ltd";
+ case 921:
+ return "Nikon Corporation";
+ case 922:
+ return "NeST";
+ case 923:
+ return "South Silicon Valley Microelectronics";
+ case 924:
+ return "ALE International";
+ case 925:
+ return "CareView Communications, Inc.";
+ case 926:
+ return "SchoolBoard Limited";
+ case 927:
+ return "Molex Corporation";
+ case 928:
+ return "IVT Wireless Limited";
+ case 929:
+ return "Alpine Labs LLC";
+ case 930:
+ return "Candura Instruments";
+ case 931:
+ return "SmartMovt Technology Co., Ltd";
+ case 932:
+ return "Token Zero Ltd";
+ case 933:
+ return "ACE CAD Enterprise Co., Ltd. (ACECAD)";
+ case 934:
+ return "Medela, Inc";
+ case 935:
+ return "AeroScout";
+ case 936:
+ return "Esrille Inc.";
+ case 937:
+ return "THINKERLY SRL";
+ case 938:
+ return "Exon Sp. z o.o.";
+ case 939:
+ return "Meizu Technology Co., Ltd.";
+ case 940:
+ return "Smablo LTD";
case 65535:
return "internal use";
default:
diff --git a/lib/hci.c b/lib/hci.c
index fda1aca..0c85875 100644
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -143,7 +143,7 @@
{
switch (bus) {
case HCI_VIRTUAL:
- return "VIRTUAL";
+ return "Virtual";
case HCI_USB:
return "USB";
case HCI_PCCARD:
@@ -161,7 +161,7 @@
case HCI_I2C:
return "I2C";
default:
- return "UNKNOWN";
+ return "Unknown";
}
}
@@ -173,12 +173,12 @@
char *hci_typetostr(int type)
{
switch (type) {
- case HCI_BREDR:
- return "BR/EDR";
+ case HCI_PRIMARY:
+ return "Primary";
case HCI_AMP:
return "AMP";
default:
- return "UNKNOWN";
+ return "Unknown";
}
}
diff --git a/lib/hci.h b/lib/hci.h
index f76e205..bdd0df0 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -59,8 +59,9 @@
#define HCI_I2C 8
/* HCI controller types */
-#define HCI_BREDR 0x00
+#define HCI_PRIMARY 0x00
#define HCI_AMP 0x01
+#define HCI_BREDR HCI_PRIMARY
/* HCI device flags */
enum {
diff --git a/monitor/analyze.c b/monitor/analyze.c
index 0f2d19a..4dc2891 100644
--- a/monitor/analyze.c
+++ b/monitor/analyze.c
@@ -29,6 +29,8 @@
#include <stdio.h>
#include <string.h>
+#include "lib/bluetooth.h"
+
#include "src/shared/util.h"
#include "src/shared/queue.h"
#include "src/shared/btsnoop.h"
@@ -45,6 +47,11 @@
unsigned long num_evt;
unsigned long num_acl;
unsigned long num_sco;
+ unsigned long vendor_diag;
+ unsigned long system_note;
+ unsigned long user_log;
+ unsigned long unknown;
+ uint16_t manufacturer;
};
static struct queue *dev_list;
@@ -67,13 +74,22 @@
}
printf("Found %s controller with index %u\n", str, dev->index);
- printf(" BD_ADDR %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ printf(" BD_ADDR %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
dev->bdaddr[5], dev->bdaddr[4], dev->bdaddr[3],
dev->bdaddr[2], dev->bdaddr[1], dev->bdaddr[0]);
+ if (dev->manufacturer != 0xffff)
+ printf(" (%s)", bt_compidtostr(dev->manufacturer));
+ printf("\n");
+
+
printf(" %lu commands\n", dev->num_cmd);
printf(" %lu events\n", dev->num_evt);
printf(" %lu ACL packets\n", dev->num_acl);
printf(" %lu SCO packets\n", dev->num_sco);
+ printf(" %lu vendor diagnostics\n", dev->vendor_diag);
+ printf(" %lu system notes\n", dev->system_note);
+ printf(" %lu user logs\n", dev->user_log);
+ printf(" %lu unknown opcodes\n", dev->unknown);
printf("\n");
free(dev);
@@ -84,12 +100,9 @@
struct hci_dev *dev;
dev = new0(struct hci_dev, 1);
- if (!dev) {
- fprintf(stderr, "Failed to allocate new device entry\n");
- return NULL;
- }
dev->index = index;
+ dev->manufacturer = 0xffff;
return dev;
}
@@ -111,8 +124,6 @@
fprintf(stderr, "Creating new device for unknown index\n");
dev = dev_alloc(index);
- if (!dev)
- return NULL;
queue_push_tail(dev_list, dev);
}
@@ -127,8 +138,6 @@
struct hci_dev *dev;
dev = dev_alloc(index);
- if (!dev)
- return;
dev->type = ni->type;
memcpy(dev->bdaddr, ni->bdaddr, 6);
@@ -251,6 +260,70 @@
dev->num_sco++;
}
+static void info_index(struct timeval *tv, uint16_t index,
+ const void *data, uint16_t size)
+{
+ const struct btsnoop_opcode_index_info *hdr = data;
+ struct hci_dev *dev;
+
+ data += sizeof(*hdr);
+ size -= sizeof(*hdr);
+
+ dev = dev_lookup(index);
+ if (!dev)
+ return;
+
+ dev->manufacturer = hdr->manufacturer;
+}
+
+static void vendor_diag(struct timeval *tv, uint16_t index,
+ const void *data, uint16_t size)
+{
+ struct hci_dev *dev;
+
+ dev = dev_lookup(index);
+ if (!dev)
+ return;
+
+ dev->vendor_diag++;
+}
+
+static void system_note(struct timeval *tv, uint16_t index,
+ const void *data, uint16_t size)
+{
+ struct hci_dev *dev;
+
+ dev = dev_lookup(index);
+ if (!dev)
+ return;
+
+ dev->system_note++;
+}
+
+static void user_log(struct timeval *tv, uint16_t index,
+ const void *data, uint16_t size)
+{
+ struct hci_dev *dev;
+
+ dev = dev_lookup(index);
+ if (!dev)
+ return;
+
+ dev->user_log++;
+}
+
+static void unknown_opcode(struct timeval *tv, uint16_t index,
+ const void *data, uint16_t size)
+{
+ struct hci_dev *dev;
+
+ dev = dev_lookup(index);
+ if (!dev)
+ return;
+
+ dev->unknown++;
+}
+
void analyze_trace(const char *path)
{
struct btsnoop *btsnoop_file;
@@ -274,10 +347,6 @@
}
dev_list = queue_new();
- if (!dev_list) {
- fprintf(stderr, "Failed to allocate device list\n");
- goto done;
- }
while (1) {
unsigned char buf[BTSNOOP_MAX_PACKET_SIZE];
@@ -312,9 +381,22 @@
case BTSNOOP_OPCODE_OPEN_INDEX:
case BTSNOOP_OPCODE_CLOSE_INDEX:
break;
+ case BTSNOOP_OPCODE_INDEX_INFO:
+ info_index(&tv, index, buf, pktlen);
+ break;
+ case BTSNOOP_OPCODE_VENDOR_DIAG:
+ vendor_diag(&tv, index, buf, pktlen);
+ break;
+ case BTSNOOP_OPCODE_SYSTEM_NOTE:
+ system_note(&tv, index, buf, pktlen);
+ break;
+ case BTSNOOP_OPCODE_USER_LOGGING:
+ user_log(&tv, index, buf, pktlen);
+ break;
default:
- fprintf(stderr, "Wrong opcode %u\n", opcode);
- goto done;
+ fprintf(stderr, "Unknown opcode %u\n", opcode);
+ unknown_opcode(&tv, index, buf, pktlen);
+ break;
}
num_packets++;
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index c1f2bc5..582c853 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -1999,6 +1999,7 @@
static void print_uuid(const char *label, const void *data, uint16_t size)
{
const char *str;
+ char uuidstr[36];
switch (size) {
case 2:
@@ -2010,12 +2011,12 @@
print_field("%s: %s (0x%8.8x)", label, str, get_le32(data));
break;
case 16:
- str = uuid128_to_str(data);
- print_field("%s: %s (%8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x)",
- label, str,
+ sprintf(uuidstr, "%8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x",
get_le32(data + 12), get_le16(data + 10),
get_le16(data + 8), get_le16(data + 6),
get_le32(data + 2), get_le16(data + 0));
+ str = uuidstr_to_str(uuidstr);
+ print_field("%s: %s (%s)", label, str, uuidstr);
break;
default:
packet_hexdump(data, size);
diff --git a/monitor/packet.c b/monitor/packet.c
index 32fbcf7..0947213 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -5542,7 +5542,7 @@
if (index_current < MAX_INDEX) {
switch (index_list[index_current].type) {
- case HCI_BREDR:
+ case HCI_PRIMARY:
print_lmp_version(rsp->lmp_ver, rsp->lmp_subver);
break;
case HCI_AMP:
diff --git a/monitor/uuid.c b/monitor/uuid.c
index 1ceaa6f..6660bc7 100644
--- a/monitor/uuid.c
+++ b/monitor/uuid.c
@@ -585,11 +585,6 @@
return "Unknown";
}
-const char *uuid128_to_str(const unsigned char *uuid)
-{
- return "Unknown";
-}
-
const char *uuidstr_to_str(const char *uuid)
{
uint32_t val;
diff --git a/monitor/uuid.h b/monitor/uuid.h
index f467f51..6ffc0ee 100644
--- a/monitor/uuid.h
+++ b/monitor/uuid.h
@@ -26,6 +26,4 @@
const char *uuid16_to_str(uint16_t uuid);
const char *uuid32_to_str(uint32_t uuid);
-const char *uuid128_to_str(const unsigned char *uuid);
-
const char *uuidstr_to_str(const char *uuid);
diff --git a/obexd/client/opp.c b/obexd/client/opp.c
index 3c2801a..92785f6 100644
--- a/obexd/client/opp.c
+++ b/obexd/client/opp.c
@@ -117,7 +117,8 @@
static DBusMessage *opp_exchange_business_cards(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
- return g_dbus_create_error(message, ERROR_INTERFACE ".Failed", NULL);
+ return g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+ "Not Implemented");
}
static const GDBusMethodTable opp_methods[] = {
diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c
index a906527..3ee18a6 100644
--- a/obexd/plugins/ftp.c
+++ b/obexd/plugins/ftp.c
@@ -278,6 +278,8 @@
DBG("Fullname: %s", fullname);
err = verify_path(fullname);
+ if (err == -ENOENT)
+ goto not_found;
if (err < 0)
goto done;
diff --git a/obexd/plugins/phonebook-dummy.c b/obexd/plugins/phonebook-dummy.c
index eeb078f..29ae889 100644
--- a/obexd/plugins/phonebook-dummy.c
+++ b/obexd/plugins/phonebook-dummy.c
@@ -520,7 +520,6 @@
struct dummy_data *dummy;
char *filename;
int fd;
- guint ret;
filename = g_build_filename(root_folder, folder, id, NULL);
@@ -538,13 +537,13 @@
dummy->apparams = params;
dummy->fd = fd;
- ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy,
+ dummy->id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy,
dummy_free);
if (err)
*err = 0;
- return GINT_TO_POINTER(ret);
+ return dummy;
}
void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
@@ -553,7 +552,7 @@
struct cache_query *query;
char *foldername;
DIR *dp;
- guint ret;
+ struct dummy_data *dummy;
foldername = g_build_filename(root_folder, name, NULL);
dp = opendir(foldername);
@@ -572,11 +571,13 @@
query->user_data = user_data;
query->dp = dp;
- ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache, query,
- query_free);
+ dummy = g_new0(struct dummy_data, 1);
+
+ dummy->id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache,
+ query, query_free);
if (err)
*err = 0;
- return GINT_TO_POINTER(ret);
+ return dummy;
}
diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
index 82de98b..4ec9cca 100644
--- a/profiles/audio/avdtp.c
+++ b/profiles/audio/avdtp.c
@@ -1397,6 +1397,7 @@
avdtp_send(session, session->in.transaction,
AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION,
&rej, sizeof(rej));
+ stream_free(stream);
return;
}
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 6c8ed81..c100149 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -3200,7 +3200,8 @@
session->controller->player = player;
service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
- control_set_player(service, media_player_get_path(player->user_data));
+ control_set_player(service, player ?
+ media_player_get_path(player->user_data) : NULL);
}
static struct avrcp_player *create_ct_player(struct avrcp *session,
@@ -3330,6 +3331,10 @@
struct avrcp_player *player = data;
GSList *l;
+ /* Don't remove reserved player */
+ if (!player->id)
+ return;
+
for (l = player->sessions; l; l = l->next) {
struct avrcp *session = l->data;
struct avrcp_data *controller = session->controller;
@@ -3393,6 +3398,10 @@
g_slist_free_full(removed, player_remove);
+ /* There should always be an active player */
+ if (!session->controller->player)
+ create_ct_player(session, 0);
+
return FALSE;
}
diff --git a/src/adapter.c b/src/adapter.c
index a81a144..3b21afa 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2187,9 +2187,7 @@
*transport = SCAN_TYPE_BREDR;
else if (!strcmp(transport_str, "le"))
*transport = SCAN_TYPE_LE;
- else if (!strcmp(transport_str, "auto"))
- *transport = SCAN_TYPE_DUAL;
- else
+ else if (strcmp(transport_str, "auto"))
return false;
return true;
@@ -2220,8 +2218,9 @@
* successful, sets *filter to proper value.
* Returns false on any error, and true on success.
*/
-static bool parse_discovery_filter_dict(struct discovery_filter **filter,
- DBusMessage *msg)
+static bool parse_discovery_filter_dict(struct btd_adapter *adapter,
+ struct discovery_filter **filter,
+ DBusMessage *msg)
{
DBusMessageIter iter, subiter, dictiter, variantiter;
bool is_empty = true;
@@ -2233,7 +2232,7 @@
(*filter)->uuids = NULL;
(*filter)->pathloss = DISTANCE_VAL_INVALID;
(*filter)->rssi = DISTANCE_VAL_INVALID;
- (*filter)->type = SCAN_TYPE_DUAL;
+ (*filter)->type = get_scan_type(adapter);
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
@@ -2308,7 +2307,7 @@
return btd_error_not_supported(msg);
/* parse parameters */
- if (!parse_discovery_filter_dict(&discovery_filter, msg))
+ if (!parse_discovery_filter_dict(adapter, &discovery_filter, msg))
return btd_error_invalid_args(msg);
is_discovering = get_discovery_client(adapter, sender, &client);
@@ -5451,7 +5450,7 @@
memset(&eir_data, 0, sizeof(eir_data));
eir_parse(&eir_data, data, data_len);
- if (bdaddr_type == BDADDR_BREDR)
+ if (bdaddr_type == BDADDR_BREDR || adapter->filtered_discovery)
discoverable = true;
else
discoverable = eir_data.flags & (EIR_LIM_DISC | EIR_GEN_DISC);
diff --git a/src/device.c b/src/device.c
index b1ff1bb..5198c6d 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2700,6 +2700,9 @@
char *str = NULL;
int len;
+ if (device_address_is_private(device))
+ return NULL;
+
snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
key_file = g_key_file_new();
@@ -5186,6 +5189,9 @@
if (device->temporary == temporary)
return;
+ if (device_address_is_private(device))
+ return;
+
DBG("temporary %d", temporary);
device->temporary = temporary;
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 0cbacca..7abb306 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -74,6 +74,17 @@
struct queue *chrcs;
};
+typedef bool (*async_dbus_op_complete_t)(void *data);
+
+struct async_dbus_op {
+ int ref_count;
+ unsigned int id;
+ struct queue *msgs;
+ void *data;
+ uint16_t offset;
+ async_dbus_op_complete_t complete;
+};
+
struct characteristic {
struct service *service;
struct gatt_db_attribute *attr;
@@ -85,8 +96,8 @@
bt_uuid_t uuid;
char *path;
- unsigned int read_id;
- unsigned int write_id;
+ struct async_dbus_op *read_op;
+ struct async_dbus_op *write_op;
struct queue *descs;
@@ -101,8 +112,8 @@
bt_uuid_t uuid;
char *path;
- unsigned int read_id;
- unsigned int write_id;
+ struct async_dbus_op *read_op;
+ struct async_dbus_op *write_op;
};
static bool uuid_cmp(const bt_uuid_t *uuid, uint16_t u16)
@@ -205,22 +216,11 @@
return 0;
}
-typedef bool (*async_dbus_op_complete_t)(void *data);
-
-struct async_dbus_op {
- int ref_count;
- DBusMessage *msg;
- void *data;
- uint16_t offset;
- async_dbus_op_complete_t complete;
-};
-
static void async_dbus_op_free(void *data)
{
struct async_dbus_op *op = data;
- if (op->msg)
- dbus_message_unref(op->msg);
+ queue_destroy(op->msgs, (void *)dbus_message_unref);
free(op);
}
@@ -296,27 +296,44 @@
GATT_DESCRIPTOR_IFACE, "Value");
}
+static void async_dbus_op_reply(struct async_dbus_op *op, int err,
+ const uint8_t *value, size_t length)
+{
+ const struct queue_entry *entry;
+ DBusMessage *reply;
+
+ op->id = 0;
+
+ for (entry = queue_get_entries(op->msgs); entry; entry = entry->next) {
+ DBusMessage *msg = entry->data;
+
+ if (err) {
+ reply = err > 0 ? create_gatt_dbus_error(msg, err) :
+ btd_error_failed(msg, strerror(err));
+ goto send_reply;
+ }
+
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ if (!reply) {
+ error("Failed to allocate D-Bus message reply");
+ return;
+ }
+
+ if (value)
+ message_append_byte_array(reply, value, length);
+
+send_reply:
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ }
+}
+
static void read_op_cb(struct gatt_db_attribute *attrib, int err,
const uint8_t *value, size_t length,
void *user_data)
{
struct async_dbus_op *op = user_data;
- DBusMessage *reply;
- if (err) {
- error("Failed to read attribute");
- return;
- }
-
- reply = g_dbus_create_reply(op->msg, DBUS_TYPE_INVALID);
- if (!reply) {
- error("Failed to allocate D-Bus message reply");
- return;
- }
-
- message_append_byte_array(reply, value, length);
-
- g_dbus_send_message(btd_get_dbus_connection(), reply);
+ async_dbus_op_reply(op, err, value, length);
}
static void desc_read_cb(bool success, uint8_t att_ecode,
@@ -325,8 +342,6 @@
{
struct async_dbus_op *op = user_data;
struct descriptor *desc = op->data;
- struct service *service = desc->chrc->service;
- DBusMessage *reply;
if (!success)
goto fail;
@@ -337,42 +352,24 @@
if (!gatt_db_attribute_write(desc->attr, op->offset, value, length, 0,
NULL, write_descriptor_cb, desc)) {
error("Failed to store attribute");
+ att_ecode = BT_ATT_ERROR_UNLIKELY;
goto fail;
}
- /*
- * If the value length is exactly MTU-1, then we may not have read the
- * entire value. Perform a long read to obtain the rest, otherwise,
- * we're done.
- */
- if (length == bt_gatt_client_get_mtu(service->client->gatt) - 1) {
- op->offset += length;
- desc->read_id = bt_gatt_client_read_long_value(
- service->client->gatt,
- desc->handle,
- op->offset,
- desc_read_cb,
- async_dbus_op_ref(op),
- async_dbus_op_unref);
- if (desc->read_id)
- return;
- }
-
/* Read the stored data from db */
if (!gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op)) {
error("Failed to read database");
+ att_ecode = BT_ATT_ERROR_UNLIKELY;
goto fail;
}
- desc->read_id = 0;
+ desc->read_op = NULL;
return;
fail:
- reply = create_gatt_dbus_error(op->msg, att_ecode);
- desc->read_id = 0;
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- return;
+ async_dbus_op_reply(op, att_ecode, NULL, 0);
+ desc->read_op = NULL;
}
static int parse_options(DBusMessageIter *iter, uint16_t *offset)
@@ -401,24 +398,45 @@
return -EINVAL;
dbus_message_iter_get_basic(&value, offset);
}
+
+ dbus_message_iter_next(&dict);
}
return 0;
}
-static unsigned int read_value(struct bt_gatt_client *gatt, uint16_t handle,
- bt_gatt_client_read_callback_t callback,
- struct async_dbus_op *op)
+static struct async_dbus_op *async_dbus_op_new(DBusMessage *msg, void *data)
{
- if (op->offset)
- return bt_gatt_client_read_long_value(gatt, handle, op->offset,
- callback,
- async_dbus_op_ref(op),
- async_dbus_op_unref);
- else
- return bt_gatt_client_read_value(gatt, handle, callback,
- async_dbus_op_ref(op),
- async_dbus_op_unref);
+ struct async_dbus_op *op;
+
+ op = new0(struct async_dbus_op, 1);
+ op->msgs = queue_new();
+ queue_push_tail(op->msgs, dbus_message_ref(msg));
+ op->data = data;
+
+ return op;
+}
+
+static struct async_dbus_op *read_value(struct bt_gatt_client *gatt,
+ DBusMessage *msg, uint16_t handle,
+ uint16_t offset,
+ bt_gatt_client_read_callback_t callback,
+ void *data)
+{
+ struct async_dbus_op *op;
+
+ op = async_dbus_op_new(msg, data);
+ op->offset = offset;
+
+ op->id = bt_gatt_client_read_long_value(gatt, handle, offset, callback,
+ async_dbus_op_ref(op),
+ async_dbus_op_unref);
+ if (op->id)
+ return op;
+
+ async_dbus_op_free(op);
+
+ return NULL;
}
static DBusMessage *descriptor_read_value(DBusConnection *conn,
@@ -427,63 +445,51 @@
struct descriptor *desc = user_data;
struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
DBusMessageIter iter;
- struct async_dbus_op *op;
uint16_t offset = 0;
if (!gatt)
return btd_error_failed(msg, "Not connected");
- if (desc->read_id)
- return btd_error_in_progress(msg);
-
dbus_message_iter_init(msg, &iter);
if (parse_options(&iter, &offset))
return btd_error_invalid_args(msg);
- op = new0(struct async_dbus_op, 1);
- op->msg = dbus_message_ref(msg);
- op->data = desc;
- op->offset = offset;
-
- desc->read_id = read_value(gatt, desc->handle, desc_read_cb, op);
- if (desc->read_id)
+ if (desc->read_op) {
+ if (desc->read_op->offset != offset)
+ return btd_error_in_progress(msg);
+ queue_push_tail(desc->read_op->msgs, dbus_message_ref(msg));
return NULL;
+ }
- async_dbus_op_free(op);
+ desc->read_op = read_value(gatt, msg, desc->handle, offset,
+ desc_read_cb, desc);
+ if (!desc->read_op)
+ return btd_error_failed(msg, "Failed to send read request");
- return btd_error_failed(msg, "Failed to send read request");
+ return NULL;
}
static void write_result_cb(bool success, bool reliable_error,
uint8_t att_ecode, void *user_data)
{
struct async_dbus_op *op = user_data;
- DBusMessage *reply;
+ int err = 0;
if (op->complete && !op->complete(op->data)) {
- reply = btd_error_failed(op->msg, "Operation failed");
+ err = -EFAULT;
goto done;
}
if (!success) {
if (reliable_error)
- reply = btd_error_failed(op->msg,
- "Reliable write failed");
+ err = -EFAULT;
else
- reply = create_gatt_dbus_error(op->msg, att_ecode);
-
- goto done;
- }
-
- reply = g_dbus_create_reply(op->msg, DBUS_TYPE_INVALID);
- if (!reply) {
- error("Failed to allocate D-Bus message reply");
- return;
+ err = att_ecode;
}
done:
- g_dbus_send_message(btd_get_dbus_connection(), reply);
+ async_dbus_op_reply(op, err, NULL, 0);
}
static void write_cb(bool success, uint8_t att_ecode, void *user_data)
@@ -491,7 +497,7 @@
write_result_cb(success, false, att_ecode, user_data);
}
-static unsigned int start_long_write(DBusMessage *msg, uint16_t handle,
+static struct async_dbus_op *start_long_write(DBusMessage *msg, uint16_t handle,
struct bt_gatt_client *gatt,
bool reliable, const uint8_t *value,
size_t value_len, uint16_t offset,
@@ -499,53 +505,52 @@
async_dbus_op_complete_t complete)
{
struct async_dbus_op *op;
- unsigned int id;
- op = new0(struct async_dbus_op, 1);
- op->msg = dbus_message_ref(msg);
- op->data = data;
+ op = async_dbus_op_new(msg, data);
op->complete = complete;
op->offset = offset;
- id = bt_gatt_client_write_long_value(gatt, reliable, handle, offset,
+ op->id = bt_gatt_client_write_long_value(gatt, reliable, handle, offset,
value, value_len,
write_result_cb, op,
async_dbus_op_free);
- if (!id)
+ if (!op->id) {
async_dbus_op_free(op);
+ return NULL;
+ }
- return id;
+ return op;
}
-static unsigned int start_write_request(DBusMessage *msg, uint16_t handle,
+static struct async_dbus_op *start_write_request(DBusMessage *msg,
+ uint16_t handle,
struct bt_gatt_client *gatt,
const uint8_t *value, size_t value_len,
void *data,
async_dbus_op_complete_t complete)
{
struct async_dbus_op *op;
- unsigned int id;
- op = new0(struct async_dbus_op, 1);
- op->msg = dbus_message_ref(msg);
- op->data = data;
+ op = async_dbus_op_new(msg, data);
op->complete = complete;
- id = bt_gatt_client_write_value(gatt, handle, value, value_len,
+ op->id = bt_gatt_client_write_value(gatt, handle, value, value_len,
write_cb, op,
async_dbus_op_free);
- if (!id)
+ if (!op->id) {
async_dbus_op_free(op);
+ return NULL;
+ }
- return id;
+ return op;
}
static bool desc_write_complete(void *data)
{
struct descriptor *desc = data;
- desc->write_id = 0;
+ desc->write_op = NULL;
/*
* The descriptor might have been unregistered during the read. Return
@@ -567,7 +572,7 @@
if (!gatt)
return btd_error_failed(msg, "Not connected");
- if (desc->write_id)
+ if (desc->write_op)
return btd_error_in_progress(msg);
dbus_message_iter_init(msg, &iter);
@@ -591,17 +596,17 @@
* write.
*/
if (value_len <= bt_gatt_client_get_mtu(gatt) - 3 && !offset)
- desc->write_id = start_write_request(msg, desc->handle,
+ desc->write_op = start_write_request(msg, desc->handle,
gatt, value,
value_len, desc,
desc_write_complete);
else
- desc->write_id = start_long_write(msg, desc->handle, gatt,
+ desc->write_op = start_long_write(msg, desc->handle, gatt,
false, value,
value_len, offset, desc,
desc_write_complete);
- if (!desc->write_id)
+ if (!desc->write_op)
return btd_error_failed(msg, "Failed to initiate write");
return NULL;
@@ -679,11 +684,11 @@
DBG("Removing GATT descriptor: %s", desc->path);
- if (desc->read_id)
- bt_gatt_client_cancel(gatt, desc->read_id);
+ if (desc->read_op)
+ bt_gatt_client_cancel(gatt, desc->read_op->id);
- if (desc->write_id)
- bt_gatt_client_cancel(gatt, desc->write_id);
+ if (desc->write_op)
+ bt_gatt_client_cancel(gatt, desc->write_op->id);
desc->chrc = NULL;
@@ -829,8 +834,6 @@
{
struct async_dbus_op *op = user_data;
struct characteristic *chrc = op->data;
- struct service *service = chrc->service;
- DBusMessage *reply;
if (!success)
goto fail;
@@ -841,41 +844,24 @@
if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
NULL, write_characteristic_cb, chrc)) {
error("Failed to store attribute");
+ att_ecode = BT_ATT_ERROR_UNLIKELY;
goto fail;
}
- /*
- * If the value length is exactly MTU-1, then we may not have read the
- * entire value. Perform a long read to obtain the rest, otherwise,
- * we're done.
- */
- if (length == bt_gatt_client_get_mtu(service->client->gatt) - 1) {
- op->offset += length;
- chrc->read_id = bt_gatt_client_read_long_value(
- service->client->gatt,
- chrc->value_handle,
- op->offset,
- chrc_read_cb,
- async_dbus_op_ref(op),
- async_dbus_op_unref);
- if (chrc->read_id)
- return;
- }
-
- chrc->read_id = 0;
-
/* Read the stored data from db */
if (!gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op)) {
error("Failed to read database");
+ att_ecode = BT_ATT_ERROR_UNLIKELY;
goto fail;
}
+ chrc->read_op = NULL;
+
return;
fail:
- reply = create_gatt_dbus_error(op->msg, att_ecode);
- chrc->read_id = 0;
- g_dbus_send_message(btd_get_dbus_connection(), reply);
+ async_dbus_op_reply(op, att_ecode, NULL, 0);
+ chrc->read_op = NULL;
}
static DBusMessage *characteristic_read_value(DBusConnection *conn,
@@ -884,39 +870,36 @@
struct characteristic *chrc = user_data;
struct bt_gatt_client *gatt = chrc->service->client->gatt;
DBusMessageIter iter;
- struct async_dbus_op *op;
uint16_t offset = 0;
if (!gatt)
return btd_error_failed(msg, "Not connected");
- if (chrc->read_id)
- return btd_error_in_progress(msg);
-
dbus_message_iter_init(msg, &iter);
if (parse_options(&iter, &offset))
return btd_error_invalid_args(msg);
- op = new0(struct async_dbus_op, 1);
- op->msg = dbus_message_ref(msg);
- op->data = chrc;
- op->offset = offset;
-
- chrc->read_id = read_value(gatt, chrc->value_handle, chrc_read_cb, op);
- if (chrc->read_id)
+ if (chrc->read_op) {
+ if (chrc->read_op->offset != offset)
+ return btd_error_in_progress(msg);
+ queue_push_tail(chrc->read_op->msgs, dbus_message_ref(msg));
return NULL;
+ }
- async_dbus_op_free(op);
+ chrc->read_op = read_value(gatt, msg, chrc->value_handle, offset,
+ chrc_read_cb, chrc);
+ if (!chrc->read_op)
+ return btd_error_failed(msg, "Failed to send read request");
- return btd_error_failed(msg, "Failed to send read request");
+ return NULL;
}
static bool chrc_write_complete(void *data)
{
struct characteristic *chrc = data;
- chrc->write_id = 0;
+ chrc->write_op = NULL;
/*
* The characteristic might have been unregistered during the read.
@@ -939,7 +922,7 @@
if (!gatt)
return btd_error_failed(msg, "Not connected");
- if (chrc->write_id)
+ if (chrc->write_op)
return btd_error_in_progress(msg);
dbus_message_iter_init(msg, &iter);
@@ -963,10 +946,10 @@
*/
if ((chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)) {
supported = true;
- chrc->write_id = start_long_write(msg, chrc->value_handle, gatt,
+ chrc->write_op = start_long_write(msg, chrc->value_handle, gatt,
true, value, value_len, offset,
chrc, chrc_write_complete);
- if (chrc->write_id)
+ if (chrc->write_op)
return NULL;
}
@@ -979,17 +962,17 @@
return btd_error_failed(msg, "No ATT transport");
if (value_len <= mtu - 3 && !offset)
- chrc->write_id = start_write_request(msg,
+ chrc->write_op = start_write_request(msg,
chrc->value_handle,
gatt, value, value_len,
chrc, chrc_write_complete);
else
- chrc->write_id = start_long_write(msg,
+ chrc->write_op = start_long_write(msg,
chrc->value_handle, gatt,
false, value, value_len, offset,
chrc, chrc_write_complete);
- if (chrc->write_id)
+ if (chrc->write_op)
return NULL;
}
@@ -1138,26 +1121,17 @@
write_characteristic_cb, chrc);
}
-static DBusMessage *create_notify_reply(struct async_dbus_op *op,
- bool success, uint8_t att_ecode)
+static void create_notify_reply(struct async_dbus_op *op, bool success,
+ uint8_t att_ecode)
{
- DBusMessage *reply = NULL;
-
- if (!op->msg)
- return NULL;
+ int err;
if (success)
- reply = g_dbus_create_reply(op->msg, DBUS_TYPE_INVALID);
- else if (att_ecode)
- reply = create_gatt_dbus_error(op->msg, att_ecode);
+ err = 0;
else
- reply = btd_error_failed(op->msg,
- "Characteristic not available");
+ err = att_ecode ? att_ecode : -ENOENT;
- if (!reply)
- error("Failed to construct D-Bus message reply");
-
- return reply;
+ async_dbus_op_reply(op, err, NULL, 0);
}
static void register_notify_cb(uint16_t att_ecode, void *user_data)
@@ -1165,16 +1139,15 @@
struct async_dbus_op *op = user_data;
struct notify_client *client = op->data;
struct characteristic *chrc = client->chrc;
- DBusMessage *reply;
if (att_ecode) {
queue_remove(chrc->notify_clients, client);
queue_remove(chrc->service->client->all_notify_clients, client);
notify_client_free(client);
- reply = create_notify_reply(op, false, att_ecode);
+ create_notify_reply(op, false, att_ecode);
- goto done;
+ return;
}
if (!chrc->notifying) {
@@ -1184,11 +1157,7 @@
"Notifying");
}
- reply = create_notify_reply(op, true, 0);
-
-done:
- if (reply)
- g_dbus_send_message(btd_get_dbus_connection(), reply);
+ create_notify_reply(op, true, 0);
}
static DBusMessage *characteristic_start_notify(DBusConnection *conn,
@@ -1238,9 +1207,7 @@
goto fail;
}
- op = new0(struct async_dbus_op, 1);
- op->data = client;
- op->msg = dbus_message_ref(msg);
+ op = async_dbus_op_new(msg, client);
client->notify_id = bt_gatt_client_register_notify(gatt,
chrc->value_handle,
@@ -1393,11 +1360,11 @@
DBG("Removing GATT characteristic: %s", chrc->path);
- if (chrc->read_id)
- bt_gatt_client_cancel(gatt, chrc->read_id);
+ if (chrc->read_op)
+ bt_gatt_client_cancel(gatt, chrc->read_op->id);
- if (chrc->write_id)
- bt_gatt_client_cancel(gatt, chrc->write_id);
+ if (chrc->write_op)
+ bt_gatt_client_cancel(gatt, chrc->write_op->id);
queue_remove_all(chrc->notify_clients, NULL, NULL, remove_client);
queue_remove_all(chrc->descs, NULL, NULL, unregister_descriptor);
diff --git a/src/gatt-database.c b/src/gatt-database.c
index e287b98..bf1925b 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -468,8 +468,6 @@
uint8_t dst_type;
bdaddr_t src, dst;
- DBG("New incoming LE ATT connection");
-
if (gerr) {
error("%s", gerr->message);
return;
@@ -485,6 +483,9 @@
return;
}
+ DBG("New incoming %s ATT connection", dst_type == BDADDR_BREDR ?
+ "BR/EDR" : "LE");
+
adapter = adapter_find(&src);
if (!adapter)
return;
@@ -1168,7 +1169,7 @@
} else if (!strcmp("secure-read", flag)) {
*props |= BT_GATT_CHRC_PROP_READ;
*ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
- *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_READ_SECURE;
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_SECURE;
} else if (!strcmp("secure-write", flag)) {
*props |= BT_GATT_CHRC_PROP_WRITE;
*ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
@@ -1210,9 +1211,9 @@
else if (!strcmp("encrypt-authenticated-write", flag))
*perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
else if (!strcmp("secure-read", flag))
- *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_SECURE;
else if (!strcmp("secure-write", flag))
- *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_SECURE;
else {
error("Invalid descriptor flag: %s", flag);
return false;
diff --git a/src/service.c b/src/service.c
index f7912f5..0da14ab 100644
--- a/src/service.c
+++ b/src/service.c
@@ -353,7 +353,8 @@
void btd_service_connecting_complete(struct btd_service *service, int err)
{
- if (service->state != BTD_SERVICE_STATE_CONNECTING)
+ if (service->state != BTD_SERVICE_STATE_DISCONNECTED &&
+ service->state != BTD_SERVICE_STATE_CONNECTING)
return;
if (err == 0)
diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index 4a9b67f..51922d1 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -37,6 +37,10 @@
#define BT_ATT_MAX_LE_MTU 517
#define BT_ATT_MAX_VALUE_LEN 512
+#define BT_ATT_LINK_BREDR 0x00
+#define BT_ATT_LINK_LE 0x01
+#define BT_ATT_LINK_LOCAL 0xff
+
/* ATT protocol opcodes */
#define BT_ATT_OP_ERROR_RSP 0x01
#define BT_ATT_OP_MTU_REQ 0x02
diff --git a/src/shared/att.c b/src/shared/att.c
index abcf3bb..f1e0f59 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -34,6 +34,7 @@
#include "src/shared/util.h"
#include "src/shared/timeout.h"
#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
#include "lib/uuid.h"
#include "src/shared/att.h"
#include "src/shared/crypto.h"
@@ -184,7 +185,7 @@
unsigned int id;
unsigned int timeout_id;
enum att_op_type type;
- uint16_t opcode;
+ uint8_t opcode;
void *pdu;
uint16_t len;
bt_att_response_func_t callback;
@@ -967,6 +968,18 @@
free(att);
}
+static uint16_t get_l2cap_mtu(int fd)
+{
+ socklen_t len;
+ struct l2cap_options l2o;
+
+ len = sizeof(l2o);
+ if (getsockopt(fd, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0)
+ return 0;
+
+ return l2o.omtu;
+}
+
struct bt_att *bt_att_new(int fd, bool ext_signed)
{
struct bt_att *att;
@@ -976,10 +989,6 @@
att = new0(struct bt_att, 1);
att->fd = fd;
- att->mtu = BT_ATT_DEFAULT_LE_MTU;
- att->buf = malloc(att->mtu);
- if (!att->buf)
- goto fail;
att->io = io_new(fd);
if (!att->io)
@@ -1005,6 +1014,18 @@
if (!att->io_on_l2cap)
att->io_sec_level = BT_ATT_SECURITY_LOW;
+ if (bt_att_get_link_type(att) == BT_ATT_LINK_BREDR)
+ att->mtu = get_l2cap_mtu(att->fd);
+ else
+ att->mtu = BT_ATT_DEFAULT_LE_MTU;
+
+ if (att->mtu < BT_ATT_DEFAULT_LE_MTU)
+ goto fail;
+
+ att->buf = malloc(att->mtu);
+ if (!att->buf)
+ goto fail;
+
return bt_att_ref(att);
fail:
@@ -1099,6 +1120,28 @@
return true;
}
+uint8_t bt_att_get_link_type(struct bt_att *att)
+{
+ struct sockaddr_l2 src;
+ socklen_t len;
+
+ if (!att)
+ return -EINVAL;
+
+ if (!att->io_on_l2cap)
+ return BT_ATT_LINK_LOCAL;
+
+ len = sizeof(src);
+ memset(&src, 0, len);
+ if (getsockname(att->fd, (void *)&src, &len) < 0)
+ return -errno;
+
+ if (src.l2_bdaddr_type == BDADDR_BREDR)
+ return BT_ATT_LINK_BREDR;
+
+ return BT_ATT_LINK_LE;
+}
+
bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
void *user_data,
bt_att_destroy_func_t destroy)
diff --git a/src/shared/att.h b/src/shared/att.h
index 2a7f87e..7bffee7 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -53,6 +53,7 @@
uint16_t bt_att_get_mtu(struct bt_att *att);
bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu);
+uint8_t bt_att_get_link_type(struct bt_att *att);
bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
void *user_data,
diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index aa66dac..6de5514 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -568,8 +568,8 @@
return bt_crypto_e(crypto, k, res, res);
}
-static bool aes_cmac(struct bt_crypto *crypto, uint8_t key[16], uint8_t *msg,
- size_t msg_len, uint8_t res[16])
+static bool aes_cmac(struct bt_crypto *crypto, const uint8_t key[16],
+ const uint8_t *msg, size_t msg_len, uint8_t res[16])
{
uint8_t key_msb[16], out[16], msg_msb[CMAC_MSG_MAX];
ssize_t len;
@@ -679,3 +679,12 @@
return true;
}
+
+bool bt_crypto_h6(struct bt_crypto *crypto, const uint8_t w[16],
+ const uint8_t keyid[4], uint8_t res[16])
+{
+ if (!aes_cmac(crypto, w, keyid, 4, res))
+ return false;
+
+ return true;
+}
diff --git a/src/shared/crypto.h b/src/shared/crypto.h
index 9ba5803..84d4992 100644
--- a/src/shared/crypto.h
+++ b/src/shared/crypto.h
@@ -56,6 +56,8 @@
uint8_t a1[7], uint8_t a2[7], uint8_t res[16]);
bool bt_crypto_g2(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32],
uint8_t x[16], uint8_t y[16], uint32_t *val);
+bool bt_crypto_h6(struct bt_crypto *crypto, const uint8_t w[16],
+ const uint8_t keyid[4], uint8_t res[16]);
bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
const uint8_t *m, uint16_t m_len,
uint32_t sign_cnt, uint8_t signature[12]);
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index adabfe3..8fd8a45 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -1622,14 +1622,25 @@
if (!op)
return false;
+ /*
+ * BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] page 546:
+ *
+ * 4.3.1 Exchange MTU
+ *
+ * This sub-procedure shall not be used on a BR/EDR physical link since
+ * the MTU size is negotiated using L2CAP channel configuration
+ * procedures.
+ */
+ if (bt_att_get_link_type(client->att) == BT_ATT_LINK_BREDR)
+ goto discover;
+
/* Check if MTU needs to be send */
mtu = MAX(BT_ATT_DEFAULT_LE_MTU, mtu);
if (mtu == BT_ATT_DEFAULT_LE_MTU)
goto discover;
/* Configure the MTU */
- client->mtu_req_id = bt_gatt_exchange_mtu(client->att,
- MAX(BT_ATT_DEFAULT_LE_MTU, mtu),
+ client->mtu_req_id = bt_gatt_exchange_mtu(client->att, mtu,
exchange_mtu_cb,
discovery_op_ref(op),
discovery_op_unref);
diff --git a/test/example-gatt-server b/test/example-gatt-server
index 71aeb1b..84905f3 100755
--- a/test/example-gatt-server
+++ b/test/example-gatt-server
@@ -117,7 +117,7 @@
if interface != GATT_SERVICE_IFACE:
raise InvalidArgsException()
- return self.get_properties[GATT_SERVICE_IFACE]
+ return self.get_properties()[GATT_SERVICE_IFACE]
class Characteristic(dbus.service.Object):
@@ -164,7 +164,7 @@
if interface != GATT_CHRC_IFACE:
raise InvalidArgsException()
- return self.get_properties[GATT_CHRC_IFACE]
+ return self.get_properties()[GATT_CHRC_IFACE]
@dbus.service.method(GATT_CHRC_IFACE,
in_signature='a{sv}',
@@ -222,7 +222,7 @@
if interface != GATT_DESC_IFACE:
raise InvalidArgsException()
- return self.get_properties[GATT_CHRC_IFACE]
+ return self.get_properties()[GATT_CHRC_IFACE]
@dbus.service.method(GATT_DESC_IFACE,
in_signature='a{sv}',
diff --git a/test/simple-endpoint b/test/simple-endpoint
index 0164cff..78fb5fd 100755
--- a/test/simple-endpoint
+++ b/test/simple-endpoint
@@ -66,9 +66,9 @@
mainloop.quit()
@dbus.service.method("org.bluez.MediaEndpoint1",
- in_signature="", out_signature="")
- def ClearConfiguration(self):
- print("ClearConfiguration")
+ in_signature="o", out_signature="")
+ def ClearConfiguration(self, transport):
+ print("ClearConfiguration (%s)" % (transport))
@dbus.service.method("org.bluez.MediaEndpoint1",
in_signature="oay", out_signature="")
diff --git a/tools/btinfo.c b/tools/btinfo.c
index fd11ac4..8e36577 100644
--- a/tools/btinfo.c
+++ b/tools/btinfo.c
@@ -79,7 +79,7 @@
#define HCI_UP (1 << 0)
-#define HCI_BREDR 0x00
+#define HCI_PRIMARY 0x00
#define HCI_AMP 0x01
static struct hci_dev_info hci_info;
@@ -128,7 +128,7 @@
printf("HCI revision: %u\n", le16_to_cpu(rsp->hci_rev));
switch (hci_type) {
- case HCI_BREDR:
+ case HCI_PRIMARY:
printf("LMP version: %u\n", rsp->lmp_ver);
printf("LMP subversion: %u\n", le16_to_cpu(rsp->lmp_subver));
break;
diff --git a/tools/btproxy.c b/tools/btproxy.c
index 43de037..4bb7fef 100644
--- a/tools/btproxy.c
+++ b/tools/btproxy.c
@@ -49,7 +49,7 @@
#include "src/shared/ecc.h"
#include "monitor/bt.h"
-#define HCI_BREDR 0x00
+#define HCI_PRIMARY 0x00
#define HCI_AMP 0x01
#define BTPROTO_HCI 1
@@ -758,7 +758,7 @@
const char *unix_path = NULL;
unsigned short tcp_port = 0xb1ee; /* 45550 */
bool use_redirect = false;
- uint8_t type = HCI_BREDR;
+ uint8_t type = HCI_PRIMARY;
const char *str;
sigset_t mask;
diff --git a/tools/cltest.c b/tools/cltest.c
index 95fa7b6..44a17a8 100644
--- a/tools/cltest.c
+++ b/tools/cltest.c
@@ -228,7 +228,7 @@
if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0)
continue;
- if (((di.type & 0x30) >> 4) != HCI_BREDR)
+ if (((di.type & 0x30) >> 4) != HCI_PRIMARY)
continue;
if (!bacmp(&bdaddr_src, BDADDR_ANY)) {
diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index 0c78c4d..6bd5576 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -407,6 +407,8 @@
dbus_message_iter_get_basic(&value, device);
printf("Device: %s\n", *device);
}
+
+ dbus_message_iter_next(&dict);
}
return 0;
@@ -513,10 +515,6 @@
dbus_message_iter_init_append(reply, &iter);
- if (parse_options(&iter, &device))
- return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
- "Invalid arguments");
-
desc_read(desc, &iter);
return reply;
diff --git a/tools/hciconfig.c b/tools/hciconfig.c
index 93bb8ab..a609008 100644
--- a/tools/hciconfig.c
+++ b/tools/hciconfig.c
@@ -1151,7 +1151,7 @@
}
hciver = hci_vertostr(ver.hci_ver);
- if (((di.type & 0x30) >> 4) == HCI_BREDR)
+ if (((di.type & 0x30) >> 4) == HCI_PRIMARY)
lmpver = lmp_vertostr(ver.lmp_ver);
else
lmpver = pal_vertostr(ver.lmp_ver);
@@ -1161,7 +1161,7 @@
"\t%s Version: %s (0x%x) Subversion: 0x%x\n"
"\tManufacturer: %s (%d)\n",
hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev,
- (((di.type & 0x30) >> 4) == HCI_BREDR) ? "LMP" : "PAL",
+ (((di.type & 0x30) >> 4) == HCI_PRIMARY) ? "LMP" : "PAL",
lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver,
bt_compidtostr(ver.manufacturer), ver.manufacturer);
@@ -1939,7 +1939,7 @@
if (all && !hci_test_bit(HCI_RAW, &di->flags)) {
print_dev_features(di, 0);
- if (((di->type & 0x30) >> 4) == HCI_BREDR) {
+ if (((di->type & 0x30) >> 4) == HCI_PRIMARY) {
print_pkt_type(di);
print_link_policy(di);
print_link_mode(di);
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 494d436..b6f4873 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -428,6 +428,7 @@
bool just_works;
bool client_enable_le;
bool client_enable_sc;
+ bool client_enable_adv;
bool expect_sc_key;
bool force_power_off;
bool addr_type_avail;
@@ -3090,6 +3091,96 @@
.verify_alt_ev_func = verify_ltk,
};
+static bool lk_is_authenticated(const struct mgmt_link_key_info *lk)
+{
+ switch (lk->type) {
+ case 0x00: /* Combination Key */
+ case 0x01: /* Local Unit Key */
+ case 0x02: /* Remote Unit Key */
+ case 0x03: /* Debug Combination Key */
+ if (lk->pin_len == 16)
+ return true;
+ return false;
+ case 0x05: /* Authenticated Combination Key generated from P-192 */
+ case 0x08: /* Authenticated Combination Key generated from P-256 */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool lk_is_sc(const struct mgmt_link_key_info *lk)
+{
+ switch (lk->type) {
+ case 0x07: /* Unauthenticated Combination Key generated from P-256 */
+ case 0x08: /* Authenticated Combination Key generated from P-256 */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool verify_link_key(const void *param, uint16_t length)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+ const struct mgmt_ev_new_link_key *ev = param;
+
+ if (length != sizeof(struct mgmt_ev_new_link_key)) {
+ tester_warn("Invalid new Link Key length %u != %zu", length,
+ sizeof(struct mgmt_ev_new_link_key));
+ return false;
+ }
+
+ if (test->just_works && lk_is_authenticated(&ev->key)) {
+ tester_warn("Authenticated key for just-works");
+ return false;
+ }
+
+ if (!test->just_works && !lk_is_authenticated(&ev->key)) {
+ tester_warn("Unauthenticated key for MITM");
+ return false;
+ }
+
+ if (test->expect_sc_key && !lk_is_sc(&ev->key)) {
+ tester_warn("Non-LE SC key for SC pairing");
+ return false;
+ }
+
+ if (!test->expect_sc_key && lk_is_sc(&ev->key)) {
+ tester_warn("SC key for Non-SC pairing");
+ return false;
+ }
+
+ return true;
+}
+
+static uint16_t settings_powered_le_sc_bondable[] = {
+ MGMT_OP_SET_LE,
+ MGMT_OP_SET_SSP,
+ MGMT_OP_SET_BONDABLE,
+ MGMT_OP_SET_SECURE_CONN,
+ MGMT_OP_SET_POWERED, 0 };
+
+static const struct generic_data pair_device_le_sc_success_test_3 = {
+ .setup_settings = settings_powered_le_sc_bondable,
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_func = pair_device_send_param_func,
+ .addr_type_avail = true,
+ .addr_type = 0x01,
+ .client_enable_sc = true,
+ .client_enable_ssp = true,
+ .client_enable_adv = true,
+ .expect_sc_key = true,
+ .io_cap = 0x02, /* KeyboardOnly */
+ .client_io_cap = 0x02, /* KeyboardOnly */
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_func = pair_device_expect_param_func,
+ .expect_alt_ev = MGMT_EV_NEW_LINK_KEY,
+ .expect_alt_ev_len = 26,
+ .verify_alt_ev_func = verify_link_key,
+};
+
static uint16_t settings_powered_connectable_bondable[] = {
MGMT_OP_SET_BONDABLE,
MGMT_OP_SET_CONNECTABLE,
@@ -4808,11 +4899,12 @@
static void setup_bthost(void)
{
struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
struct bthost *bthost;
bthost = hciemu_client_get_host(data->hciemu);
bthost_set_cmd_complete_cb(bthost, client_cmd_complete, data);
- if (data->hciemu_type == HCIEMU_TYPE_LE)
+ if (data->hciemu_type == HCIEMU_TYPE_LE || test->client_enable_adv)
bthost_set_adv_enable(bthost, 0x01);
else
bthost_write_scan_enable(bthost, 0x03);
@@ -6653,6 +6745,9 @@
test_le("Pair Device - LE SC Success 2",
&pair_device_le_sc_success_test_2,
NULL, test_command_generic);
+ test_bredrle("Pair Device - LE SC Success 3",
+ &pair_device_le_sc_success_test_3,
+ NULL, test_command_generic);
test_bredrle("Pairing Acceptor - Legacy 1",
&pairing_acceptor_legacy_1, NULL,
diff --git a/unit/test-crypto.c b/unit/test-crypto.c
index 8d65707..bc37abb 100644
--- a/unit/test-crypto.c
+++ b/unit/test-crypto.c
@@ -34,6 +34,48 @@
static struct bt_crypto *crypto;
+static void print_debug(const char *str, void *user_data)
+{
+ tester_debug("%s", str);
+}
+
+static void test_h6(gconstpointer data)
+{
+ const uint8_t w[16] = {
+ 0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
+ 0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
+ const uint8_t m[4] = { 0x72, 0x62, 0x65, 0x6c };
+ const uint8_t exp[16] = {
+ 0x99, 0x63, 0xb1, 0x80, 0xe2, 0xa9, 0xd3, 0xe8,
+ 0x1c, 0xc9, 0x6d, 0xe7, 0x02, 0xe1, 0x9a, 0x2d };
+ uint8_t res[16];
+
+ tester_debug("W:");
+ util_hexdump(' ', w, 16, print_debug, NULL);
+
+ tester_debug("M:");
+ util_hexdump(' ', m, 4, print_debug, NULL);
+
+ if (!bt_crypto_h6(crypto, w, m, res)) {
+ tester_test_failed();
+ return;
+ }
+
+ tester_debug("Expected:");
+ util_hexdump(' ', exp, 16, print_debug, NULL);
+
+ tester_debug("Result:");
+ util_hexdump(' ', res, 16, print_debug, NULL);
+
+
+ if (memcmp(res, exp, 16)) {
+ tester_test_failed();
+ return;
+ }
+
+ tester_test_passed();
+}
+
struct test_data {
const uint8_t *msg;
uint16_t msg_len;
@@ -137,11 +179,6 @@
.key = key_5,
};
-static void print_debug(const char *str, void *user_data)
-{
- tester_debug("%s", str);
-}
-
static bool result_compare(const uint8_t exp[12], uint8_t res[12])
{
int i;
@@ -181,6 +218,8 @@
tester_init(&argc, &argv);
+ tester_add("/crypto/h6", NULL, NULL, test_h6, NULL);
+
tester_add("/crypto/sign_att_1", &test_data_1, NULL, test_sign, NULL);
tester_add("/crypto/sign_att_2", &test_data_2, NULL, test_sign, NULL);
tester_add("/crypto/sign_att_3", &test_data_3, NULL, test_sign, NULL);