summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDoHyun Pyun <dh79.pyun@samsung.com>2015-06-08 17:17:10 +0900
committerDoHyun Pyun <dh79.pyun@samsung.com>2015-06-08 20:46:56 +0900
commit82c1ec306908f5d6d4cd9ca328d3fbe7ebac92d3 (patch)
tree94cd4766383381127b03f8de9b66b4b3ecb19a4d /tools
parentc270b3c99f32d1ce10b8552822b9353ab9a0484a (diff)
downloadbluez-82c1ec306908f5d6d4cd9ca328d3fbe7ebac92d3.tar.gz
bluez-82c1ec306908f5d6d4cd9ca328d3fbe7ebac92d3.tar.bz2
bluez-82c1ec306908f5d6d4cd9ca328d3fbe7ebac92d3.zip
Upgrade Bluez 5.28 and synchronize Tizen 2.4's bluez
Change-Id: Ifaf2154ba0ab19b180946e0d92f1817a1d9ed839 Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/3dsp.c282
-rw-r--r--tools/amptest.c6
-rw-r--r--tools/avinfo.c10
-rw-r--r--tools/avtest.c10
-rw-r--r--tools/bccmd.c7
-rw-r--r--tools/bdaddr.c6
-rw-r--r--tools/bluemoon.c105
-rw-r--r--tools/bluetooth-player.c5
-rw-r--r--tools/btattach.c8
-rw-r--r--tools/btgatt-client.c245
-rw-r--r--tools/btgatt-server.c113
-rw-r--r--tools/btinfo.c2
-rw-r--r--tools/btiotest.c2
-rw-r--r--tools/btmgmt.c1888
-rw-r--r--tools/btproxy.c15
-rw-r--r--tools/btsnoop.c2
-rw-r--r--tools/ciptool.c14
-rw-r--r--tools/cltest.c10
-rw-r--r--tools/csr.c6
-rw-r--r--tools/csr_hci.c6
-rw-r--r--tools/gap-tester.c2
-rw-r--r--tools/gatt-example533
-rw-r--r--tools/gatt-service.c3
-rw-r--r--tools/hciattach.c30
-rw-r--r--tools/hciattach_ath3k.c17
-rw-r--r--tools/hciattach_bcm43xx.c6
-rw-r--r--tools/hciattach_intel.c6
-rw-r--r--tools/hciattach_qualcomm.c6
-rw-r--r--tools/hciattach_st.c2
-rw-r--r--tools/hciattach_ti.c6
-rw-r--r--tools/hciattach_tialt.c6
-rw-r--r--tools/hciconfig.c9
-rw-r--r--tools/hcieventmask.c6
-rw-r--r--tools/hcisecfilter.c8
-rw-r--r--tools/hcitool.146
-rw-r--r--tools/hcitool.c72
-rw-r--r--tools/hex2hcd.c481
-rw-r--r--tools/hid2hci.12
-rw-r--r--tools/hid2hci.c57
-rw-r--r--tools/hwdb.c2
-rw-r--r--tools/ibeacon.c2
-rw-r--r--tools/l2cap-tester.c45
-rw-r--r--tools/l2ping.c8
-rw-r--r--tools/l2test.c8
-rw-r--r--tools/mcaptest.c71
-rw-r--r--tools/mgmt-tester.c185
-rwxr-xr-xtools/mpris-player.c2593
-rw-r--r--tools/mpris-proxy.c3
-rw-r--r--tools/obex-client-tool.c2
-rw-r--r--tools/obex-server-tool.c2
-rw-r--r--tools/obexctl.c32
-rw-r--r--tools/oobtest.c800
-rw-r--r--tools/parser/hci.c20
-rw-r--r--tools/rctest.c12
-rw-r--r--tools/rfcomm-tester.c107
-rw-r--r--tools/rfcomm.c8
-rw-r--r--tools/scotest.c4
-rw-r--r--tools/sdptool.c13
-rw-r--r--[-rwxr-xr-x]tools/update_compids.sh0
59 files changed, 4075 insertions, 3882 deletions
diff --git a/tools/3dsp.c b/tools/3dsp.c
index 68dcbb5a..686fe139 100644
--- a/tools/3dsp.c
+++ b/tools/3dsp.c
@@ -31,15 +31,37 @@
#include <string.h>
#include <getopt.h>
-#include "monitor/mainloop.h"
#include "monitor/bt.h"
+#include "src/shared/mainloop.h"
#include "src/shared/timeout.h"
#include "src/shared/util.h"
#include "src/shared/hci.h"
#define LT_ADDR 0x01
#define PKT_TYPE 0x0008 /* 0x0008 = EDR + DM1, 0xff1e = BR only */
-#define SERVICE_DATA LT_ADDR
+#define SERVICE_DATA 0x00
+
+struct broadcast_message {
+ uint32_t frame_sync_instant;
+ uint16_t bluetooth_clock_phase;
+ uint16_t left_open_offset;
+ uint16_t left_close_offset;
+ uint16_t right_open_offset;
+ uint16_t right_close_offset;
+ uint16_t frame_sync_period;
+ uint8_t frame_sync_period_fraction;
+} __attribute__ ((packed));
+
+struct brcm_evt_sync_train_received {
+ uint8_t status;
+ uint8_t bdaddr[6];
+ uint32_t offset;
+ uint8_t map[10];
+ uint8_t service_data;
+ uint8_t lt_addr;
+ uint32_t instant;
+ uint16_t interval;
+} __attribute__ ((packed));
static struct bt_hci *hci_dev;
@@ -76,7 +98,34 @@ static void shutdown_device(void)
mainloop_quit();
}
-static void slave_broadcast_receive(const void *data, uint8_t size,
+static void inquiry_started(const void *data, uint8_t size, void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ printf("Failed to search for 3D display\n");
+ shutdown_device();
+ return;
+ }
+
+ printf("Searching for 3D display\n");
+}
+
+static void start_inquiry(void)
+{
+ struct bt_hci_cmd_inquiry cmd;
+
+ cmd.lap[0] = 0x33;
+ cmd.lap[1] = 0x8b;
+ cmd.lap[2] = 0x9e;
+ cmd.length = 0x08;
+ cmd.num_resp = 0x00;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd),
+ inquiry_started, NULL, NULL);
+}
+
+static void set_slave_broadcast_receive(const void *data, uint8_t size,
void *user_data)
{
printf("Slave broadcast receiption enabled\n");
@@ -90,7 +139,12 @@ static void sync_train_received(const void *data, uint8_t size,
if (evt->status) {
printf("Failed to synchronize with 3D display\n");
- shutdown_device();
+ start_inquiry();
+ return;
+ }
+
+ if (evt->lt_addr != LT_ADDR) {
+ printf("Ignoring synchronization for non 3D display\n");
return;
}
@@ -107,8 +161,42 @@ static void sync_train_received(const void *data, uint8_t size,
memcpy(cmd.map, evt->map, 10);
bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_RECEIVE,
- &cmd, sizeof(cmd),
- slave_broadcast_receive, NULL, NULL);
+ &cmd, sizeof(cmd),
+ set_slave_broadcast_receive, NULL, NULL);
+}
+
+static void brcm_sync_train_received(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct brcm_evt_sync_train_received *evt = data;
+ struct bt_hci_cmd_set_slave_broadcast_receive cmd;
+
+ if (evt->status) {
+ printf("Failed to synchronize with 3D display\n");
+ start_inquiry();
+ return;
+ }
+
+ if (evt->lt_addr != LT_ADDR) {
+ printf("Ignoring synchronization for non 3D display\n");
+ return;
+ }
+
+ cmd.enable = 0x01;
+ memcpy(cmd.bdaddr, evt->bdaddr, 6);
+ cmd.lt_addr = evt->lt_addr;
+ cmd.interval = evt->interval;
+ cmd.offset = evt->offset;
+ cmd.instant = evt->instant;
+ cmd.timeout = cpu_to_le16(0xfffe);
+ cmd.accuracy = 250;
+ cmd.skip = 20;
+ cmd.pkt_type = cpu_to_le16(PKT_TYPE);
+ memcpy(cmd.map, evt->map, 10);
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_RECEIVE,
+ &cmd, sizeof(cmd),
+ set_slave_broadcast_receive, NULL, NULL);
}
static void truncated_page_complete(const void *data, uint8_t size,
@@ -125,8 +213,22 @@ static void truncated_page_complete(const void *data, uint8_t size,
printf("Attempt to synchronize with 3D display\n");
- bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
- sync_train_received, NULL, NULL);
+ memcpy(cmd.bdaddr, evt->bdaddr, 6);
+ cmd.timeout = cpu_to_le16(0x4000);
+ cmd.window = cpu_to_le16(0x0100);
+ cmd.interval = cpu_to_le16(0x0080);
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_RECEIVE_SYNC_TRAIN, &cmd, sizeof(cmd),
+ NULL, NULL, NULL);
+}
+
+static void slave_broadcast_timeout(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_evt_slave_broadcast_timeout *evt = data;
+ struct bt_hci_cmd_receive_sync_train cmd;
+
+ printf("Re-synchronizing with 3D display\n");
memcpy(cmd.bdaddr, evt->bdaddr, 6);
cmd.timeout = cpu_to_le16(0x4000);
@@ -137,6 +239,25 @@ static void truncated_page_complete(const void *data, uint8_t size,
NULL, NULL, NULL);
}
+static void slave_broadcast_receive(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_evt_slave_broadcast_receive *evt = data;
+ struct bt_hci_cmd_read_clock cmd;
+
+ if (evt->status != 0x00)
+ return;
+
+ if (le32_to_cpu(evt->clock) != 0x00000000)
+ return;
+
+ cmd.handle = cpu_to_le16(0x0000);
+ cmd.type = 0x00;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd),
+ NULL, NULL, NULL);
+}
+
static void ext_inquiry_result(const void *data, uint8_t size, void *user_data)
{
const struct bt_hci_evt_ext_inquiry_result *evt = data;
@@ -153,9 +274,6 @@ static void ext_inquiry_result(const void *data, uint8_t size, void *user_data)
bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY_CANCEL, NULL, 0,
NULL, NULL, NULL);
- bt_hci_register(hci_dev, BT_HCI_EVT_TRUNCATED_PAGE_COMPLETE,
- truncated_page_complete, NULL, NULL);
-
memcpy(cmd.bdaddr, evt->bdaddr, 6);
cmd.pscan_rep_mode = evt->pscan_rep_mode;
cmd.clock_offset = evt->clock_offset;
@@ -169,25 +287,32 @@ static void inquiry_complete(const void *data, uint8_t size, void *user_data)
{
printf("No 3D display found\n");
- shutdown_device();
+ start_inquiry();
}
-static void inquiry_started(const void *data, uint8_t size, void *user_data)
+static void read_local_version(const void *data, uint8_t size, void *user_data)
{
- uint8_t status = *((uint8_t *) data);
+ const struct bt_hci_rsp_read_local_version *rsp = data;
- if (status) {
- printf("Failed to search for 3D display\n");
+ if (rsp->status) {
+ printf("Failed to read local version information\n");
shutdown_device();
return;
}
- printf("Searching for 3D display\n");
+ if (rsp->manufacturer == 15) {
+ printf("Enabling receiver workaround for Broadcom\n");
+
+ bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
+ brcm_sync_train_received, NULL, NULL);
+ } else {
+ bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
+ sync_train_received, NULL, NULL);
+ }
}
static void start_glasses(void)
{
- struct bt_hci_cmd_inquiry cmd;
uint8_t evtmask1[] = { 0x03, 0xe0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00 };
uint8_t evtmask2[] = { 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t inqmode = 0x02;
@@ -199,6 +324,9 @@ static void start_glasses(void)
NULL, NULL, NULL);
}
+ bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
+ read_local_version, NULL, NULL);
+
bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK_PAGE2, evtmask2, 8,
NULL, NULL, NULL);
bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_INQUIRY_MODE, &inqmode, 1,
@@ -209,28 +337,14 @@ static void start_glasses(void)
bt_hci_register(hci_dev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
ext_inquiry_result, NULL, NULL);
- cmd.lap[0] = 0x33;
- cmd.lap[1] = 0x8b;
- cmd.lap[2] = 0x9e;
- cmd.length = 0x08;
- cmd.num_resp = 0x00;
-
- bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd),
- inquiry_started, NULL, NULL);
-}
-
-static void conn_request(const void *data, uint8_t size, void *user_data)
-{
- const struct bt_hci_evt_conn_request *evt = data;
- struct bt_hci_cmd_accept_conn_request cmd;
-
- printf("Incoming connection from 3D glasses\n");
-
- memcpy(cmd.bdaddr, evt->bdaddr, 6);
- cmd.role = 0x00;
+ bt_hci_register(hci_dev, BT_HCI_EVT_TRUNCATED_PAGE_COMPLETE,
+ truncated_page_complete, NULL, NULL);
+ bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_BROADCAST_TIMEOUT,
+ slave_broadcast_timeout, NULL, NULL);
+ bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_BROADCAST_RECEIVE,
+ slave_broadcast_receive, NULL, NULL);
- bt_hci_send(hci_dev, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd),
- NULL, NULL, NULL);
+ start_inquiry();
}
static bool sync_train_active = false;
@@ -241,8 +355,7 @@ static void sync_train_complete(const void *data, uint8_t size,
sync_train_active = false;
}
-static void slave_page_response_timeout(const void *data, uint8_t size,
- void *user_data)
+static void start_sync_train(void)
{
struct bt_hci_cmd_write_sync_train_params cmd;
@@ -259,15 +372,44 @@ static void slave_page_response_timeout(const void *data, uint8_t size,
bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_SYNC_TRAIN_PARAMS,
&cmd, sizeof(cmd), NULL, NULL, NULL);
- bt_hci_send(hci_dev, BT_HCI_CMD_READ_SYNC_TRAIN_PARAMS, NULL, 0,
- NULL, NULL, NULL);
-
bt_hci_send(hci_dev, BT_HCI_CMD_START_SYNC_TRAIN, NULL, 0,
NULL, NULL, NULL);
sync_train_active = true;
}
+static void conn_request(const void *data, uint8_t size, void *user_data)
+{
+ const struct bt_hci_evt_conn_request *evt = data;
+ struct bt_hci_cmd_accept_conn_request cmd;
+
+ printf("Incoming connection from 3D glasses\n");
+
+ memcpy(cmd.bdaddr, evt->bdaddr, 6);
+ cmd.role = 0x00;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd),
+ NULL, NULL, NULL);
+
+ start_sync_train();
+}
+
+static void slave_page_response_timeout(const void *data, uint8_t size,
+ void *user_data)
+{
+ printf("Incoming truncated page received\n");
+
+ start_sync_train();
+}
+
+static void slave_broadcast_channel_map_change(const void *data, uint8_t size,
+ void *user_data)
+{
+ printf("Broadcast channel map changed\n");
+
+ start_sync_train();
+}
+
static void inquiry_resp_tx_power(const void *data, uint8_t size,
void *user_data)
{
@@ -292,10 +434,53 @@ static void inquiry_resp_tx_power(const void *data, uint8_t size,
NULL, NULL, NULL);
}
+static void read_clock(const void *data, uint8_t size, void *user_data)
+{
+ const struct bt_hci_rsp_read_clock *rsp = data;
+ struct broadcast_message msg;
+ uint8_t bcastdata[sizeof(msg) + 3] = { LT_ADDR, 0x03, 0x11, };
+
+ if (rsp->status) {
+ printf("Failed to read local clock information\n");
+ shutdown_device();
+ return;
+ }
+
+ msg.frame_sync_instant = rsp->clock;
+ msg.bluetooth_clock_phase = rsp->accuracy;
+ msg.left_open_offset = cpu_to_le16(50);
+ msg.left_close_offset = cpu_to_le16(300);
+ msg.right_open_offset = cpu_to_le16(350);
+ msg.right_close_offset = cpu_to_le16(600);
+ msg.frame_sync_period = cpu_to_le16(650);
+ msg.frame_sync_period_fraction = 0;
+ memcpy(bcastdata + 3, &msg, sizeof(msg));
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_DATA,
+ bcastdata, sizeof(bcastdata), NULL, NULL, NULL);
+}
+
+static void set_slave_broadcast(const void *data, uint8_t size, void *user_data)
+{
+ const struct bt_hci_rsp_set_slave_broadcast *rsp = data;
+ struct bt_hci_cmd_read_clock cmd;
+
+ if (rsp->status) {
+ printf("Failed to set slave broadcast transmission\n");
+ shutdown_device();
+ return;
+ }
+
+ cmd.handle = cpu_to_le16(0x0000);
+ cmd.type = 0x00;
+
+ bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd),
+ read_clock, NULL, NULL);
+}
+
static void start_display(void)
{
struct bt_hci_cmd_set_slave_broadcast cmd;
- uint8_t bcastdata[20] = { LT_ADDR, 0x03, 0x11, 0x23, 0x42, };
uint8_t evtmask1[] = { 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t evtmask2[] = { 0x00, 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t sspmode = 0x01;
@@ -322,15 +507,14 @@ static void start_display(void)
bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_PAGE_RESPONSE_TIMEOUT,
slave_page_response_timeout, NULL, NULL);
+ bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_BROADCAST_CHANNEL_MAP_CHANGE,
+ slave_broadcast_channel_map_change, NULL, NULL);
bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_COMPLETE,
sync_train_complete, NULL, NULL);
bt_hci_send(hci_dev, BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER, NULL, 0,
inquiry_resp_tx_power, NULL, NULL);
- bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_DATA,
- bcastdata, sizeof(bcastdata), NULL, NULL, NULL);
-
cmd.enable = 0x01;
cmd.lt_addr = LT_ADDR;
cmd.lpo_allowed = 0x01;
@@ -340,7 +524,7 @@ static void start_display(void)
cmd.timeout = cpu_to_le16(0xfffe);
bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST, &cmd, sizeof(cmd),
- NULL, NULL, NULL);
+ set_slave_broadcast, NULL, NULL);
}
static void signal_callback(int signum, void *user_data)
diff --git a/tools/amptest.c b/tools/amptest.c
index bba0a9af..55747078 100644
--- a/tools/amptest.c
+++ b/tools/amptest.c
@@ -36,9 +36,9 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
static int activate_amp_controller(int dev_id)
{
diff --git a/tools/avinfo.c b/tools/avinfo.c
index d9f809b6..3f406ca1 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -39,12 +39,12 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include "profiles/audio/a2dp-codecs.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "profiles/audio/a2dp-codecs.h"
#define AVDTP_PSM 25
diff --git a/tools/avtest.c b/tools/avtest.c
index 541b3cdd..70c9b658 100644
--- a/tools/avtest.c
+++ b/tools/avtest.c
@@ -35,11 +35,11 @@
#include <sys/socket.h>
#include <netinet/in.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
#define AVDTP_PKT_TYPE_SINGLE 0x00
#define AVDTP_PKT_TYPE_START 0x01
diff --git a/tools/bccmd.c b/tools/bccmd.c
index 4649ad59..7cce4261 100644
--- a/tools/bccmd.c
+++ b/tools/bccmd.c
@@ -31,9 +31,9 @@
#include <getopt.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "csr.h"
@@ -279,7 +279,6 @@ static int cmd_keylen(int transport, int argc, char *argv[])
if (err < 0)
return -1;
- handle = array[0] | (array[1] << 8);
keylen = array[2] | (array[3] << 8);
printf("Crypt key length: %d bit\n", keylen * 8);
diff --git a/tools/bdaddr.c b/tools/bdaddr.c
index 8356a8de..952e9907 100644
--- a/tools/bdaddr.c
+++ b/tools/bdaddr.c
@@ -33,9 +33,9 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "src/oui.h"
diff --git a/tools/bluemoon.c b/tools/bluemoon.c
index c785472a..650ab0ca 100644
--- a/tools/bluemoon.c
+++ b/tools/bluemoon.c
@@ -35,11 +35,20 @@
#include <sys/stat.h>
#include <sys/param.h>
-#include "monitor/mainloop.h"
#include "monitor/bt.h"
+#include "src/shared/mainloop.h"
#include "src/shared/util.h"
#include "src/shared/hci.h"
+#define CMD_RESET 0xfc01
+struct cmd_reset {
+ uint8_t reset_type;
+ uint8_t patch_enable;
+ uint8_t otp_ddc_reload;
+ uint8_t boot_option;
+ uint32_t boot_addr;
+} __attribute__ ((packed));
+
#define CMD_NO_OPERATION 0xfc02
#define CMD_READ_VERSION 0xfc05
@@ -126,6 +135,11 @@ struct cmd_act_deact_traces {
uint8_t rx_trace;
} __attribute__ ((packed));
+#define CMD_TRIGGER_EXCEPTION 0xfc4d
+struct cmd_trigger_exception {
+ uint8_t type;
+} __attribute__ ((packed));
+
#define CMD_MEMORY_WRITE 0xfc8e
static struct bt_hci *hci_dev;
@@ -146,7 +160,9 @@ static const char *check_firmware_value = NULL;
uint8_t manufacturer_mode_reset = 0x00;
static bool use_manufacturer_mode = false;
static bool set_traces = false;
+static bool set_exception = false;
static bool reset_on_exit = false;
+static bool cold_boot = false;
static void reset_complete(const void *data, uint8_t size, void *user_data)
{
@@ -161,6 +177,25 @@ static void reset_complete(const void *data, uint8_t size, void *user_data)
mainloop_quit();
}
+static void cold_boot_complete(const void *data, uint8_t size, void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ fprintf(stderr, "Failed to cold boot (0x%02x)\n", status);
+ mainloop_quit();
+ return;
+ }
+
+ if (reset_on_exit) {
+ bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
+ reset_complete, NULL, NULL);
+ return;
+ }
+
+ mainloop_quit();
+}
+
static void leave_manufacturer_mode_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -286,6 +321,18 @@ static void act_deact_traces(void)
act_deact_traces_complete, NULL, NULL);
}
+static void trigger_exception(void)
+{
+ struct cmd_trigger_exception cmd;
+
+ cmd.type = 0x00;
+
+ bt_hci_send(hci_dev, CMD_TRIGGER_EXCEPTION, &cmd, sizeof(cmd),
+ NULL, NULL, NULL);
+
+ shutdown_device();
+}
+
static void write_bd_data_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -426,6 +473,11 @@ static void enter_manufacturer_mode_complete(const void *data, uint8_t size,
return;
}
+ if (set_exception) {
+ trigger_exception();
+ return;
+ }
+
shutdown_device();
}
@@ -601,6 +653,20 @@ static void read_version_complete(const void *data, uint8_t size,
return;
}
+ if (cold_boot) {
+ struct cmd_reset cmd;
+
+ cmd.reset_type = 0x01;
+ cmd.patch_enable = 0x00;
+ cmd.otp_ddc_reload = 0x01;
+ cmd.boot_option = 0x00;
+ cmd.boot_addr = cpu_to_le32(0x00000000);
+
+ bt_hci_send(hci_dev, CMD_RESET, &cmd, sizeof(cmd),
+ cold_boot_complete, NULL, NULL);
+ return;
+ }
+
if (load_firmware) {
if (load_firmware_value) {
printf("Firmware: %s\n", load_firmware_value);
@@ -733,7 +799,6 @@ static void analyze_firmware(const char *path)
if (len != st.st_size) {
fprintf(stderr, "Failed to read complete firmware file\n");
goto done;
- return;
}
if ((size_t) len < sizeof(*css)) {
@@ -767,7 +832,7 @@ static void analyze_firmware(const char *path)
printf("\n");
- if (len != le32_to_cpu(css->size) * 4) {
+ if ((size_t) len != le32_to_cpu(css->size) * 4) {
fprintf(stderr, "CSS.size does not match file length\n");
goto done;
}
@@ -830,6 +895,8 @@ static void usage(void)
"\t-F, --firmware [file] Load firmware\n"
"\t-C, --check <file> Check firmware image\n"
"\t-R, --reset Reset controller\n"
+ "\t-B, --coldboot Cold boot controller\n"
+ "\t-E, --exception Trigger exception\n"
"\t-i, --index <num> Use specified controller\n"
"\t-h, --help Show help options\n");
}
@@ -841,7 +908,10 @@ static const struct option main_options[] = {
{ "check", required_argument, NULL, 'C' },
{ "traces", no_argument, NULL, 'T' },
{ "reset", no_argument, NULL, 'R' },
+ { "coldboot", no_argument, NULL, 'B' },
+ { "exception",no_argument, NULL, 'E' },
{ "index", required_argument, NULL, 'i' },
+ { "raw", no_argument, NULL, 'r' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
@@ -850,13 +920,14 @@ static const struct option main_options[] = {
int main(int argc, char *argv[])
{
const char *str;
+ bool use_raw = false;
sigset_t mask;
int exit_status;
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "A::DF::C:TRi:vh",
+ opt = getopt_long(argc, argv, "A::DF::C:TRBEi:rvh",
main_options, NULL);
if (opt < 0)
break;
@@ -881,6 +952,10 @@ int main(int argc, char *argv[])
check_firmware_value = optarg;
check_firmware = true;
break;
+ case 'E':
+ use_manufacturer_mode = true;
+ set_exception = true;
+ break;
case 'T':
use_manufacturer_mode = true;
set_traces = true;
@@ -888,6 +963,9 @@ int main(int argc, char *argv[])
case 'R':
reset_on_exit = true;
break;
+ case 'B':
+ cold_boot = true;
+ break;
case 'i':
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
str = optarg + 3;
@@ -899,6 +977,9 @@ int main(int argc, char *argv[])
}
hci_index = atoi(str);
break;
+ case 'r':
+ use_raw = true;
+ break;
case 'v':
printf("%s\n", VERSION);
return EXIT_SUCCESS;
@@ -930,10 +1011,18 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS;
}
- hci_dev = bt_hci_new_user_channel(hci_index);
- if (!hci_dev) {
- fprintf(stderr, "Failed to open HCI user channel\n");
- return EXIT_FAILURE;
+ if (use_raw) {
+ hci_dev = bt_hci_new_raw_device(hci_index);
+ if (!hci_dev) {
+ fprintf(stderr, "Failed to open HCI raw device\n");
+ return EXIT_FAILURE;
+ }
+ } else {
+ hci_dev = bt_hci_new_user_channel(hci_index);
+ if (!hci_dev) {
+ fprintf(stderr, "Failed to open HCI user channel\n");
+ return EXIT_FAILURE;
+ }
}
bt_hci_send(hci_dev, CMD_READ_VERSION, NULL, 0,
diff --git a/tools/bluetooth-player.c b/tools/bluetooth-player.c
index f090e1b1..9e199970 100644
--- a/tools/bluetooth-player.c
+++ b/tools/bluetooth-player.c
@@ -36,9 +36,9 @@
#include <readline/readline.h>
#include <readline/history.h>
#include <glib.h>
-#include <gdbus.h>
-#include <client/display.h>
+#include "gdbus/gdbus.h"
+#include "client/display.h"
/* String display constants */
#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
@@ -654,7 +654,6 @@ static void cmd_show(int argc, char *argv[])
rl_printf("Player %s\n", g_dbus_proxy_get_path(proxy));
print_property(proxy, "Name");
- print_property(proxy, "Searchable");
print_property(proxy, "Repeat");
print_property(proxy, "Equalizer");
print_property(proxy, "Shuffle");
diff --git a/tools/btattach.c b/tools/btattach.c
index bdbbe160..b7948a36 100644
--- a/tools/btattach.c
+++ b/tools/btattach.c
@@ -37,13 +37,13 @@
#include <sys/ioctl.h>
#include <poll.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
-#include "monitor/mainloop.h"
#include "monitor/bt.h"
+#include "src/shared/mainloop.h"
#include "src/shared/timeout.h"
#include "src/shared/util.h"
#include "src/shared/hci.h"
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index e2e05374..c90f2657 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -33,13 +33,13 @@
#include <limits.h>
#include <errno.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
#include "lib/uuid.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
#include "src/shared/util.h"
#include "src/shared/att.h"
#include "src/shared/queue.h"
@@ -64,6 +64,7 @@ static bool verbose = false;
struct client {
int fd;
+ struct bt_att *att;
struct gatt_db *db;
struct bt_gatt_client *gatt;
};
@@ -74,6 +75,48 @@ static void print_prompt(void)
fflush(stdout);
}
+static const char *ecode_to_string(uint8_t ecode)
+{
+ switch (ecode) {
+ case BT_ATT_ERROR_INVALID_HANDLE:
+ return "Invalid Handle";
+ case BT_ATT_ERROR_READ_NOT_PERMITTED:
+ return "Read Not Permitted";
+ case BT_ATT_ERROR_WRITE_NOT_PERMITTED:
+ return "Write Not Permitted";
+ case BT_ATT_ERROR_INVALID_PDU:
+ return "Invalid PDU";
+ case BT_ATT_ERROR_AUTHENTICATION:
+ return "Authentication Required";
+ case BT_ATT_ERROR_REQUEST_NOT_SUPPORTED:
+ return "Request Not Supported";
+ case BT_ATT_ERROR_INVALID_OFFSET:
+ return "Invalid Offset";
+ case BT_ATT_ERROR_AUTHORIZATION:
+ return "Authorization Required";
+ case BT_ATT_ERROR_PREPARE_QUEUE_FULL:
+ return "Prepare Write Queue Full";
+ case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
+ return "Attribute Not Found";
+ case BT_ATT_ERROR_ATTRIBUTE_NOT_LONG:
+ return "Attribute Not Long";
+ case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
+ return "Insuficient Encryption Key Size";
+ case BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN:
+ return "Invalid Attribute value len";
+ case BT_ATT_ERROR_UNLIKELY:
+ return "Unlikely Error";
+ case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION:
+ return "Insufficient Encryption";
+ case BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE:
+ return "Group type Not Supported";
+ case BT_ATT_ERROR_INSUFFICIENT_RESOURCES:
+ return "Insufficient Resources";
+ default:
+ return "Unknown error type";
+ }
+}
+
static void att_disconnect_cb(int err, void *user_data)
{
printf("Device disconnected: %s\n", strerror(err));
@@ -127,7 +170,6 @@ static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
static struct client *client_create(int fd, uint16_t mtu)
{
struct client *cli;
- struct bt_att *att;
cli = new0(struct client, 1);
if (!cli) {
@@ -135,24 +177,25 @@ static struct client *client_create(int fd, uint16_t mtu)
return NULL;
}
- att = bt_att_new(fd);
- if (!att) {
+ cli->att = bt_att_new(fd);
+ if (!cli->att) {
fprintf(stderr, "Failed to initialze ATT transport layer\n");
- bt_att_unref(att);
+ bt_att_unref(cli->att);
free(cli);
return NULL;
}
- if (!bt_att_set_close_on_unref(att, true)) {
+ if (!bt_att_set_close_on_unref(cli->att, true)) {
fprintf(stderr, "Failed to set up ATT transport layer\n");
- bt_att_unref(att);
+ bt_att_unref(cli->att);
free(cli);
return NULL;
}
- if (!bt_att_register_disconnect(att, att_disconnect_cb, NULL, NULL)) {
+ if (!bt_att_register_disconnect(cli->att, att_disconnect_cb, NULL,
+ NULL)) {
fprintf(stderr, "Failed to set ATT disconnect handler\n");
- bt_att_unref(att);
+ bt_att_unref(cli->att);
free(cli);
return NULL;
}
@@ -161,16 +204,16 @@ static struct client *client_create(int fd, uint16_t mtu)
cli->db = gatt_db_new();
if (!cli->db) {
fprintf(stderr, "Failed to create GATT database\n");
- bt_att_unref(att);
+ bt_att_unref(cli->att);
free(cli);
return NULL;
}
- cli->gatt = bt_gatt_client_new(cli->db, att, mtu);
+ cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu);
if (!cli->gatt) {
fprintf(stderr, "Failed to create GATT client\n");
gatt_db_unref(cli->db);
- bt_att_unref(att);
+ bt_att_unref(cli->att);
free(cli);
return NULL;
}
@@ -179,7 +222,7 @@ static struct client *client_create(int fd, uint16_t mtu)
NULL, NULL);
if (verbose) {
- bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
+ bt_att_set_debug(cli->att, att_debug_cb, "att: ", NULL);
bt_gatt_client_set_debug(cli->gatt, gatt_debug_cb, "gatt: ",
NULL);
}
@@ -189,7 +232,6 @@ static struct client *client_create(int fd, uint16_t mtu)
NULL);
/* bt_gatt_client already holds a reference */
- bt_att_unref(att);
gatt_db_unref(cli->db);
return cli;
@@ -198,6 +240,8 @@ static struct client *client_create(int fd, uint16_t mtu)
static void client_destroy(struct client *cli)
{
bt_gatt_client_unref(cli->gatt);
+ bt_att_unref(cli->att);
+ free(cli);
}
static void print_uuid(const bt_uuid_t *uuid)
@@ -457,6 +501,10 @@ static void cmd_read_multiple(struct client *cli, char *cmd_str)
}
value = malloc(sizeof(uint16_t) * argc);
+ if (!value) {
+ printf("Failed to construct value\n");
+ return;
+ }
for (i = 0; i < argc; i++) {
value[i] = strtol(argv[i], &endptr, 0);
@@ -485,7 +533,8 @@ static void read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
int i;
if (!success) {
- PRLOG("\nRead request failed: 0x%02x\n", att_ecode);
+ PRLOG("\nRead request failed: %s (0x%02x)\n",
+ ecode_to_string(att_ecode), att_ecode);
return;
}
@@ -578,12 +627,14 @@ static void write_value_usage(void)
printf("Usage: write-value [options] <value_handle> <value>\n"
"Options:\n"
"\t-w, --without-response\tWrite without response\n"
+ "\t-s, --signed-write\tSigned write command\n"
"e.g.:\n"
"\twrite-value 0x0001 00 01 00\n");
}
static struct option write_value_options[] = {
{ "without-response", 0, 0, 'w' },
+ { "signed-write", 0, 0, 's' },
{ }
};
@@ -592,7 +643,8 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data)
if (success) {
PRLOG("\nWrite successful\n");
} else {
- PRLOG("\nWrite failed: 0x%02x\n", att_ecode);
+ PRLOG("\nWrite failed: %s (0x%02x)\n",
+ ecode_to_string(att_ecode), att_ecode);
}
}
@@ -607,6 +659,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
int length;
uint8_t *value = NULL;
bool without_response = false;
+ bool signed_write = false;
if (!bt_gatt_client_is_ready(cli->gatt)) {
printf("GATT client not initialized\n");
@@ -621,12 +674,15 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
optind = 0;
argv[0] = "write-value";
- while ((opt = getopt_long(argc, argv, "+w", write_value_options,
+ while ((opt = getopt_long(argc, argv, "+ws", write_value_options,
NULL)) != -1) {
switch (opt) {
case 'w':
without_response = true;
break;
+ case 's':
+ signed_write = true;
+ break;
default:
write_value_usage();
return;
@@ -680,7 +736,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
if (without_response) {
if (!bt_gatt_client_write_without_response(cli->gatt, handle,
- false, value, length)) {
+ signed_write, value, length)) {
printf("Failed to initiate write without response "
"procedure\n");
goto done;
@@ -722,7 +778,8 @@ static void write_long_cb(bool success, bool reliable_error, uint8_t att_ecode,
} else if (reliable_error) {
PRLOG("Reliable write not verified\n");
} else {
- PRLOG("Write failed: 0x%02x\n", att_ecode);
+ PRLOG("\nWrite failed: %s (0x%02x)\n",
+ ecode_to_string(att_ecode), att_ecode);
}
}
@@ -852,16 +909,15 @@ static void notify_cb(uint16_t value_handle, const uint8_t *value,
PRLOG("\n");
}
-static void register_notify_cb(unsigned int id, uint16_t att_ecode,
- void *user_data)
+static void register_notify_cb(uint16_t att_ecode, void *user_data)
{
- if (!id) {
+ if (att_ecode) {
PRLOG("Failed to register notify handler "
"- error code: 0x%02x\n", att_ecode);
return;
}
- PRLOG("Registered notify handler with id: %u\n", id);
+ PRLOG("Registered notify handler!");
}
static void cmd_register_notify(struct client *cli, char *cmd_str)
@@ -869,6 +925,7 @@ static void cmd_register_notify(struct client *cli, char *cmd_str)
char *argv[2];
int argc = 0;
uint16_t value_handle;
+ unsigned int id;
char *endptr = NULL;
if (!bt_gatt_client_is_ready(cli->gatt)) {
@@ -887,12 +944,15 @@ static void cmd_register_notify(struct client *cli, char *cmd_str)
return;
}
- if (!bt_gatt_client_register_notify(cli->gatt, value_handle,
+ id = bt_gatt_client_register_notify(cli->gatt, value_handle,
register_notify_cb,
- notify_cb, NULL, NULL))
+ notify_cb, NULL, NULL);
+ if (!id) {
printf("Failed to register notify handler\n");
+ return;
+ }
- printf("\n");
+ PRLOG("Registering notify handler with id: %u\n", id);
}
static void unregister_notify_usage(void)
@@ -931,6 +991,125 @@ static void cmd_unregister_notify(struct client *cli, char *cmd_str)
printf("Unregistered notify handler with id: %u\n", id);
}
+static void set_sec_level_usage(void)
+{
+ printf("Usage: set_sec_level <level>\n"
+ "level: 1-3\n"
+ "e.g.:\n"
+ "\tset-sec-level 2\n");
+}
+
+static void cmd_set_sec_level(struct client *cli, char *cmd_str)
+{
+ char *argvbuf[1];
+ char **argv = argvbuf;
+ int argc = 0;
+ char *endptr = NULL;
+ int level;
+
+ if (!bt_gatt_client_is_ready(cli->gatt)) {
+ printf("GATT client not initialized\n");
+ return;
+ }
+
+ if (!parse_args(cmd_str, 1, argv, &argc)) {
+ printf("Too many arguments\n");
+ set_sec_level_usage();
+ return;
+ }
+
+ if (argc < 1) {
+ set_sec_level_usage();
+ return;
+ }
+
+ level = strtol(argv[0], &endptr, 0);
+ if (!endptr || *endptr != '\0' || level < 1 || level > 3) {
+ printf("Invalid level: %s\n", argv[0]);
+ return;
+ }
+
+ if (!bt_gatt_client_set_sec_level(cli->gatt, level))
+ printf("Could not set sec level\n");
+ else
+ printf("Setting security level %d success\n", level);
+}
+
+static void cmd_get_sec_level(struct client *cli, char *cmd_str)
+{
+ int level;
+
+ if (!bt_gatt_client_is_ready(cli->gatt)) {
+ printf("GATT client not initialized\n");
+ return;
+ }
+
+ level = bt_gatt_client_get_sec_level(cli->gatt);
+ if (level < 0)
+ printf("Could not set sec level\n");
+ else
+ printf("Security level: %u\n", level);
+}
+
+static bool convert_sign_key(char *optarg, uint8_t key[16])
+{
+ int i;
+
+ if (strlen(optarg) != 32) {
+ printf("sign-key length is invalid\n");
+ return false;
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+static void set_sign_key_usage(void)
+{
+ printf("Usage: set-sign-key [options]\nOptions:\n"
+ "\t -c, --sign-key <csrk>\tCSRK\n"
+ "e.g.:\n"
+ "\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
+}
+
+static bool local_counter(uint32_t *sign_cnt, void *user_data)
+{
+ static uint32_t cnt = 0;
+
+ *sign_cnt = cnt++;
+
+ return true;
+}
+
+static void cmd_set_sign_key(struct client *cli, char *cmd_str)
+{
+ char *argv[3];
+ int argc = 0;
+ uint8_t key[16];
+
+ memset(key, 0, 16);
+
+ if (!parse_args(cmd_str, 2, argv, &argc)) {
+ set_sign_key_usage();
+ return;
+ }
+
+ if (argc != 2) {
+ set_sign_key_usage();
+ return;
+ }
+
+ if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
+ if (convert_sign_key(argv[1], key))
+ bt_att_set_local_key(cli->att, key, local_counter, cli);
+ } else
+ set_sign_key_usage();
+}
+
static void cmd_help(struct client *cli, char *cmd_str);
typedef void (*command_func_t)(struct client *cli, char *cmd_str);
@@ -955,6 +1134,12 @@ static struct {
"\tSubscribe to not/ind from a characteristic" },
{ "unregister-notify", cmd_unregister_notify,
"Unregister a not/ind session"},
+ { "set-sec-level", cmd_set_sec_level,
+ "Set security level on le connection"},
+ { "get-sec-level", cmd_get_sec_level,
+ "Get security level on le connection"},
+ { "set-sign-key", cmd_set_sign_key,
+ "\tSet signing key for signed write command"},
{ }
};
diff --git a/tools/btgatt-server.c b/tools/btgatt-server.c
index f6ad8c3a..b4fbe607 100644
--- a/tools/btgatt-server.c
+++ b/tools/btgatt-server.c
@@ -29,13 +29,13 @@
#include <unistd.h>
#include <errno.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
#include "lib/uuid.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
#include "src/shared/util.h"
#include "src/shared/att.h"
#include "src/shared/queue.h"
@@ -77,6 +77,7 @@ static bool verbose = false;
struct server {
int fd;
+ struct bt_att *att;
struct gatt_db *db;
struct bt_gatt_server *gatt;
@@ -125,7 +126,7 @@ static void gatt_debug_cb(const char *str, void *user_data)
static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -152,7 +153,7 @@ done:
static void gap_device_name_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -196,7 +197,7 @@ done:
static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
uint8_t value[2];
@@ -211,7 +212,7 @@ static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
PRLOG("Service Changed Read called\n");
@@ -221,7 +222,7 @@ static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -238,7 +239,7 @@ static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
static void gatt_svc_chngd_ccc_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -272,7 +273,7 @@ done:
static void hr_msrmt_ccc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -326,7 +327,7 @@ static void update_hr_msrmt_simulation(struct server *server)
static void hr_msrmt_ccc_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -366,7 +367,7 @@ done:
static void hr_control_point_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
- uint8_t opcode, bdaddr_t *bdaddr,
+ uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
@@ -539,7 +540,6 @@ static void populate_db(struct server *server)
static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
{
struct server *server;
- struct bt_att *att;
size_t name_len = strlen(test_device_name);
server = new0(struct server, 1);
@@ -548,18 +548,19 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
return NULL;
}
- att = bt_att_new(fd);
- if (!att) {
+ server->att = bt_att_new(fd);
+ if (!server->att) {
fprintf(stderr, "Failed to initialze ATT transport layer\n");
goto fail;
}
- if (!bt_att_set_close_on_unref(att, true)) {
+ if (!bt_att_set_close_on_unref(server->att, true)) {
fprintf(stderr, "Failed to set up ATT transport layer\n");
goto fail;
}
- if (!bt_att_register_disconnect(att, att_disconnect_cb, NULL, NULL)) {
+ if (!bt_att_register_disconnect(server->att, att_disconnect_cb, NULL,
+ NULL)) {
fprintf(stderr, "Failed to set ATT disconnect handler\n");
goto fail;
}
@@ -581,7 +582,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
goto fail;
}
- server->gatt = bt_gatt_server_new(server->db, att, mtu);
+ server->gatt = bt_gatt_server_new(server->db, server->att, mtu);
if (!server->gatt) {
fprintf(stderr, "Failed to create GATT server\n");
goto fail;
@@ -590,7 +591,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
server->hr_visible = hr_visible;
if (verbose) {
- bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
+ bt_att_set_debug(server->att, att_debug_cb, "att: ", NULL);
bt_gatt_server_set_debug(server->gatt, gatt_debug_cb,
"server: ", NULL);
}
@@ -599,7 +600,6 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
srand(time(NULL));
/* bt_gatt_server already holds a reference */
- bt_att_unref(att);
populate_db(server);
return server;
@@ -607,7 +607,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
fail:
gatt_db_unref(server->db);
free(server->device_name);
- bt_att_unref(att);
+ bt_att_unref(server->att);
free(server);
return NULL;
@@ -631,7 +631,7 @@ static void usage(void)
"\t-s, --security-level <sec>\tSet security level (low|"
"medium|high)\n"
"\t-v, --verbose\t\t\tEnable extra logging\n"
- "\t-r, --heart-rate\t\tEnable Heart Rate service"
+ "\t-r, --heart-rate\t\tEnable Heart Rate service\n"
"\t-h, --help\t\t\tDisplay help\n");
}
@@ -972,6 +972,69 @@ static void cmd_services(struct server *server, char *cmd_str)
gatt_db_foreach_service(server->db, NULL, print_service, server);
}
+static bool convert_sign_key(char *optarg, uint8_t key[16])
+{
+ int i;
+
+ if (strlen(optarg) != 32) {
+ printf("sign-key length is invalid\n");
+ return false;
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+static void set_sign_key_usage(void)
+{
+ printf("Usage: set-sign-key [options]\nOptions:\n"
+ "\t -c, --sign-key <remote csrk>\tRemote CSRK\n"
+ "e.g.:\n"
+ "\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
+}
+
+static bool remote_counter(uint32_t *sign_cnt, void *user_data)
+{
+ static uint32_t cnt = 0;
+
+ if (*sign_cnt < cnt)
+ return false;
+
+ cnt = *sign_cnt;
+
+ return true;
+}
+
+static void cmd_set_sign_key(struct server *server, char *cmd_str)
+{
+ char *argv[3];
+ int argc = 0;
+ uint8_t key[16];
+
+ memset(key, 0, 16);
+
+ if (!parse_args(cmd_str, 2, argv, &argc)) {
+ set_sign_key_usage();
+ return;
+ }
+
+ if (argc != 2) {
+ set_sign_key_usage();
+ return;
+ }
+
+ if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
+ if (convert_sign_key(argv[1], key))
+ bt_att_set_remote_key(server->att, key, remote_counter,
+ server);
+ } else
+ set_sign_key_usage();
+}
+
static void cmd_help(struct server *server, char *cmd_str);
typedef void (*command_func_t)(struct server *server, char *cmd_str);
@@ -985,6 +1048,8 @@ static struct {
{ "notify", cmd_notify, "\tSend handle-value notification" },
{ "heart-rate", cmd_heart_rate, "\tHide/Unhide Heart Rate Service" },
{ "services", cmd_services, "\tEnumerate all services" },
+ { "set-sign-key", cmd_set_sign_key,
+ "\tSet remote signing key for signed write command"},
{ }
};
diff --git a/tools/btinfo.c b/tools/btinfo.c
index b838c251..fd11ac42 100644
--- a/tools/btinfo.c
+++ b/tools/btinfo.c
@@ -35,8 +35,8 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include "monitor/mainloop.h"
#include "monitor/bt.h"
+#include "src/shared/mainloop.h"
#include "src/shared/timeout.h"
#include "src/shared/util.h"
#include "src/shared/hci.h"
diff --git a/tools/btiotest.c b/tools/btiotest.c
index 6a87ffd2..10e78d57 100644
--- a/tools/btiotest.c
+++ b/tools/btiotest.c
@@ -35,7 +35,7 @@
#include <glib.h>
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
#include "btio/btio.h"
diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index eac7204e..8eff56b8 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -24,6 +24,7 @@
#endif
#include <stdio.h>
+#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
@@ -36,32 +37,99 @@
#include <poll.h>
#include <getopt.h>
#include <stdbool.h>
+#include <wordexp.h>
+#include <ctype.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
#include "src/uuid-helper.h"
#include "lib/mgmt.h"
-#include "monitor/mainloop.h"
+#include "client/display.h"
+#include "src/shared/mainloop.h"
+#include "src/shared/io.h"
#include "src/shared/util.h"
#include "src/shared/mgmt.h"
-#include "src/shared/gap.h"
-static bool monitor = false;
+static struct mgmt *mgmt = NULL;
+static uint16_t mgmt_index = MGMT_INDEX_NONE;
+
static bool discovery = false;
static bool resolve_names = true;
+static bool interactive = false;
+
+static char *saved_prompt = NULL;
+static int saved_point = 0;
-static int pending = 0;
+static struct {
+ uint16_t index;
+ uint16_t req;
+ struct mgmt_addr_info addr;
+} prompt = {
+ .index = MGMT_INDEX_NONE,
+};
+
+static int pending_index = 0;
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
-static size_t convert_hexstr(const char *hexstr, uint8_t *buf, size_t buflen)
+#define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# "
+
+static void update_prompt(uint16_t index)
+{
+ char str[32];
+
+ if (index == MGMT_INDEX_NONE)
+ snprintf(str, sizeof(str), "%s# ",
+ COLOR_BLUE "[mgmt]" COLOR_OFF);
+ else
+ snprintf(str, sizeof(str),
+ COLOR_BLUE "[hci%u]" COLOR_OFF "# ", index);
+
+ if (saved_prompt) {
+ free(saved_prompt);
+ saved_prompt = strdup(str);
+ return;
+ }
+
+ rl_set_prompt(str);
+}
+
+static void noninteractive_quit(int status)
+{
+ if (interactive)
+ return;
+
+ if (status == EXIT_SUCCESS)
+ mainloop_exit_success();
+ else
+ mainloop_exit_failure();
+}
+
+#define print(fmt, arg...) do { \
+ if (interactive) \
+ rl_printf(fmt "\n", ## arg); \
+ else \
+ printf(fmt "\n", ## arg); \
+} while (0)
+
+#define error(fmt, arg...) do { \
+ if (interactive) \
+ rl_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \
+ else \
+ fprintf(stderr, fmt "\n", ## arg); \
+} while (0)
+
+static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
{
size_t i, len;
@@ -74,6 +142,17 @@ static size_t convert_hexstr(const char *hexstr, uint8_t *buf, size_t buflen)
return len;
}
+static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str,
+ size_t strlen)
+{
+ size_t i;
+
+ for (i = 0; i < buflen && i < (strlen / 2); i++)
+ sprintf(str + (i * 2), "%02x", buf[i]);
+
+ return i;
+}
+
static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
{
char identity_path[PATH_MAX];
@@ -87,7 +166,7 @@ static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
fp = fopen(identity_path, "r");
if (!fp) {
- perror("Failed to open identity file");
+ error("Failed to open identity file: %s", strerror(errno));
return false;
}
@@ -99,7 +178,7 @@ static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
return false;
str2ba(addr, &irk->addr.bdaddr);
- convert_hexstr(key, irk->val, sizeof(irk->val));
+ hex2bin(key, irk->val, sizeof(irk->val));
free(addr);
free(key);
@@ -112,7 +191,7 @@ static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
irk->addr.type = BDADDR_LE_RANDOM;
break;
default:
- fprintf(stderr, "Invalid address type %u\n", type);
+ error("Invalid address type %u", type);
return false;
}
@@ -125,41 +204,35 @@ static void controller_error(uint16_t index, uint16_t len,
const struct mgmt_ev_controller_error *ev = param;
if (len < sizeof(*ev)) {
- fprintf(stderr,
- "Too short (%u bytes) controller error event\n", len);
+ error("Too short (%u bytes) controller error event", len);
return;
}
- if (monitor)
- printf("hci%u error 0x%02x\n", index, ev->error_code);
+ print("hci%u error 0x%02x", index, ev->error_code);
}
static void index_added(uint16_t index, uint16_t len,
const void *param, void *user_data)
{
- if (monitor)
- printf("hci%u added\n", index);
+ print("hci%u added", index);
}
static void index_removed(uint16_t index, uint16_t len,
const void *param, void *user_data)
{
- if (monitor)
- printf("hci%u removed\n", index);
+ print("hci%u removed", index);
}
static void unconf_index_added(uint16_t index, uint16_t len,
const void *param, void *user_data)
{
- if (monitor)
- printf("hci%u added (unconfigured)\n", index);
+ print("hci%u added (unconfigured)", index);
}
static void unconf_index_removed(uint16_t index, uint16_t len,
const void *param, void *user_data)
{
- if (monitor)
- printf("hci%u removed (unconfigured)\n", index);
+ print("hci%u removed (unconfigured)", index);
}
static const char *options_str[] = {
@@ -167,14 +240,22 @@ static const char *options_str[] = {
"public-address",
};
-static void print_options(uint32_t options)
+static const char *options2str(uint32_t options)
{
+ static char str[256];
unsigned i;
+ int off;
+
+ off = 0;
+ str[0] = '\0';
for (i = 0; i < NELEM(options_str); i++) {
if ((options & (1 << i)) != 0)
- printf("%s ", options_str[i]);
+ off += snprintf(str + off, sizeof(str) - off, "%s ",
+ options_str[i]);
}
+
+ return str;
}
static void new_config_options(uint16_t index, uint16_t len,
@@ -183,15 +264,11 @@ static void new_config_options(uint16_t index, uint16_t len,
const uint32_t *ev = param;
if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short new_config_options event (%u)\n", len);
+ error("Too short new_config_options event (%u)", len);
return;
}
- if (monitor) {
- printf("hci%u new_config_options: ", index);
- print_options(get_le32(ev));
- printf("\n");
- }
+ print("hci%u new_config_options: %s", index, options2str(get_le32(ev)));
}
static const char *settings_str[] = {
@@ -210,16 +287,25 @@ static const char *settings_str[] = {
"debug-keys",
"privacy",
"configuration",
+ "static-addr",
};
-static void print_settings(uint32_t settings)
+static const char *settings2str(uint32_t settings)
{
+ static char str[256];
unsigned i;
+ int off;
+
+ off = 0;
+ str[0] = '\0';
for (i = 0; i < NELEM(settings_str); i++) {
if ((settings & (1 << i)) != 0)
- printf("%s ", settings_str[i]);
+ off += snprintf(str + off, sizeof(str) - off, "%s ",
+ settings_str[i]);
}
+
+ return str;
}
static void new_settings(uint16_t index, uint16_t len,
@@ -228,15 +314,11 @@ static void new_settings(uint16_t index, uint16_t len,
const uint32_t *ev = param;
if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short new_settings event (%u)\n", len);
+ error("Too short new_settings event (%u)", len);
return;
}
- if (monitor) {
- printf("hci%u new_settings: ", index);
- print_settings(get_le32(ev));
- printf("\n");
- }
+ print("hci%u new_settings: %s", index, settings2str(get_le32(ev)));
}
static void discovering(uint16_t index, uint16_t len, const void *param,
@@ -245,44 +327,36 @@ static void discovering(uint16_t index, uint16_t len, const void *param,
const struct mgmt_ev_discovering *ev = param;
if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short (%u bytes) discovering event\n",
- len);
+ error("Too short (%u bytes) discovering event", len);
return;
}
- if (ev->discovering == 0 && discovery) {
- mainloop_quit();
- return;
- }
+ print("hci%u type %u discovering %s", index, ev->type,
+ ev->discovering ? "on" : "off");
- if (monitor)
- printf("hci%u type %u discovering %s\n", index,
- ev->type, ev->discovering ? "on" : "off");
+ if (ev->discovering == 0 && discovery)
+ return noninteractive_quit(EXIT_SUCCESS);
}
static void new_link_key(uint16_t index, uint16_t len, const void *param,
void *user_data)
{
const struct mgmt_ev_new_link_key *ev = param;
+ char addr[18];
if (len != sizeof(*ev)) {
- fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
- len);
+ error("Invalid new_link_key length (%u bytes)", len);
return;
}
- if (monitor) {
- char addr[18];
- ba2str(&ev->key.addr.bdaddr, addr);
- printf("hci%u new_link_key %s type 0x%02x pin_len %d "
- "store_hint %u\n", index, addr, ev->key.type,
- ev->key.pin_len, ev->store_hint);
- }
+ ba2str(&ev->key.addr.bdaddr, addr);
+ print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u",
+ index, addr, ev->key.type, ev->key.pin_len, ev->store_hint);
}
static const char *typestr(uint8_t type)
{
- const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
+ static const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
if (type <= BDADDR_LE_RANDOM)
return str[type];
@@ -295,91 +369,107 @@ static void connected(uint16_t index, uint16_t len, const void *param,
{
const struct mgmt_ev_device_connected *ev = param;
uint16_t eir_len;
+ char addr[18];
if (len < sizeof(*ev)) {
- fprintf(stderr,
- "Invalid connected event length (%u bytes)\n", len);
+ error("Invalid connected event length (%u bytes)", len);
return;
}
eir_len = get_le16(&ev->eir_len);
if (len != sizeof(*ev) + eir_len) {
- fprintf(stderr, "Invalid connected event length "
- "(%u bytes, eir_len %u bytes)\n", len, eir_len);
+ error("Invalid connected event length (%u != eir_len %u)",
+ len, eir_len);
return;
}
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s type %s connected eir_len %u\n", index, addr,
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s type %s connected eir_len %u", index, addr,
typestr(ev->addr.type), eir_len);
- }
+}
+
+static void release_prompt(void)
+{
+ if (!interactive)
+ return;
+
+ memset(&prompt, 0, sizeof(prompt));
+ prompt.index = MGMT_INDEX_NONE;
+
+ if (!saved_prompt)
+ return;
+
+ /* This will cause rl_expand_prompt to re-run over the last prompt,
+ * but our prompt doesn't expand anyway.
+ */
+ rl_set_prompt(saved_prompt);
+ rl_replace_line("", 0);
+ rl_point = saved_point;
+ rl_redisplay();
+
+ free(saved_prompt);
+ saved_prompt = NULL;
}
static void disconnected(uint16_t index, uint16_t len, const void *param,
void *user_data)
{
const struct mgmt_ev_device_disconnected *ev = param;
+ char addr[18];
+ uint8_t reason;
if (len < sizeof(struct mgmt_addr_info)) {
- fprintf(stderr,
- "Invalid disconnected event length (%u bytes)\n", len);
+ error("Invalid disconnected event length (%u bytes)", len);
return;
}
- if (monitor) {
- char addr[18];
- uint8_t reason;
+ if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
+ release_prompt();
- if (len < sizeof(*ev))
- reason = MGMT_DEV_DISCONN_UNKNOWN;
- else
- reason = ev->reason;
+ if (len < sizeof(*ev))
+ reason = MGMT_DEV_DISCONN_UNKNOWN;
+ else
+ reason = ev->reason;
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s type %s disconnected with reason %u\n",
- index, addr, typestr(ev->addr.type), reason);
- }
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s type %s disconnected with reason %u",
+ index, addr, typestr(ev->addr.type), reason);
}
static void conn_failed(uint16_t index, uint16_t len, const void *param,
void *user_data)
{
const struct mgmt_ev_connect_failed *ev = param;
+ char addr[18];
if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid connect_failed event length (%u bytes)\n", len);
+ error("Invalid connect_failed event length (%u bytes)", len);
return;
}
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
- index, addr, typestr(ev->addr.type), ev->status,
- mgmt_errstr(ev->status));
- }
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s type %s connect failed (status 0x%02x, %s)",
+ index, addr, typestr(ev->addr.type), ev->status,
+ mgmt_errstr(ev->status));
}
static void auth_failed(uint16_t index, uint16_t len, const void *param,
void *user_data)
{
const struct mgmt_ev_auth_failed *ev = param;
+ char addr[18];
if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid auth_failed event length (%u bytes)\n", len);
+ error("Invalid auth_failed event length (%u bytes)", len);
return;
}
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s auth failed with status 0x%02x (%s)\n",
+ if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
+ release_prompt();
+
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s auth failed with status 0x%02x (%s)",
index, addr, ev->status, mgmt_errstr(ev->status));
- }
}
static void local_name_changed(uint16_t index, uint16_t len, const void *param,
@@ -388,13 +478,11 @@ static void local_name_changed(uint16_t index, uint16_t len, const void *param,
const struct mgmt_ev_local_name_changed *ev = param;
if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid local_name_changed length (%u bytes)\n", len);
+ error("Invalid local_name_changed length (%u bytes)", len);
return;
}
- if (monitor)
- printf("hci%u name changed: %s\n", index, ev->name);
+ print("hci%u name changed: %s", index, ev->name);
}
static void confirm_name_rsp(uint8_t status, uint16_t len,
@@ -404,25 +492,24 @@ static void confirm_name_rsp(uint8_t status, uint16_t len,
char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr,
- "confirm_name failed with status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
+ error("confirm_name failed with status 0x%02x (%s)", status,
+ mgmt_errstr(status));
return;
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "confirm_name rsp length %u instead of %zu\n",
- len, sizeof(*rp));
+ error("confirm_name rsp length %u instead of %zu",
+ len, sizeof(*rp));
return;
}
ba2str(&rp->addr.bdaddr, addr);
if (status != 0)
- fprintf(stderr, "confirm_name for %s failed: 0x%02x (%s)\n",
+ error("confirm_name for %s failed: 0x%02x (%s)",
addr, status, mgmt_errstr(status));
else
- printf("confirm_name succeeded for %s\n", addr);
+ print("confirm_name succeeded for %s", addr);
}
static char *eir_get_name(const uint8_t *eir, uint16_t eir_len)
@@ -490,8 +577,7 @@ static void device_found(uint16_t index, uint16_t len, const void *param,
uint32_t flags;
if (len < sizeof(*ev)) {
- fprintf(stderr,
- "Too short device_found length (%u bytes)\n", len);
+ error("Too short device_found length (%u bytes)", len);
return;
}
@@ -499,28 +585,28 @@ static void device_found(uint16_t index, uint16_t len, const void *param,
eir_len = get_le16(&ev->eir_len);
if (len != sizeof(*ev) + eir_len) {
- fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes\n",
+ error("dev_found: expected %zu bytes, got %u bytes",
sizeof(*ev) + eir_len, len);
return;
}
- if (monitor || discovery) {
+ if (discovery) {
char addr[18], *name;
ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u dev_found: %s type %s rssi %d "
+ print("hci%u dev_found: %s type %s rssi %d "
"flags 0x%04x ", index, addr,
typestr(ev->addr.type), ev->rssi, flags);
if (ev->addr.type != BDADDR_BREDR)
- printf("AD flags 0x%02x ",
+ print("AD flags 0x%02x ",
eir_get_flags(ev->eir, eir_len));
name = eir_get_name(ev->eir, eir_len);
if (name)
- printf("name %s\n", name);
+ print("name %s", name);
else
- printf("eir_len %u\n", eir_len);
+ print("eir_len %u", eir_len);
free(name);
}
@@ -544,14 +630,12 @@ static void pin_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "PIN Code reply failed with status 0x%02x (%s)\n",
+ error("PIN Code reply failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("PIN Reply successful\n");
+ print("PIN Reply successful");
}
static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index,
@@ -573,14 +657,12 @@ static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "PIN Neg reply failed with status 0x%02x (%s)\n",
+ error("PIN Neg reply failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("PIN Negative Reply successful\n");
+ print("PIN Negative Reply successful");
}
static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
@@ -595,57 +677,16 @@ static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
sizeof(cp), &cp, pin_neg_rsp, NULL, NULL);
}
-static void request_pin(uint16_t index, uint16_t len, const void *param,
- void *user_data)
-{
- const struct mgmt_ev_pin_code_request *ev = param;
- struct mgmt *mgmt = user_data;
- char pin[18];
- size_t pin_len;
-
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid pin_code request length (%u bytes)\n", len);
- return;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s request PIN\n", index, addr);
- }
-
- printf("PIN Request (press enter to reject) >> ");
- fflush(stdout);
-
- memset(pin, 0, sizeof(pin));
-
- if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n') {
- mgmt_pin_neg_reply(mgmt, index, &ev->addr);
- return;
- }
-
- pin_len = strlen(pin);
- if (pin[pin_len - 1] == '\n') {
- pin[pin_len - 1] = '\0';
- pin_len--;
- }
-
- mgmt_pin_reply(mgmt, index, &ev->addr, pin, pin_len);
-}
-
static void confirm_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "User Confirm reply failed. status 0x%02x (%s)\n",
+ error("User Confirm reply failed. status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("User Confirm Reply successful\n");
+ print("User Confirm Reply successful");
}
static int mgmt_confirm_reply(struct mgmt *mgmt, uint16_t index,
@@ -664,14 +705,12 @@ static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "Confirm Neg reply failed. status 0x%02x (%s)\n",
+ error("Confirm Neg reply failed. status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("User Confirm Negative Reply successful\n");
+ print("User Confirm Negative Reply successful");
}
static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
@@ -686,66 +725,16 @@ static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL);
}
-
-static void user_confirm(uint16_t index, uint16_t len, const void *param,
- void *user_data)
-{
- const struct mgmt_ev_user_confirm_request *ev = param;
- struct mgmt *mgmt = user_data;
- char rsp[5];
- size_t rsp_len;
- uint32_t val;
- char addr[18];
-
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid user_confirm request length (%u)\n", len);
- return;
- }
-
- ba2str(&ev->addr.bdaddr, addr);
- val = get_le32(&ev->value);
-
- if (monitor)
- printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
- val, ev->confirm_hint);
-
- if (ev->confirm_hint)
- printf("Accept pairing with %s (yes/no) >> ", addr);
- else
- printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
-
- fflush(stdout);
-
- memset(rsp, 0, sizeof(rsp));
-
- if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n') {
- mgmt_confirm_neg_reply(mgmt, index, &ev->addr);
- return;
- }
-
- rsp_len = strlen(rsp);
- if (rsp[rsp_len - 1] == '\n')
- rsp[rsp_len - 1] = '\0';
-
- if (rsp[0] == 'y' || rsp[0] == 'Y')
- mgmt_confirm_reply(mgmt, index, &ev->addr);
- else
- mgmt_confirm_neg_reply(mgmt, index, &ev->addr);
-}
-
static void passkey_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "User Passkey reply failed. status 0x%02x (%s)\n",
+ error("User Passkey reply failed. status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("User Passkey Reply successful\n");
+ print("User Passkey Reply successful");
}
static int mgmt_passkey_reply(struct mgmt *mgmt, uint16_t index,
@@ -766,14 +755,12 @@ static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "Passkey Neg reply failed. status 0x%02x (%s)\n",
+ error("Passkey Neg reply failed. status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("User Passkey Negative Reply successful\n");
+ print("User Passkey Negative Reply successful");
}
static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index,
@@ -788,95 +775,214 @@ static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index,
sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL);
}
+static bool prompt_input(const char *input)
+{
+ size_t len;
-static void request_passkey(uint16_t index, uint16_t len, const void *param,
+ if (!prompt.req)
+ return false;
+
+ len = strlen(input);
+
+ switch (prompt.req) {
+ case MGMT_EV_PIN_CODE_REQUEST:
+ if (len)
+ mgmt_pin_reply(mgmt, prompt.index, &prompt.addr,
+ input, len);
+ else
+ mgmt_pin_neg_reply(mgmt, prompt.index, &prompt.addr);
+ break;
+ case MGMT_EV_USER_PASSKEY_REQUEST:
+ if (strlen(input) > 0)
+ mgmt_passkey_reply(mgmt, prompt.index, &prompt.addr,
+ atoi(input));
+ else
+ mgmt_passkey_neg_reply(mgmt, prompt.index,
+ &prompt.addr);
+ break;
+ case MGMT_EV_USER_CONFIRM_REQUEST:
+ if (input[0] == 'y' || input[0] == 'Y')
+ mgmt_confirm_reply(mgmt, prompt.index, &prompt.addr);
+ else
+ mgmt_confirm_neg_reply(mgmt, prompt.index,
+ &prompt.addr);
+ break;
+ }
+
+ release_prompt();
+
+ return true;
+}
+
+static void interactive_prompt(const char *msg)
+{
+ if (saved_prompt)
+ return;
+
+ saved_prompt = strdup(rl_prompt);
+ if (!saved_prompt)
+ return;
+
+ saved_point = rl_point;
+
+ rl_set_prompt("");
+ rl_redisplay();
+
+ rl_set_prompt(msg);
+
+ rl_replace_line("", 0);
+ rl_redisplay();
+}
+
+static size_t get_input(char *buf, size_t buf_len)
+{
+ size_t len;
+
+ if (!fgets(buf, buf_len, stdin))
+ return 0;
+
+ len = strlen(buf);
+
+ /* Remove trailing white-space */
+ while (len && isspace(buf[len - 1]))
+ buf[--len] = '\0';
+
+ return len;
+}
+
+static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr,
+ const char *fmt, ...)
+{
+ char msg[256], buf[18];
+ va_list ap;
+ int off;
+
+ prompt.index = index;
+ prompt.req = req;
+ memcpy(&prompt.addr, addr, sizeof(*addr));
+
+ va_start(ap, fmt);
+ off = vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+
+ snprintf(msg + off, sizeof(msg) - off, " %s ",
+ COLOR_BOLDGRAY ">>" COLOR_OFF);
+
+ if (interactive) {
+ interactive_prompt(msg);
+ va_end(ap);
+ return;
+ }
+
+ printf("%s", msg);
+ fflush(stdout);
+
+ memset(buf, 0, sizeof(buf));
+ get_input(buf, sizeof(buf));
+ prompt_input(buf);
+}
+
+static void request_pin(uint16_t index, uint16_t len, const void *param,
void *user_data)
{
- const struct mgmt_ev_user_passkey_request *ev = param;
- struct mgmt *mgmt = user_data;
- char passkey[7];
+ const struct mgmt_ev_pin_code_request *ev = param;
+ char addr[18];
if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid passkey request length (%u bytes)\n", len);
+ error("Invalid pin_code request length (%u bytes)", len);
return;
}
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s request passkey\n", index, addr);
- }
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s request PIN", index, addr);
- printf("Passkey Request (press enter to reject) >> ");
- fflush(stdout);
+ ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr,
+ "PIN Request (press enter to reject)");
+}
- memset(passkey, 0, sizeof(passkey));
+static void user_confirm(uint16_t index, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_ev_user_confirm_request *ev = param;
+ uint32_t val;
+ char addr[18];
- if (fgets(passkey, sizeof(passkey), stdin) == NULL ||
- passkey[0] == '\n') {
- mgmt_passkey_neg_reply(mgmt, index, &ev->addr);
+ if (len != sizeof(*ev)) {
+ error("Invalid user_confirm request length (%u)", len);
return;
}
- len = strlen(passkey);
- if (passkey[len - 1] == '\n') {
- passkey[len - 1] = '\0';
- len--;
+ ba2str(&ev->addr.bdaddr, addr);
+ val = get_le32(&ev->value);
+
+ print("hci%u %s User Confirm %06u hint %u", index, addr,
+ val, ev->confirm_hint);
+
+ if (ev->confirm_hint)
+ ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
+ "Accept pairing with %s (yes/no)", addr);
+ else
+ ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
+ "Confirm value %06u for %s (yes/no)", val, addr);
+}
+
+static void request_passkey(uint16_t index, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_ev_user_passkey_request *ev = param;
+ char addr[18];
+
+ if (len != sizeof(*ev)) {
+ error("Invalid passkey request length (%u bytes)", len);
+ return;
}
- mgmt_passkey_reply(mgmt, index, &ev->addr, atoi(passkey));
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s request passkey", index, addr);
+
+ ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr,
+ "Passkey Request (press enter to reject)");
}
static void passkey_notify(uint16_t index, uint16_t len, const void *param,
void *user_data)
{
const struct mgmt_ev_passkey_notify *ev = param;
+ char addr[18];
if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid passkey request length (%u bytes)\n", len);
+ error("Invalid passkey request length (%u bytes)", len);
return;
}
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s request passkey\n", index, addr);
- }
+ ba2str(&ev->addr.bdaddr, addr);
+ print("hci%u %s request passkey", index, addr);
- printf("Passkey Notify: %06u (entered %u)\n", get_le32(&ev->passkey),
+ print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey),
ev->entered);
}
-static void cmd_monitor(struct mgmt *mgmt, uint16_t index, int argc,
- char **argv)
-{
- printf("Monitoring mgmt events...\n");
- monitor = true;
-}
-
static void version_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
const struct mgmt_rp_read_version *rp = param;
if (status != 0) {
- fprintf(stderr, "Reading mgmt version failed with status"
- " 0x%02x (%s)\n", status, mgmt_errstr(status));
+ error("Reading mgmt version failed with status 0x%02x (%s)",
+ status, mgmt_errstr(status));
goto done;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small version reply (%u bytes)\n", len);
+ error("Too small version reply (%u bytes)", len);
goto done;
}
- printf("MGMT Version %u, revision %u\n", rp->version,
+ print("MGMT Version %u, revision %u", rp->version,
get_le16(&rp->revision));
done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc,
@@ -884,8 +990,8 @@ static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc,
{
if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
0, NULL, version_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send read_version cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send read_version cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -899,13 +1005,13 @@ static void commands_rsp(uint8_t status, uint16_t len, const void *param,
int i;
if (status != 0) {
- fprintf(stderr, "Reading supported commands failed with status"
- " 0x%02x (%s)\n", status, mgmt_errstr(status));
+ error("Read Supported Commands failed: status 0x%02x (%s)",
+ status, mgmt_errstr(status));
goto done;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
+ error("Too small commands reply (%u bytes)", len);
goto done;
}
@@ -916,27 +1022,27 @@ static void commands_rsp(uint8_t status, uint16_t len, const void *param,
num_events * sizeof(uint16_t);
if (len < expected_len) {
- fprintf(stderr, "Too small commands reply (%u != %zu)\n",
+ error("Too small commands reply (%u != %zu)",
len, expected_len);
goto done;
}
opcode = rp->opcodes;
- printf("%u commands:\n", num_commands);
+ print("%u commands:", num_commands);
for (i = 0; i < num_commands; i++) {
uint16_t op = get_le16(opcode++);
- printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
+ print("\t%s (0x%04x)", mgmt_opstr(op), op);
}
- printf("%u events:\n", num_events);
+ print("%u events:", num_events);
for (i = 0; i < num_events; i++) {
uint16_t ev = get_le16(opcode++);
- printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
+ print("\t%s (0x%04x)", mgmt_evstr(ev), ev);
}
done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
@@ -944,8 +1050,8 @@ static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
{
if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
0, NULL, commands_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send read_commands cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send read_commands cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -957,28 +1063,25 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
unsigned int i;
if (status != 0) {
- fprintf(stderr,
- "Reading index list failed with status 0x%02x (%s)\n",
+ error("Reading index list failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
goto done;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small index list reply (%u bytes)\n",
- len);
+ error("Too small index list reply (%u bytes)", len);
goto done;
}
count = get_le16(&rp->num_controllers);
if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
- fprintf(stderr,
- "Index count (%u) doesn't match reply length (%u)\n",
+ error("Index count (%u) doesn't match reply length (%u)",
count, len);
goto done;
}
- printf("Unconfigured index list with %u item%s\n",
+ print("Unconfigured index list with %u item%s",
count, count != 1 ? "s" : "");
for (i = 0; i < count; i++) {
@@ -986,12 +1089,12 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
index = get_le16(&rp->index[i]);
- printf("\thci%u\n", index);
+ print("\thci%u", index);
}
done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
@@ -1001,29 +1104,25 @@ static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
uint16_t index = PTR_TO_UINT(user_data);
if (status != 0) {
- fprintf(stderr,
- "Reading hci%u config failed with status 0x%02x (%s)\n",
+ error("Reading hci%u config failed with status 0x%02x (%s)",
index, status, mgmt_errstr(status));
goto done;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+ error("Too small info reply (%u bytes)", len);
goto done;
}
- printf("hci%u:\tmanufacturer %u\n", index, get_le16(&rp->manufacturer));
-
- printf("\tsupported options: ");
- print_options(get_le32(&rp->supported_options));
- printf("\n");
+ print("hci%u:\tmanufacturer %u", index, get_le16(&rp->manufacturer));
- printf("\tmissing options: ");
- print_options(get_le32(&rp->missing_options));
- printf("\n");
+ print("\tsupported options: %s",
+ options2str(get_le32(&rp->supported_options)));
+ print("\tmissing options: %s",
+ options2str(get_le32(&rp->missing_options)));
done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1034,8 +1133,8 @@ static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST,
MGMT_INDEX_NONE, 0, NULL,
unconf_index_rsp, mgmt, NULL) == 0) {
- fprintf(stderr, "Unable to send unconf_index_list cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send unconf_index_list cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
return;
@@ -1045,8 +1144,8 @@ static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
config_info_rsp, data, NULL) == 0) {
- fprintf(stderr, "Unable to send read_config_info cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send read_config_info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1057,40 +1156,39 @@ static void info_rsp(uint8_t status, uint16_t len, const void *param,
uint16_t index = PTR_TO_UINT(user_data);
char addr[18];
- pending--;
+ pending_index--;
if (status != 0) {
- fprintf(stderr,
- "Reading hci%u info failed with status 0x%02x (%s)\n",
+ error("Reading hci%u info failed with status 0x%02x (%s)",
index, status, mgmt_errstr(status));
goto done;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+ error("Too small info reply (%u bytes)", len);
goto done;
}
ba2str(&rp->bdaddr, addr);
- printf("hci%u:\taddr %s version %u manufacturer %u"
- " class 0x%02x%02x%02x\n", index,
+ print("hci%u:\taddr %s version %u manufacturer %u"
+ " class 0x%02x%02x%02x", index,
addr, rp->version, get_le16(&rp->manufacturer),
rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
- printf("\tsupported settings: ");
- print_settings(get_le32(&rp->supported_settings));
+ print("\tsupported settings: %s",
+ settings2str(get_le32(&rp->supported_settings)));
- printf("\n\tcurrent settings: ");
- print_settings(get_le32(&rp->current_settings));
+ print("\tcurrent settings: %s",
+ settings2str(get_le32(&rp->current_settings)));
- printf("\n\tname %s\n", rp->name);
- printf("\tshort name %s\n", rp->short_name);
+ print("\tname %s", rp->name);
+ print("\tshort name %s", rp->short_name);
- if (pending > 0)
+ if (pending_index > 0)
return;
done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void index_rsp(uint8_t status, uint16_t len, const void *param,
@@ -1102,36 +1200,25 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
unsigned int i;
if (status != 0) {
- fprintf(stderr,
- "Reading index list failed with status 0x%02x (%s)\n",
+ error("Reading index list failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small index list reply (%u bytes)\n",
- len);
- goto done;
+ error("Too small index list reply (%u bytes)", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
count = get_le16(&rp->num_controllers);
if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
- fprintf(stderr,
- "Index count (%u) doesn't match reply length (%u)\n",
+ error("Index count (%u) doesn't match reply length (%u)",
count, len);
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
- if (monitor)
- printf("Index list with %u item%s\n",
- count, count != 1 ? "s" : "");
-
- if (count == 0)
- goto done;
-
- if (monitor && count > 0)
- printf("\t");
+ print("Index list with %u item%s", count, count != 1 ? "s" : "");
for (i = 0; i < count; i++) {
uint16_t index;
@@ -1139,27 +1226,19 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
index = get_le16(&rp->index[i]);
- if (monitor)
- printf("hci%u ", index);
-
data = UINT_TO_PTR(index);
if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
info_rsp, data, NULL) == 0) {
- fprintf(stderr, "Unable to send read_info cmd\n");
- goto done;
+ error("Unable to send read_info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
- pending++;
+ pending_index++;
}
- if (monitor && count > 0)
- printf("\n");
-
- return;
-
-done:
- mainloop_quit();
+ if (!count)
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1170,8 +1249,8 @@ static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
MGMT_INDEX_NONE, 0, NULL,
index_rsp, mgmt, NULL) == 0) {
- fprintf(stderr, "Unable to send index_list cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send index_list cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
return;
@@ -1181,8 +1260,8 @@ static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
data, NULL) == 0) {
- fprintf(stderr, "Unable to send read_info cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send read_info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1232,24 +1311,22 @@ static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
const uint32_t *rp = param;
if (status != 0) {
- fprintf(stderr,
- "%s for hci%u failed with status 0x%02x (%s)\n",
+ error("%s for hci%u failed with status 0x%02x (%s)",
mgmt_opstr(op), id, status, mgmt_errstr(status));
goto done;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small %s response (%u bytes)\n",
+ error("Too small %s response (%u bytes)",
mgmt_opstr(op), len);
goto done;
}
- printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
- print_settings(get_le32(rp));
- printf("\n");
+ print("hci%u %s complete, settings: %s", id, mgmt_opstr(op),
+ settings2str(get_le32(rp)));
done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
@@ -1258,8 +1335,8 @@ static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
uint8_t val;
if (argc < 2) {
- printf("Specify \"on\" or \"off\"\n");
- exit(EXIT_FAILURE);
+ print("Specify \"on\" or \"off\"");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -1273,8 +1350,8 @@ static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
index = 0;
if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) {
- fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
- exit(EXIT_FAILURE);
+ error("Unable to send %s cmd", mgmt_opstr(op));
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1289,8 +1366,8 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
struct mgmt_cp_set_discoverable cp;
if (argc < 2) {
- printf("Usage: btmgmt %s <yes/no/limited> [timeout]\n", argv[0]);
- exit(EXIT_FAILURE);
+ print("Usage: %s <yes/no/limited> [timeout]", argv[0]);
+ return noninteractive_quit(EXIT_FAILURE);
}
memset(&cp, 0, sizeof(cp));
@@ -1312,8 +1389,8 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp,
setting_rsp) == 0) {
- fprintf(stderr, "Unable to send set_discoverable cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_discoverable cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1351,8 +1428,8 @@ static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
uint8_t val;
if (argc < 2) {
- printf("Specify \"on\" or \"off\" or \"only\"\n");
- exit(EXIT_FAILURE);
+ print("Specify \"on\" or \"off\" or \"only\"");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -1369,8 +1446,8 @@ static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index,
sizeof(val), &val, setting_rsp) == 0) {
- fprintf(stderr, "Unable to send set_secure_conn cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_secure_conn cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1401,8 +1478,8 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
struct mgmt_cp_set_privacy cp;
if (argc < 2) {
- printf("Specify \"on\" or \"off\"\n");
- exit(EXIT_FAILURE);
+ print("Specify \"on\" or \"off\"");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -1416,25 +1493,24 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
index = 0;
if (argc > 2) {
- if (convert_hexstr(argv[2], cp.irk,
+ if (hex2bin(argv[2], cp.irk,
sizeof(cp.irk)) != sizeof(cp.irk)) {
- fprintf(stderr, "Invalid key format\n");
- exit(EXIT_FAILURE);
+ error("Invalid key format");
+ return noninteractive_quit(EXIT_FAILURE);
}
} else {
int fd;
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "open(/dev/urandom): %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
+ error("open(/dev/urandom): %s", strerror(errno));
+ return noninteractive_quit(EXIT_FAILURE);
}
if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) {
- fprintf(stderr, "Reading from urandom failed\n");
+ error("Reading from urandom failed");
close(fd);
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
close(fd);
@@ -1442,8 +1518,8 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
setting_rsp) == 0) {
- fprintf(stderr, "Unable to send Set Privacy command\n");
- exit(EXIT_FAILURE);
+ error("Unable to send Set Privacy command");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1453,21 +1529,20 @@ static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
const struct mgmt_ev_class_of_dev_changed *rp = param;
if (len == 0 && status != 0) {
- fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+ error("%s failed, status 0x%02x (%s)",
mgmt_opstr(op), status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
- goto done;
+ error("Unexpected %s len %u", mgmt_opstr(op), len);
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
+ print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op),
rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1475,8 +1550,8 @@ static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
uint8_t class[2];
if (argc < 3) {
- printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
- exit(EXIT_FAILURE);
+ print("Usage: %s <major> <minor>", argv[0]);
+ return noninteractive_quit(EXIT_FAILURE);
}
class[0] = atoi(argv[1]);
@@ -1487,8 +1562,8 @@ static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class,
class_rsp) == 0) {
- fprintf(stderr, "Unable to send set_dev_class cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_dev_class cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1499,33 +1574,30 @@ static void disconnect_rsp(uint8_t status, uint16_t len, const void *param,
char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
+ error("Disconnect failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "Invalid disconnect response length (%u)\n",
- len);
- goto done;
+ error("Invalid disconnect response length (%u)", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
ba2str(&rp->addr.bdaddr, addr);
if (status == 0)
- printf("%s disconnected\n", addr);
+ print("%s disconnected", addr);
else
- fprintf(stderr,
- "Disconnecting %s failed with status 0x%02x (%s)\n",
+ error("Disconnecting %s failed with status 0x%02x (%s)",
addr, status, mgmt_errstr(status));
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void disconnect_usage(void)
{
- printf("Usage: btmgmt disconnect [-t type] <remote address>\n");
+ print("Usage: disconnect [-t type] <remote address>");
}
static struct option disconnect_options[] = {
@@ -1548,9 +1620,11 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ disconnect_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
disconnect_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1560,7 +1634,7 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
if (argc < 1) {
disconnect_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -1572,8 +1646,8 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp,
disconnect_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send disconnect cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send disconnect cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1584,16 +1658,15 @@ static void con_rsp(uint8_t status, uint16_t len, const void *param,
uint16_t count, i;
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
- len);
- goto done;
+ error("Too small (%u bytes) get_connections rsp", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
count = get_le16(&rp->conn_count);
if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
- fprintf(stderr, "Invalid get_connections length "
- " (count=%u, len=%u)\n", count, len);
- goto done;
+ error("Invalid get_connections length (count=%u, len=%u)",
+ count, len);
+ return noninteractive_quit(EXIT_FAILURE);
}
for (i = 0; i < count; i++) {
@@ -1601,11 +1674,10 @@ static void con_rsp(uint8_t status, uint16_t len, const void *param,
ba2str(&rp->addr[i].bdaddr, addr);
- printf("%s type %s\n", addr, typestr(rp->addr[i].type));
+ print("%s type %s", addr, typestr(rp->addr[i].type));
}
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1615,8 +1687,8 @@ static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL,
con_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send get_connections cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send get_connections cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1624,20 +1696,18 @@ static void find_service_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "Unable to start service discovery. status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ error("Start Service Discovery failed: status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("Service discovery started\n");
+ print("Service discovery started");
discovery = true;
}
static void find_service_usage(void)
{
- printf("Usage: btmgmt find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]\n");
+ print("Usage: find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]");
}
static struct option find_service_options[] = {
@@ -1678,39 +1748,39 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
index = 0;
type = 0;
- hci_set_bit(BDADDR_BREDR, &type);
- hci_set_bit(BDADDR_LE_PUBLIC, &type);
- hci_set_bit(BDADDR_LE_RANDOM, &type);
+ type |= (1 << BDADDR_BREDR);
+ type |= (1 << BDADDR_LE_PUBLIC);
+ type |= (1 << BDADDR_LE_RANDOM);
rssi = 127;
count = 0;
if (argc == 1) {
find_service_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
while ((opt = getopt_long(argc, argv, "+lbu:r:p:h",
find_service_options, NULL)) != -1) {
switch (opt) {
case 'l':
- hci_clear_bit(BDADDR_BREDR, &type);
- hci_set_bit(BDADDR_LE_PUBLIC, &type);
- hci_set_bit(BDADDR_LE_RANDOM, &type);
+ type &= ~(1 << BDADDR_BREDR);
+ type |= (1 << BDADDR_LE_PUBLIC);
+ type |= (1 << BDADDR_LE_RANDOM);
break;
case 'b':
- hci_set_bit(BDADDR_BREDR, &type);
- hci_clear_bit(BDADDR_LE_PUBLIC, &type);
- hci_clear_bit(BDADDR_LE_RANDOM, &type);
+ type |= (1 << BDADDR_BREDR);
+ type &= ~(1 << BDADDR_LE_PUBLIC);
+ type &= ~(1 << BDADDR_LE_RANDOM);
break;
case 'u':
if (count == MAX_UUIDS) {
- printf("Max %u UUIDs supported\n", MAX_UUIDS);
- exit(EXIT_FAILURE);
+ print("Max %u UUIDs supported", MAX_UUIDS);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (bt_string2uuid(&uuid, optarg) < 0) {
- printf("Invalid UUID: %s\n", optarg);
- exit(EXIT_FAILURE);
+ print("Invalid UUID: %s", optarg);
+ return noninteractive_quit(EXIT_FAILURE);
}
cp = (void *) buf;
uuid_to_uuid128(&uuid128, &uuid);
@@ -1723,10 +1793,10 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
break;
case 'h':
find_service_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_SUCCESS);
default:
find_service_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1736,7 +1806,7 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
if (argc > 0) {
find_service_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
cp = (void *) buf;
@@ -1747,8 +1817,8 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index,
sizeof(*cp) + count * 16, cp,
find_service_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send start_service_discovery cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send start_service_discovery cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1756,20 +1826,18 @@ static void find_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
- fprintf(stderr,
- "Unable to start discovery. status 0x%02x (%s)\n",
+ error("Unable to start discovery. status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
- return;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("Discovery started\n");
+ print("Discovery started");
discovery = true;
}
static void find_usage(void)
{
- printf("Usage: btmgmt find [-l|-b]>\n");
+ print("Usage: find [-l|-b]>");
}
static struct option find_options[] = {
@@ -1789,27 +1857,29 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
index = 0;
type = 0;
- hci_set_bit(BDADDR_BREDR, &type);
- hci_set_bit(BDADDR_LE_PUBLIC, &type);
- hci_set_bit(BDADDR_LE_RANDOM, &type);
+ type |= (1 << BDADDR_BREDR);
+ type |= (1 << BDADDR_LE_PUBLIC);
+ type |= (1 << BDADDR_LE_RANDOM);
while ((opt = getopt_long(argc, argv, "+lbh", find_options,
NULL)) != -1) {
switch (opt) {
case 'l':
- hci_clear_bit(BDADDR_BREDR, &type);
- hci_set_bit(BDADDR_LE_PUBLIC, &type);
- hci_set_bit(BDADDR_LE_RANDOM, &type);
+ type &= ~(1 << BDADDR_BREDR);
+ type |= (1 << BDADDR_LE_PUBLIC);
+ type |= (1 << BDADDR_LE_RANDOM);
break;
case 'b':
- hci_set_bit(BDADDR_BREDR, &type);
- hci_clear_bit(BDADDR_LE_PUBLIC, &type);
- hci_clear_bit(BDADDR_LE_RANDOM, &type);
+ type |= (1 << BDADDR_BREDR);
+ type &= ~(1 << BDADDR_LE_PUBLIC);
+ type &= ~(1 << BDADDR_LE_RANDOM);
break;
case 'h':
+ find_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
find_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1822,8 +1892,8 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_START_DISCOVERY, index, sizeof(cp), &cp,
find_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send start_discovery cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send start_discovery cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1831,11 +1901,10 @@ static void name_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Unable to set local name "
- "with status 0x%02x (%s)\n",
+ error("Unable to set local name with status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1843,8 +1912,8 @@ static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
struct mgmt_cp_set_local_name cp;
if (argc < 2) {
- printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
- exit(EXIT_FAILURE);
+ print("Usage: %s <name> [shortname]", argv[0]);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -1858,8 +1927,8 @@ static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp,
name_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send set_name cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_name cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1870,35 +1939,34 @@ static void pair_rsp(uint8_t status, uint16_t len, const void *param,
char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
+ error("Pairing failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
- goto done;
+ error("Unexpected pair_rsp len %u", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
+ if (!memcmp(&rp->addr, &prompt.addr, sizeof(rp->addr)))
+ release_prompt();
+
ba2str(&rp->addr.bdaddr, addr);
- if (status != 0) {
- fprintf(stderr,
- "Pairing with %s (%s) failed. status 0x%02x (%s)\n",
+ if (status)
+ error("Pairing with %s (%s) failed. status 0x%02x (%s)",
addr, typestr(rp->addr.type), status,
mgmt_errstr(status));
- goto done;
- }
-
- printf("Paired with %s (%s)\n", addr, typestr(rp->addr.type));
+ else
+ print("Paired with %s (%s)", addr, typestr(rp->addr.type));
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void pair_usage(void)
{
- printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
+ print("Usage: pair [-c cap] [-t type] <remote address>");
}
static struct option pair_options[] = {
@@ -1926,9 +1994,11 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ pair_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
pair_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1938,7 +2008,7 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (argc < 1) {
pair_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -1950,12 +2020,12 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
cp.io_cap = cap;
ba2str(&cp.addr.bdaddr, addr);
- printf("Pairing with %s (%s)\n", addr, typestr(cp.addr.type));
+ print("Pairing with %s (%s)", addr, typestr(cp.addr.type));
if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
pair_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send pair_device cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send pair_device cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -1966,35 +2036,31 @@ static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param,
char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr, "Cancel Pairing failed with 0x%02x (%s)\n",
+ error("Cancel Pairing failed with 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected cancel_pair_rsp len %u\n", len);
- goto done;
+ error("Unexpected cancel_pair_rsp len %u", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
ba2str(&rp->bdaddr, addr);
- if (status != 0) {
- fprintf(stderr,
- "Cancel Pairing with %s (%s) failed. 0x%02x (%s)\n",
+ if (status)
+ error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)",
addr, typestr(rp->type), status,
mgmt_errstr(status));
- goto done;
- }
-
- printf("Pairing Cancelled with %s\n", addr);
+ else
+ print("Pairing Cancelled with %s", addr);
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cancel_pair_usage(void)
{
- printf("Usage: btmgmt cancelpair [-t type] <remote address>\n");
+ print("Usage: cancelpair [-t type] <remote address>");
}
static struct option cancel_pair_options[] = {
@@ -2017,9 +2083,11 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ cancel_pair_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
cancel_pair_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2029,7 +2097,7 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
if (argc < 1) {
cancel_pair_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2041,8 +2109,8 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
if (mgmt_send(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp,
cancel_pair_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send cancel_pair_device cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send cancel_pair_device cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2053,34 +2121,30 @@ static void unpair_rsp(uint8_t status, uint16_t len, const void *param,
char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
+ error("Unpair device failed. status 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
- goto done;
+ error("Unexpected unpair_device_rsp len %u", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
ba2str(&rp->addr.bdaddr, addr);
- if (status != 0) {
- fprintf(stderr,
- "Unpairing %s failed. status 0x%02x (%s)\n",
+ if (status)
+ error("Unpairing %s failed. status 0x%02x (%s)",
addr, status, mgmt_errstr(status));
- goto done;
- }
-
- printf("%s unpaired\n", addr);
+ else
+ print("%s unpaired", addr);
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void unpair_usage(void)
{
- printf("Usage: btmgmt unpair [-t type] <remote address>\n");
+ print("Usage: unpair [-t type] <remote address>");
}
static struct option unpair_options[] = {
@@ -2103,9 +2167,11 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ unpair_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
unpair_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2115,7 +2181,7 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
if (argc < 1) {
unpair_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2128,8 +2194,8 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp,
unpair_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send unpair_device cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send unpair_device cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2137,12 +2203,12 @@ static void keys_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+ error("Load keys failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("Keys successfully loaded\n");
+ print("Keys successfully loaded");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -2156,8 +2222,8 @@ static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp,
keys_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send load_keys cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send load_keys cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2165,12 +2231,12 @@ static void ltks_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+ error("Load keys failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("Long term keys successfully loaded\n");
+ print("Long term keys successfully loaded");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -2184,8 +2250,8 @@ static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp,
ltks_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send load_ltks cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send load_ltks cmd");
+ return noninteractive_quit(EXIT_SUCCESS);
}
}
@@ -2193,17 +2259,17 @@ static void irks_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Load IRKs failed with status 0x%02x (%s)\n",
+ error("Load IRKs failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("Identity Resolving Keys successfully loaded\n");
+ print("Identity Resolving Keys successfully loaded");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void irks_usage(void)
{
- printf("Usage: btmgmt irks [--local]\n");
+ print("Usage: irks [--local]");
}
static struct option irks_options[] = {
@@ -2232,8 +2298,8 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
switch (opt) {
case 'l':
if (count >= MAX_IRKS) {
- fprintf(stderr, "Number of IRKs exceeded\n");
- exit(EXIT_FAILURE);
+ error("Number of IRKs exceeded");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (strlen(optarg) > 3 &&
strncasecmp(optarg, "hci", 3) == 0)
@@ -2241,17 +2307,17 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
else
local_index = atoi(optarg);
if (!load_identity(local_index, &cp->irks[count])) {
- fprintf(stderr, "Unable to load identity\n");
- exit(EXIT_FAILURE);
+ error("Unable to load identity");
+ return noninteractive_quit(EXIT_FAILURE);
}
count++;
break;
case 'h':
irks_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_SUCCESS);
default:
irks_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2261,7 +2327,7 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (argc > 0) {
irks_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
cp->irk_count = cpu_to_le16(count);
@@ -2269,8 +2335,8 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index,
sizeof(*cp) + count * 23, cp,
irks_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send load_irks cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send load_irks cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2281,34 +2347,31 @@ static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+ error("%s failed, status 0x%02x (%s)",
mgmt_opstr(op), status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
- goto done;
+ error("Unexpected %s len %u", mgmt_opstr(op), len);
+ return noninteractive_quit(EXIT_FAILURE);
}
ba2str(&rp->bdaddr, addr);
- if (status != 0) {
- fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
+ if (status)
+ error("%s %s (%s) failed. status 0x%02x (%s)",
mgmt_opstr(op), addr, typestr(rp->type),
status, mgmt_errstr(status));
- goto done;
- }
-
- printf("%s %s succeeded\n", mgmt_opstr(op), addr);
+ else
+ print("%s %s succeeded", mgmt_opstr(op), addr);
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void block_usage(void)
{
- printf("Usage: btmgmt block [-t type] <remote address>\n");
+ print("Usage: block [-t type] <remote address>");
}
static struct option block_options[] = {
@@ -2330,9 +2393,11 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ block_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
block_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2342,7 +2407,7 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (argc < 1) {
block_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2354,14 +2419,14 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp,
block_rsp) == 0) {
- fprintf(stderr, "Unable to send block_device cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send block_device cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
static void unblock_usage(void)
{
- printf("Usage: btmgmt unblock [-t type] <remote address>\n");
+ print("Usage: unblock [-t type] <remote address>");
}
static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
@@ -2378,9 +2443,11 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ unblock_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
unblock_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2390,7 +2457,7 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
if (argc < 1) {
unblock_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2402,8 +2469,8 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp,
block_rsp) == 0) {
- fprintf(stderr, "Unable to send unblock_device cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send unblock_device cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2415,16 +2482,16 @@ static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
uuid_t uuid, uuid128;
if (argc < 3) {
- printf("UUID and service hint needed\n");
- exit(EXIT_FAILURE);
+ print("UUID and service hint needed");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
index = 0;
if (bt_string2uuid(&uuid, argv[1]) < 0) {
- printf("Invalid UUID: %s\n", argv[1]);
- exit(EXIT_FAILURE);
+ print("Invalid UUID: %s", argv[1]);
+ return noninteractive_quit(EXIT_FAILURE);
}
memset(&cp, 0, sizeof(cp));
@@ -2437,8 +2504,8 @@ static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp,
class_rsp) == 0) {
- fprintf(stderr, "Unable to send add_uuid cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send add_uuid cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2450,16 +2517,16 @@ static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
uuid_t uuid, uuid128;
if (argc < 2) {
- printf("UUID needed\n");
- exit(EXIT_FAILURE);
+ print("UUID needed");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
index = 0;
if (bt_string2uuid(&uuid, argv[1]) < 0) {
- printf("Invalid UUID: %s\n", argv[1]);
- exit(EXIT_FAILURE);
+ print("Invalid UUID: %s", argv[1]);
+ return noninteractive_quit(EXIT_FAILURE);
}
memset(&cp, 0, sizeof(cp));
@@ -2470,8 +2537,8 @@ static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp,
class_rsp) == 0) {
- fprintf(stderr, "Unable to send remove_uuid cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send remove_uuid cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2489,46 +2556,35 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param,
{
const struct mgmt_rp_read_local_oob_data *rp = param;
const struct mgmt_rp_read_local_oob_ext_data *rp_ext = param;
- int i;
+ char str[33];
if (status != 0) {
- fprintf(stderr, "Read Local OOB Data failed "
- "with status 0x%02x (%s)\n",
+ error("Read Local OOB Data failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small (%u bytes) read_local_oob rsp\n",
- len);
- goto done;
+ error("Too small (%u bytes) read_local_oob rsp", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("Hash C from P-192: ");
- for (i = 0; i < 16; i++)
- printf("%02x", rp->hash[i]);
- printf("\n");
+ bin2hex(rp->hash, 16, str, sizeof(str));
+ print("Hash C from P-192: %s", str);
- printf("Randomizer R with P-192: ");
- for (i = 0; i < 16; i++)
- printf("%02x", rp->randomizer[i]);
- printf("\n");
+ bin2hex(rp->randomizer, 16, str, sizeof(str));
+ print("Randomizer R with P-192: %s", str);
if (len < sizeof(*rp_ext))
- goto done;
+ return noninteractive_quit(EXIT_SUCCESS);
- printf("Hash C from P-256: ");
- for (i = 0; i < 16; i++)
- printf("%02x", rp_ext->hash256[i]);
- printf("\n");
+ bin2hex(rp_ext->hash256, 16, str, sizeof(str));
+ print("Hash C from P-256: %s", str);
- printf("Randomizer R with P-256: ");
- for (i = 0; i < 16; i++)
- printf("%02x", rp_ext->randomizer256[i]);
- printf("\n");
+ bin2hex(rp_ext->randomizer256, 16, str, sizeof(str));
+ print("Randomizer R with P-256: %s", str);
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_local_oob(struct mgmt *mgmt, uint16_t index,
@@ -2539,8 +2595,8 @@ static void cmd_local_oob(struct mgmt *mgmt, uint16_t index,
if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
local_oob_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send read_local_oob cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send read_local_oob cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2551,26 +2607,25 @@ static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param,
char addr[18];
if (status != 0) {
- fprintf(stderr, "Add Remote OOB Data failed: 0x%02x (%s)\n",
+ error("Add Remote OOB Data failed: 0x%02x (%s)",
status, mgmt_errstr(status));
return;
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small (%u bytes) add_remote_oob rsp\n",
- len);
+ error("Too small (%u bytes) add_remote_oob rsp", len);
return;
}
ba2str(&rp->bdaddr, addr);
- printf("Remote OOB data added for %s (%u)\n", addr, rp->type);
+ print("Remote OOB data added for %s (%u)", addr, rp->type);
}
static void remote_oob_usage(void)
{
- printf("Usage: btmgmt remote-oob [-t <addr_type>] "
+ print("Usage: remote-oob [-t <addr_type>] "
"[-r <rand192>] [-h <hash192>] [-R <rand256>] [-H <hash256>] "
- "<addr>\n");
+ "<addr>");
}
static struct option remote_oob_opt[] = {
@@ -2595,20 +2650,20 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
cp.addr.type = strtol(optarg, NULL, 0);
break;
case 'r':
- convert_hexstr(optarg, cp.rand192, 16);
+ hex2bin(optarg, cp.rand192, 16);
break;
case 'h':
- convert_hexstr(optarg, cp.hash192, 16);
+ hex2bin(optarg, cp.hash192, 16);
break;
case 'R':
- convert_hexstr(optarg, cp.rand256, 16);
+ hex2bin(optarg, cp.rand256, 16);
break;
case 'H':
- convert_hexstr(optarg, cp.hash256, 16);
+ hex2bin(optarg, cp.hash256, 16);
break;
default:
remote_oob_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2618,7 +2673,7 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
if (argc < 1) {
remote_oob_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2626,13 +2681,13 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
str2ba(argv[0], &cp.addr.bdaddr);
- printf("Adding OOB data for %s (%s)\n", argv[0], typestr(cp.addr.type));
+ print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type));
if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index,
sizeof(cp), &cp, remote_oob_rsp,
NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send add_remote_oob cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send add_remote_oob cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2640,19 +2695,18 @@ static void did_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Set Device ID failed "
- "with status 0x%02x (%s)\n",
+ error("Set Device ID failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("Device ID successfully set\n");
+ print("Device ID successfully set");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void did_usage(void)
{
- printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
- printf(" possible source values: bluetooth, usb\n");
+ print("Usage: did <source>:<vendor>:<product>:<version>");
+ print(" possible source values: bluetooth, usb");
}
static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -2663,7 +2717,7 @@ static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
if (argc < 2) {
did_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
@@ -2681,7 +2735,7 @@ static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
}
did_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
done:
if (index == MGMT_INDEX_NONE)
@@ -2694,8 +2748,8 @@ done:
if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp,
did_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send set_device_id cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_device_id cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2703,18 +2757,17 @@ static void static_addr_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Set static address failed "
- "with status 0x%02x (%s)\n",
+ error("Set static address failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("Static address successfully set\n");
+ print("Static address successfully set");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void static_addr_usage(void)
{
- printf("Usage: btmgmt static-addr <address>\n");
+ print("Usage: static-addr <address>");
}
static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
@@ -2724,7 +2777,7 @@ static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
if (argc < 2) {
static_addr_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2734,8 +2787,8 @@ static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp,
static_addr_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send set_static_address cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_static_address cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2745,24 +2798,21 @@ static void options_rsp(uint16_t op, uint16_t id, uint8_t status,
const uint32_t *rp = param;
if (status != 0) {
- fprintf(stderr,
- "%s for hci%u failed with status 0x%02x (%s)\n",
+ error("%s for hci%u failed with status 0x%02x (%s)",
mgmt_opstr(op), id, status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small %s response (%u bytes)\n",
+ error("Too small %s response (%u bytes)",
mgmt_opstr(op), len);
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("hci%u %s complete, options: ", id, mgmt_opstr(op));
- print_options(get_le32(rp));
- printf("\n");
+ print("hci%u %s complete, options: %s", id, mgmt_opstr(op),
+ options2str(get_le32(rp)));
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
@@ -2771,8 +2821,8 @@ static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
struct mgmt_cp_set_public_address cp;
if (argc < 2) {
- printf("Usage: btmgmt public-addr <address>\n");
- exit(EXIT_FAILURE);
+ print("Usage: public-addr <address>");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2782,8 +2832,8 @@ static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp,
options_rsp) == 0) {
- fprintf(stderr, "Unable to send Set Public Address cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send Set Public Address cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2793,8 +2843,8 @@ static void cmd_ext_config(struct mgmt *mgmt, uint16_t index,
struct mgmt_cp_set_external_config cp;
if (argc < 2) {
- printf("Specify \"on\" or \"off\"\n");
- exit(EXIT_FAILURE);
+ print("Specify \"on\" or \"off\"");
+ return noninteractive_quit(EXIT_FAILURE);
}
if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -2809,8 +2859,8 @@ static void cmd_ext_config(struct mgmt *mgmt, uint16_t index,
if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp,
options_rsp) == 0) {
- fprintf(stderr, "Unable to send Set External Config cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send Set External Config cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2826,37 +2876,35 @@ static void conn_info_rsp(uint8_t status, uint16_t len, const void *param,
const struct mgmt_rp_get_conn_info *rp = param; char addr[18];
if (len == 0 && status != 0) {
- fprintf(stderr, "Get Conn Info failed, status 0x%02x (%s)\n",
+ error("Get Conn Info failed, status 0x%02x (%s)",
status, mgmt_errstr(status));
- goto done;
+ return noninteractive_quit(EXIT_FAILURE);
}
if (len < sizeof(*rp)) {
- fprintf(stderr, "Unexpected Get Conn Info len %u\n", len);
- goto done;
+ error("Unexpected Get Conn Info len %u", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
ba2str(&rp->addr.bdaddr, addr);
- if (status != 0) {
- fprintf(stderr, "Get Conn Info for %s (%s) failed. status 0x%02x (%s)\n",
+ if (status) {
+ error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)",
addr, typestr(rp->addr.type),
status, mgmt_errstr(status));
- goto done;
- }
-
- printf("Connection Information for %s (%s)\n",
+ } else {
+ print("Connection Information for %s (%s)",
addr, typestr(rp->addr.type));
- printf("\tRSSI %d\n\tTX power %d\n\tmaximum TX power %d\n",
+ print("\tRSSI %d\tTX power %d\tmaximum TX power %d",
rp->rssi, rp->tx_power, rp->max_tx_power);
+ }
-done:
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void conn_info_usage(void)
{
- printf("Usage: btmgmt conn-info [-t type] <remote address>\n");
+ print("Usage: conn-info [-t type] <remote address>");
}
static struct option conn_info_options[] = {
@@ -2879,9 +2927,11 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ conn_info_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
conn_info_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2891,7 +2941,7 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
if (argc < 1) {
conn_info_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2903,8 +2953,8 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp,
conn_info_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send get_conn_info cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send get_conn_info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2912,18 +2962,17 @@ static void io_cap_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Could not set IO Capability with "
- "status 0x%02x (%s)\n",
+ error("Could not set IO Capability with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("IO Capabilities successfully set\n");
+ print("IO Capabilities successfully set");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void io_cap_usage(void)
{
- printf("Usage: btmgmt io-cap <cap>\n");
+ print("Usage: io-cap <cap>");
}
static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
@@ -2934,7 +2983,7 @@ static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
if (argc < 2) {
io_cap_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2946,8 +2995,8 @@ static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp,
io_cap_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send set-io-cap cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set-io-cap cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2955,17 +3004,17 @@ static void scan_params_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Set scan parameters failed with status 0x%02x (%s)\n",
+ error("Set scan parameters failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
else
- printf("Scan parameters successfully set\n");
+ print("Scan parameters successfully set");
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void scan_params_usage(void)
{
- printf("Usage: btmgmt scan-params <interval> <window>\n");
+ print("Usage: scan-params <interval> <window>");
}
static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
@@ -2975,7 +3024,7 @@ static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
if (argc < 3) {
scan_params_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -2986,8 +3035,8 @@ static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp,
scan_params_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send set_scan_params cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send set_scan_params cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -2997,21 +3046,21 @@ static void clock_info_rsp(uint8_t status, uint16_t len, const void *param,
const struct mgmt_rp_get_clock_info *rp = param;
if (len < sizeof(*rp)) {
- fprintf(stderr, "Unexpected Get Clock Info len %u\n", len);
- exit(EXIT_FAILURE);
+ error("Unexpected Get Clock Info len %u", len);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (status) {
- fprintf(stderr, "Get Clock Info failed with status 0x%02x (%s)\n",
+ error("Get Clock Info failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
- printf("Local Clock: %u\n", le32_to_cpu(rp->local_clock));
- printf("Piconet Clock: %u\n", le32_to_cpu(rp->piconet_clock));
- printf("Accurary: %u\n", le16_to_cpu(rp->accuracy));
+ print("Local Clock: %u", le32_to_cpu(rp->local_clock));
+ print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock));
+ print("Accurary: %u", le16_to_cpu(rp->accuracy));
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_clock_info(struct mgmt *mgmt, uint16_t index,
@@ -3029,8 +3078,8 @@ static void cmd_clock_info(struct mgmt *mgmt, uint16_t index,
if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp,
clock_info_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send get_clock_info cmd\n");
- exit(EXIT_FAILURE);
+ error("Unable to send get_clock_info cmd");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -3038,14 +3087,14 @@ static void add_device_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Add device failed with status 0x%02x (%s)\n",
+ error("Add device failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void add_device_usage(void)
{
- printf("Usage: btmgmt add-device [-a action] [-t type] <address>\n");
+ print("Usage: add-device [-a action] [-t type] <address>");
}
static struct option add_device_options[] = {
@@ -3074,9 +3123,11 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ add_device_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
add_device_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -3086,7 +3137,7 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
if (argc < 1) {
add_device_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -3098,12 +3149,12 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
cp.action = action;
ba2str(&cp.addr.bdaddr, addr);
- printf("Adding device with %s (%s)\n", addr, typestr(cp.addr.type));
+ print("Adding device with %s (%s)", addr, typestr(cp.addr.type));
if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp,
add_device_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send add device command\n");
- exit(EXIT_FAILURE);
+ error("Unable to send add device command");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -3111,14 +3162,14 @@ static void remove_device_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0)
- fprintf(stderr, "Remove device failed with status 0x%02x (%s)\n",
+ error("Remove device failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
- mainloop_quit();
+ noninteractive_quit(EXIT_SUCCESS);
}
static void del_device_usage(void)
{
- printf("Usage: btmgmt del-device [-t type] <address>\n");
+ print("Usage: del-device [-t type] <address>");
}
static struct option del_device_options[] = {
@@ -3142,9 +3193,11 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
type = strtol(optarg, NULL, 0);
break;
case 'h':
+ del_device_usage();
+ return noninteractive_quit(EXIT_SUCCESS);
default:
del_device_usage();
- exit(EXIT_SUCCESS);
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -3154,7 +3207,7 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
if (argc < 1) {
del_device_usage();
- exit(EXIT_FAILURE);
+ return noninteractive_quit(EXIT_FAILURE);
}
if (index == MGMT_INDEX_NONE)
@@ -3165,12 +3218,12 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
cp.addr.type = type;
ba2str(&cp.addr.bdaddr, addr);
- printf("Removing device with %s (%s)\n", addr, typestr(cp.addr.type));
+ print("Removing device with %s (%s)", addr, typestr(cp.addr.type));
if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp,
remove_device_rsp, NULL, NULL) == 0) {
- fprintf(stderr, "Unable to send remove device command\n");
- exit(EXIT_FAILURE);
+ error("Unable to send remove device command");
+ return noninteractive_quit(EXIT_FAILURE);
}
}
@@ -3183,12 +3236,15 @@ static void cmd_clr_devices(struct mgmt *mgmt, uint16_t index,
cmd_del_device(mgmt, index, 2, rm_argv);
}
-static struct {
+struct cmd_info {
char *cmd;
void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
char *doc;
-} command[] = {
- { "monitor", cmd_monitor, "Monitor events" },
+ char * (*gen) (const char *text, int state);
+ void (*disp) (char **matches, int num_matches, int max_length);
+};
+
+static struct cmd_info all_cmd[] = {
{ "version", cmd_version, "Get the MGMT Version" },
{ "commands", cmd_commands, "List supported commands" },
{ "config", cmd_config, "Show configuration info" },
@@ -3238,16 +3294,237 @@ static struct {
{ "add-device", cmd_add_device, "Add Device" },
{ "del-device", cmd_del_device, "Remove Device" },
{ "clr-devices",cmd_clr_devices,"Clear Devices" },
- { }
};
-static void gap_ready(bool status, void *user_data)
+static void cmd_quit(struct mgmt *mgmt, uint16_t index,
+ int argc, char **argv)
+{
+ mainloop_exit_success();
+}
+
+static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
+{
+ mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
+ NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
+ local_name_changed, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
+ mgmt, NULL);
+ mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
+ mgmt, NULL);
+ mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
+ mgmt, NULL);
+ mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
+ request_passkey, mgmt, NULL);
+ mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
+ passkey_notify, mgmt, NULL);
+ mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index,
+ unconf_index_added, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index,
+ unconf_index_removed, NULL, NULL);
+ mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
+ new_config_options, NULL, NULL);
+
+}
+
+static void cmd_select(struct mgmt *mgmt, uint16_t index,
+ int argc, char **argv)
+{
+ if (argc != 2) {
+ error("Usage: select <index>");
+ return;
+ }
+
+ mgmt_cancel_all(mgmt);
+ mgmt_unregister_all(mgmt);
+
+ if (!strcmp(argv[1], "none") || !strcmp(argv[1], "any") ||
+ !strcmp(argv[1], "all"))
+ mgmt_index = MGMT_INDEX_NONE;
+ else if (!strncmp(argv[1], "hci", 3))
+ mgmt_index = atoi(&argv[1][3]);
+ else
+ mgmt_index = atoi(argv[1]);
+
+ register_mgmt_callbacks(mgmt, mgmt_index);
+
+ print("Selected index %u", mgmt_index);
+
+ update_prompt(mgmt_index);
+}
+
+static struct cmd_info interactive_cmd[] = {
+ { "select", cmd_select, "Select a different index" },
+ { "quit", cmd_quit, "Exit program" },
+ { "exit", cmd_quit, "Exit program" },
+ { "help", NULL, "List supported commands" },
+};
+
+static char *cmd_generator(const char *text, int state)
+{
+ static size_t i, j, len;
+ const char *cmd;
+
+ if (!state) {
+ i = 0;
+ j = 0;
+ len = strlen(text);
+ }
+
+ while (i < NELEM(all_cmd)) {
+ cmd = all_cmd[i++].cmd;
+
+ if (!strncmp(cmd, text, len))
+ return strdup(cmd);
+ }
+
+ while (j < NELEM(interactive_cmd)) {
+ cmd = interactive_cmd[j++].cmd;
+
+ if (!strncmp(cmd, text, len))
+ return strdup(cmd);
+ }
+
+ return NULL;
+}
+
+static char **cmd_completion(const char *text, int start, int end)
{
+ char **matches = NULL;
+
+ if (start > 0) {
+ unsigned int i;
+
+ for (i = 0; i < NELEM(all_cmd); i++) {
+ struct cmd_info *c = &all_cmd[i];
+
+ if (strncmp(c->cmd, rl_line_buffer, start - 1))
+ continue;
+
+ if (!c->gen)
+ continue;
+
+ rl_completion_display_matches_hook = c->disp;
+ matches = rl_completion_matches(text, c->gen);
+ break;
+ }
+ } else {
+ rl_completion_display_matches_hook = NULL;
+ matches = rl_completion_matches(text, cmd_generator);
+ }
+
+ if (!matches)
+ rl_attempted_completion_over = 1;
+
+ return matches;
+}
+
+static struct cmd_info *find_cmd(const char *cmd, struct cmd_info table[],
+ size_t cmd_count)
+{
+ size_t i;
+
+ for (i = 0; i < cmd_count; i++) {
+ if (!strcmp(table[i].cmd, cmd))
+ return &table[i];
+ }
+
+ return NULL;
+}
+
+static void rl_handler(char *input)
+{
+ struct cmd_info *c;
+ wordexp_t w;
+ char *cmd, **argv;
+ size_t argc, i;
+
+ if (!input) {
+ rl_insert_text("quit");
+ rl_redisplay();
+ rl_crlf();
+ mainloop_quit();
+ return;
+ }
+
+ if (!strlen(input))
+ goto done;
+
+ if (prompt_input(input))
+ goto done;
+
+ add_history(input);
+
+ if (wordexp(input, &w, WRDE_NOCMD))
+ goto done;
+
+ if (w.we_wordc == 0)
+ goto free_we;
+
+ cmd = w.we_wordv[0];
+ argv = w.we_wordv;
+ argc = w.we_wordc;
+
+ c = find_cmd(cmd, all_cmd, NELEM(all_cmd));
+ if (!c && interactive)
+ c = find_cmd(cmd, interactive_cmd, NELEM(interactive_cmd));
+
+ if (c && c->func) {
+ c->func(mgmt, mgmt_index, argc, argv);
+ goto free_we;
+ }
+
+ if (strcmp(cmd, "help")) {
+ print("Invalid command");
+ goto free_we;
+ }
+
+ print("Available commands:");
+
+ for (i = 0; i < NELEM(all_cmd); i++) {
+ c = &all_cmd[i];
+ if (c->doc)
+ print(" %s %-*s %s", c->cmd,
+ (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
+ }
+
+ if (!interactive)
+ goto free_we;
+
+ for (i = 0; i < NELEM(interactive_cmd); i++) {
+ c = &interactive_cmd[i];
+ if (c->doc)
+ print(" %s %-*s %s", c->cmd,
+ (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
+ }
+
+free_we:
+ wordfree(&w);
+done:
+ free(input);
}
static void usage(void)
{
- int i;
+ unsigned int i;
printf("btmgmt ver %s\n", VERSION);
printf("Usage:\n"
@@ -3259,8 +3536,8 @@ static void usage(void)
"\t--help\tDisplay help\n");
printf("Commands:\n");
- for (i = 0; command[i].cmd; i++)
- printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
+ for (i = 0; i < NELEM(all_cmd); i++)
+ printf("\t%-15s\t%s\n", all_cmd[i].cmd, all_cmd[i].doc);
printf("\n"
"For more information on the usage of each command use:\n"
@@ -3274,15 +3551,32 @@ static struct option main_options[] = {
{ 0, 0, 0, 0 }
};
+static bool prompt_read(struct io *io, void *user_data)
+{
+ rl_callback_read_char();
+ return true;
+}
+
+static struct io *setup_stdin(void)
+{
+ struct io *io;
+
+ io = io_new(STDIN_FILENO);
+ if (!io)
+ return io;
+
+ io_set_read_handler(io, prompt_read, NULL, NULL);
+
+ return io;
+}
+
int main(int argc, char *argv[])
{
- struct bt_gap *gap;
- int opt, i;
+ struct io *input;
uint16_t index = MGMT_INDEX_NONE;
- struct mgmt *mgmt;
- int exit_status;
+ int status, opt;
- while ((opt = getopt_long(argc, argv, "+hvi:",
+ while ((opt = getopt_long(argc, argv, "+hi:",
main_options, NULL)) != -1) {
switch (opt) {
case 'i':
@@ -3292,9 +3586,6 @@ int main(int argc, char *argv[])
else
index = atoi(optarg);
break;
- case 'v':
- monitor = true;
- break;
case 'h':
default:
usage();
@@ -3306,86 +3597,61 @@ int main(int argc, char *argv[])
argv += optind;
optind = 0;
- if (argc < 1) {
- usage();
- return 0;
- }
-
mainloop_init();
- if (index == MGMT_INDEX_NONE)
- gap = bt_gap_new_default();
- else
- gap = bt_gap_new_index(index);
-
- bt_gap_set_ready_handler(gap, gap_ready, NULL, NULL);
-
mgmt = mgmt_new_default();
if (!mgmt) {
fprintf(stderr, "Unable to open mgmt_socket\n");
return EXIT_FAILURE;
}
- for (i = 0; command[i].cmd; i++) {
- if (strcmp(command[i].cmd, argv[0]) != 0)
- continue;
+ if (argc > 0) {
+ struct cmd_info *c;
+
+ c = find_cmd(argv[0], all_cmd, NELEM(all_cmd));
+ if (!c) {
+ fprintf(stderr, "Unknown command: %s\n", argv[0]);
+ mgmt_unref(mgmt);
+ return EXIT_FAILURE;
+ }
- command[i].func(mgmt, index, argc, argv);
- break;
+ c->func(mgmt, index, argc, argv);
}
- if (command[i].cmd == NULL) {
- fprintf(stderr, "Unknown command: %s\n", argv[0]);
- mgmt_unref(mgmt);
- return EXIT_FAILURE;
+ register_mgmt_callbacks(mgmt, index);
+
+ /* Interactive mode */
+ if (!argc)
+ input = setup_stdin();
+ else
+ input = NULL;
+
+ if (input) {
+ interactive = true;
+
+ rl_attempted_completion_function = cmd_completion;
+
+ rl_erase_empty_line = 1;
+ rl_callback_handler_install(NULL, rl_handler);
+
+ update_prompt(index);
+ rl_redisplay();
}
- mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
- NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
- local_name_changed, NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
- mgmt, NULL);
- mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
- mgmt, NULL);
- mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
- mgmt, NULL);
- mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
- request_passkey, mgmt, NULL);
- mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
- passkey_notify, mgmt, NULL);
- mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index,
- unconf_index_added, NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index,
- unconf_index_removed, NULL, NULL);
- mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
- new_config_options, NULL, NULL);
+ mgmt_index = index;
- exit_status = mainloop_run();
+ status = mainloop_run();
+
+ if (input) {
+ io_destroy(input);
+
+ rl_message("");
+ rl_callback_handler_remove();
+ }
mgmt_cancel_all(mgmt);
mgmt_unregister_all(mgmt);
mgmt_unref(mgmt);
- bt_gap_unref(gap);
-
- return exit_status;
+ return status;
}
diff --git a/tools/btproxy.c b/tools/btproxy.c
index 35031482..43ccac17 100644
--- a/tools/btproxy.c
+++ b/tools/btproxy.c
@@ -44,9 +44,12 @@
#include <arpa/inet.h>
#include "src/shared/util.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
#include "monitor/bt.h"
+#define HCI_BREDR 0x00
+#define HCI_AMP 0x01
+
#define BTPROTO_HCI 1
struct sockaddr_hci {
sa_family_t hci_family;
@@ -563,6 +566,7 @@ static void usage(void)
"\t-u, --unix [path] Use Unix server\n"
"\t-p, --port <port> Use specified TCP port\n"
"\t-i, --index <num> Use specified controller\n"
+ "\t-a, --amp Create AMP controller\n"
"\t-d, --debug Enable debugging output\n"
"\t-h, --help Show help options\n");
}
@@ -573,6 +577,7 @@ static const struct option main_options[] = {
{ "unix", optional_argument, NULL, 'u' },
{ "port", required_argument, NULL, 'p' },
{ "index", required_argument, NULL, 'i' },
+ { "amp", no_argument, NULL, 'a' },
{ "debug", no_argument, NULL, 'd' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
@@ -585,18 +590,22 @@ int main(int argc, char *argv[])
const char *server_address = NULL;
const char *unix_path = NULL;
unsigned short tcp_port = 0xb1ee; /* 45550 */
+ uint8_t type = HCI_BREDR;
const char *str;
sigset_t mask;
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "c:l::u::p:i:dvh",
+ opt = getopt_long(argc, argv, "ac:l::u::p:i:dvh",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
+ case 'a':
+ type = HCI_AMP;
+ break;
case 'c':
connect_address = optarg;
break;
@@ -674,7 +683,7 @@ int main(int argc, char *argv[])
printf("Opening virtual device\n");
- host_fd = open_vhci(0x00);
+ host_fd = open_vhci(type);
if (host_fd < 0) {
close(dev_fd);
return EXIT_FAILURE;
diff --git a/tools/btsnoop.c b/tools/btsnoop.c
index 71191ebc..3eb8082d 100644
--- a/tools/btsnoop.c
+++ b/tools/btsnoop.c
@@ -230,7 +230,7 @@ next_packet:
if (flags & 0x01)
opcode = BTSNOOP_OPCODE_SCO_RX_PKT;
else
- opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
+ opcode = BTSNOOP_OPCODE_SCO_TX_PKT;
break;
case 0x04:
opcode = BTSNOOP_OPCODE_EVENT_PKT;
diff --git a/tools/ciptool.c b/tools/ciptool.c
index 3ff9fb1f..e60493d1 100644
--- a/tools/ciptool.c
+++ b/tools/ciptool.c
@@ -36,13 +36,13 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/cmtp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/cmtp.h"
static volatile sig_atomic_t __io_canceled = 0;
diff --git a/tools/cltest.c b/tools/cltest.c
index 0231805b..95fa7b63 100644
--- a/tools/cltest.c
+++ b/tools/cltest.c
@@ -36,12 +36,12 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
static bool send_message(const bdaddr_t *src, const bdaddr_t *dst,
uint16_t psm)
diff --git a/tools/csr.c b/tools/csr.c
index 36af921e..2c091890 100644
--- a/tools/csr.c
+++ b/tools/csr.c
@@ -35,9 +35,9 @@
#include <sys/mman.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "csr.h"
diff --git a/tools/csr_hci.c b/tools/csr_hci.c
index 6bd37c35..d2e4ab9c 100644
--- a/tools/csr_hci.c
+++ b/tools/csr_hci.c
@@ -30,9 +30,9 @@
#include <string.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "csr.h"
diff --git a/tools/gap-tester.c b/tools/gap-tester.c
index 2a0be915..2aa40426 100644
--- a/tools/gap-tester.c
+++ b/tools/gap-tester.c
@@ -25,7 +25,7 @@
#include <config.h>
#endif
-#include <gdbus.h>
+#include "gdbus/gdbus.h"
#include "src/shared/tester.h"
#include "emulator/hciemu.h"
diff --git a/tools/gatt-example b/tools/gatt-example
new file mode 100644
index 00000000..a6f5cbe1
--- /dev/null
+++ b/tools/gatt-example
@@ -0,0 +1,533 @@
+#!/usr/bin/python
+
+import dbus
+import dbus.exceptions
+import dbus.mainloop.glib
+import dbus.service
+
+import array
+import gobject
+
+from random import randint
+
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+GATT_MANAGER_IFACE = 'org.bluez.GattManager1'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+GATT_SERVICE_IFACE = 'org.bluez.GattService1'
+GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
+GATT_DESC_IFACE = 'org.bluez.GattDescriptor1'
+
+class InvalidArgsException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs'
+
+class NotSupportedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.NotSupported'
+
+class NotPermittedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.NotPermitted'
+
+class InvalidValueLengthException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.InvalidValueLength'
+
+class FailedException(dbus.exceptions.DBusException):
+ _dbus_error_name = 'org.bluez.Error.Failed'
+
+
+class Service(dbus.service.Object):
+ PATH_BASE = '/org/bluez/example/service'
+
+ def __init__(self, bus, index, uuid, primary):
+ self.path = self.PATH_BASE + str(index)
+ self.bus = bus
+ self.uuid = uuid
+ self.primary = primary
+ self.characteristics = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ return {
+ GATT_SERVICE_IFACE: {
+ 'UUID': self.uuid,
+ 'Primary': self.primary,
+ 'Characteristics': dbus.Array(
+ self.get_characteristic_paths(),
+ signature='o')
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_characteristic(self, characteristic):
+ self.characteristics.append(characteristic)
+
+ def get_characteristic_paths(self):
+ result = []
+ for chrc in self.characteristics:
+ result.append(chrc.get_path())
+ return result
+
+ def get_characteristics(self):
+ return self.characteristics
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ if interface != GATT_SERVICE_IFACE:
+ raise InvalidArgsException()
+
+ return self.get_properties[GATT_SERVICE_IFACE]
+
+ @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
+ def GetManagedObjects(self):
+ response = {}
+ print 'GetManagedObjects'
+
+ response[self.get_path()] = self.get_properties()
+ chrcs = self.get_characteristics()
+ for chrc in chrcs:
+ response[chrc.get_path()] = chrc.get_properties()
+ descs = chrc.get_descriptors()
+ for desc in descs:
+ response[desc.get_path()] = desc.get_properties()
+
+ return response
+
+
+class Characteristic(dbus.service.Object):
+ def __init__(self, bus, index, uuid, flags, service):
+ self.path = service.path + '/char' + str(index)
+ self.bus = bus
+ self.uuid = uuid
+ self.service = service
+ self.flags = flags
+ self.descriptors = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ return {
+ GATT_CHRC_IFACE: {
+ 'Service': self.service.get_path(),
+ 'UUID': self.uuid,
+ 'Flags': self.flags,
+ 'Descriptors': dbus.Array(
+ self.get_descriptor_paths(),
+ signature='o')
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_descriptor(self, descriptor):
+ self.descriptors.append(descriptor)
+
+ def get_descriptor_paths(self):
+ result = []
+ for desc in self.descriptors:
+ result.append(desc.get_path())
+ return result
+
+ def get_descriptors(self):
+ return self.descriptors
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ if interface != GATT_CHRC_IFACE:
+ raise InvalidArgsException()
+
+ return self.get_properties[GATT_CHRC_IFACE]
+
+ @dbus.service.method(GATT_CHRC_IFACE, out_signature='ay')
+ def ReadValue(self):
+ print 'Default ReadValue called, returning error'
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_CHRC_IFACE, in_signature='ay')
+ def WriteValue(self, value):
+ print 'Default WriteValue called, returning error'
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_CHRC_IFACE)
+ def StartNotify(self):
+ print 'Default StartNotify called, returning error'
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_CHRC_IFACE)
+ def StopNotify(self):
+ print 'Default StopNotify called, returning error'
+ raise NotSupportedException()
+
+ @dbus.service.signal(DBUS_PROP_IFACE,
+ signature='sa{sv}as')
+ def PropertiesChanged(self, interface, changed, invalidated):
+ pass
+
+
+class Descriptor(dbus.service.Object):
+ def __init__(self, bus, index, uuid, characteristic):
+ self.path = characteristic.path + '/desc' + str(index)
+ self.bus = bus
+ self.uuid = uuid
+ self.chrc = characteristic
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ return {
+ GATT_DESC_IFACE: {
+ 'Characteristic': self.chrc.get_path(),
+ 'UUID': self.uuid,
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ @dbus.service.method(DBUS_PROP_IFACE,
+ in_signature='s',
+ out_signature='a{sv}')
+ def GetAll(self, interface):
+ if interface != GATT_DESC_IFACE:
+ raise InvalidArgsException()
+
+ return self.get_properties[GATT_CHRC_IFACE]
+
+ @dbus.service.method(GATT_DESC_IFACE, out_signature='ay')
+ def ReadValue(self):
+ print 'Default ReadValue called, returning error'
+ raise NotSupportedException()
+
+ @dbus.service.method(GATT_DESC_IFACE, in_signature='ay')
+ def WriteValue(self, value):
+ print 'Default WriteValue called, returning error'
+ raise NotSupportedException()
+
+
+class HeartRateService(Service):
+ """
+ Fake Heart Rate Service that simulates a fake heart beat and control point
+ behavior.
+
+ """
+ HR_UUID = '0000180d-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index):
+ Service.__init__(self, bus, index, self.HR_UUID, True)
+ self.add_characteristic(HeartRateMeasurementChrc(bus, 0, self))
+ self.add_characteristic(BodySensorLocationChrc(bus, 1, self))
+ self.add_characteristic(HeartRateControlPointChrc(bus, 2, self))
+ self.energy_expended = 0
+
+
+class HeartRateMeasurementChrc(Characteristic):
+ HR_MSRMT_UUID = '00002a37-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.HR_MSRMT_UUID,
+ ['notify'],
+ service)
+ self.notifying = False
+ self.hr_ee_count = 0
+
+ def hr_msrmt_cb(self):
+ value = []
+ value.append(dbus.Byte(0x06))
+
+ value.append(dbus.Byte(randint(90, 130)))
+
+ if self.hr_ee_count % 10 == 0:
+ value[0] = dbus.Byte(value[0] | 0x08)
+ value.append(dbus.Byte(self.service.energy_expended & 0xff))
+ value.append(dbus.Byte((self.service.energy_expended >> 8) & 0xff))
+
+ self.service.energy_expended = \
+ min(0xffff, self.service.energy_expended + 1)
+ self.hr_ee_count += 1
+
+ print 'Updating value: ' + repr(value)
+
+ self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': value }, [])
+
+ return self.notifying
+
+ def _update_hr_msrmt_simulation(self):
+ print 'Update HR Measurement Simulation'
+
+ if not self.notifying:
+ return
+
+ gobject.timeout_add(1000, self.hr_msrmt_cb)
+
+ def StartNotify(self):
+ if self.notifying:
+ print 'Already notifying, nothing to do'
+ return
+
+ self.notifying = True
+ self._update_hr_msrmt_simulation()
+
+ def StopNotify(self):
+ if not self.notifying:
+ print 'Not notifying, nothing to do'
+ return
+
+ self.notifying = False
+ self._update_hr_msrmt_simulation()
+
+
+class BodySensorLocationChrc(Characteristic):
+ BODY_SNSR_LOC_UUID = '00002a38-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.BODY_SNSR_LOC_UUID,
+ ['read'],
+ service)
+
+ def ReadValue(self):
+ # Return 'Chest' as the sensor location.
+ return [ 0x01 ]
+
+class HeartRateControlPointChrc(Characteristic):
+ HR_CTRL_PT_UUID = '00002a39-0000-1000-8000-00805f9b34fb'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.HR_CTRL_PT_UUID,
+ ['write'],
+ service)
+
+ def WriteValue(self, value):
+ print 'Heart Rate Control Point WriteValue called'
+
+ if len(value) != 1:
+ raise InvalidValueLengthException()
+
+ byte = value[0]
+ print 'Control Point value: ' + repr(byte)
+
+ if byte != 1:
+ raise FailedException("0x80")
+
+ print 'Energy Expended field reset!'
+ self.service.energy_expended = 0
+
+
+class BatteryService(Service):
+ """
+ Fake Battery service that emulates a draining battery.
+
+ """
+ BATTERY_UUID = '180f'
+
+ def __init__(self, bus, index):
+ Service.__init__(self, bus, index, self.BATTERY_UUID, True)
+ self.add_characteristic(BatteryLevelCharacteristic(bus, 0, self))
+
+
+class BatteryLevelCharacteristic(Characteristic):
+ """
+ Fake Battery Level characteristic. The battery level is drained by 2 points
+ every 5 seconds.
+
+ """
+ BATTERY_LVL_UUID = '2a19'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.BATTERY_LVL_UUID,
+ ['read', 'notify'],
+ service)
+ self.notifying = False
+ self.battery_lvl = 100
+ gobject.timeout_add(5000, self.drain_battery)
+
+ def notify_battery_level(self):
+ if not self.notifying:
+ return
+ self.PropertiesChanged(
+ GATT_CHRC_IFACE,
+ { 'Value': [dbus.Byte(self.battery_lvl)] }, [])
+
+ def drain_battery(self):
+ if self.battery_lvl > 0:
+ self.battery_lvl -= 2
+ if self.battery_lvl < 0:
+ self.battery_lvl = 0
+ print 'Battery Level drained: ' + repr(self.battery_lvl)
+ self.notify_battery_level()
+ return True
+
+ def ReadValue(self):
+ print 'Battery Level read: ' + repr(self.battery_lvl)
+ return [dbus.Byte(self.battery_lvl)]
+
+ def StartNotify(self):
+ if self.notifying:
+ print 'Already notifying, nothing to do'
+ return
+
+ self.notifying = True
+ self.notify_battery_level()
+
+ def StopNotify(self):
+ if not self.notifying:
+ print 'Not notifying, nothing to do'
+ return
+
+ self.notifying = False
+
+
+class TestService(Service):
+ """
+ Dummy test service that provides characteristics and descriptors that
+ exercise various API functionality.
+
+ """
+ TEST_SVC_UUID = '12345678-1234-5678-1234-56789abcdef0'
+
+ def __init__(self, bus, index):
+ Service.__init__(self, bus, index, self.TEST_SVC_UUID, False)
+ self.add_characteristic(TestCharacteristic(bus, 0, self))
+
+
+class TestCharacteristic(Characteristic):
+ """
+ Dummy test characteristic. Allows writing arbitrary bytes to its value, and
+ contains "extended properties", as well as a test descriptor.
+
+ """
+ TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef1'
+
+ def __init__(self, bus, index, service):
+ Characteristic.__init__(
+ self, bus, index,
+ self.TEST_CHRC_UUID,
+ ['read', 'write', 'writable-auxiliaries'],
+ service)
+ self.value = []
+ self.add_descriptor(TestDescriptor(bus, 0, self))
+ self.add_descriptor(
+ CharacteristicUserDescriptionDescriptor(bus, 1, self))
+
+ def ReadValue(self):
+ print 'TestCharacteristic Read: ' + repr(self.value)
+ return self.value
+
+ def WriteValue(self, value):
+ print 'TestCharacteristic Write: ' + repr(value)
+ self.value = value
+
+
+class TestDescriptor(Descriptor):
+ """
+ Dummy test descriptor. Returns a static value.
+
+ """
+ TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef2'
+
+ def __init__(self, bus, index, characteristic):
+ Descriptor.__init__(
+ self, bus, index,
+ self.TEST_DESC_UUID,
+ characteristic)
+
+ def ReadValue(self):
+ return [
+ dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t')
+ ]
+
+
+class CharacteristicUserDescriptionDescriptor(Descriptor):
+ """
+ Writable CUD descriptor.
+
+ """
+ CUD_UUID = '2901'
+
+ def __init__(self, bus, index, characteristic):
+ self.writable = 'writable-auxiliaries' in characteristic.flags
+ self.value = array.array('B', 'This is a characteristic for testing')
+ self.value = self.value.tolist()
+ Descriptor.__init__(
+ self, bus, index,
+ self.CUD_UUID,
+ characteristic)
+
+ def ReadValue(self):
+ return self.value
+
+ def WriteValue(self, value):
+ if not self.writable:
+ raise NotPermittedException()
+ self.value = value
+
+
+def register_service_cb():
+ print 'GATT service registered'
+
+
+def register_service_error_cb(error):
+ print 'Failed to register service: ' + str(error)
+ mainloop.quit()
+
+
+def find_adapter(bus):
+ remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
+ DBUS_OM_IFACE)
+ objects = remote_om.GetManagedObjects()
+
+ for o, props in objects.iteritems():
+ if props.has_key(GATT_MANAGER_IFACE):
+ return o
+
+ return None
+
+def main():
+ global mainloop
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ adapter = find_adapter(bus)
+ if not adapter:
+ print 'GattManager1 interface not found'
+ return
+
+ service_manager = dbus.Interface(
+ bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+ GATT_MANAGER_IFACE)
+
+ hr_service = HeartRateService(bus, 0)
+ bat_service = BatteryService(bus, 1)
+ test_service = TestService(bus, 2)
+
+ mainloop = gobject.MainLoop()
+
+ service_manager.RegisterService(hr_service.get_path(), {},
+ reply_handler=register_service_cb,
+ error_handler=register_service_error_cb)
+ service_manager.RegisterService(bat_service.get_path(), {},
+ reply_handler=register_service_cb,
+ error_handler=register_service_error_cb)
+ service_manager.RegisterService(test_service.get_path(), {},
+ reply_handler=register_service_cb,
+ error_handler=register_service_error_cb)
+
+ mainloop.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index 6bca4047..33e0d6a0 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -33,7 +33,8 @@
#include <glib.h>
#include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
#include "src/error.h"
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 3535faa7..150c5d04 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -45,9 +45,9 @@
#include <sys/param.h>
#include <sys/ioctl.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
@@ -1315,7 +1315,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
if (tcgetattr(fd, &ti) < 0) {
perror("Can't get port settings");
- return -1;
+ goto fail;
}
cfmakeraw(&ti);
@@ -1331,13 +1331,13 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
perror("Can't set port settings");
- return -1;
+ goto fail;
}
/* Set initial baudrate */
if (set_speed(fd, &ti, u->init_speed) < 0) {
perror("Can't set initial baud rate");
- return -1;
+ goto fail;
}
tcflush(fd, TCIOFLUSH);
@@ -1358,39 +1358,43 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
#endif
if (u->init && u->init(fd, u, &ti) < 0)
- return -1;
+ goto fail;
tcflush(fd, TCIOFLUSH);
/* Set actual baudrate */
if (set_speed(fd, &ti, u->speed) < 0) {
perror("Can't set baud rate");
- return -1;
+ goto fail;
}
/* Set TTY to N_HCI line discipline */
i = N_HCI;
if (ioctl(fd, TIOCSETD, &i) < 0) {
perror("Can't set line discipline");
- return -1;
+ goto fail;
}
if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
perror("Can't set UART flags");
- return -1;
+ goto fail;
}
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
perror("Can't set device");
- return -1;
+ goto fail;
}
#if 0
if (u->post && u->post(fd, u, &ti) < 0)
- return -1;
+ goto fail;
#endif
return fd;
+
+fail:
+ close(fd);
+ return -1;
}
#endif /* __BROADCOM_PATCH__ */
@@ -1530,7 +1534,7 @@ int main(int argc, char *argv[])
dev[0] = 0;
if (!strchr(opt, '/'))
strcpy(dev, "/dev/");
- strncat(dev, opt, PATH_MAX);
+ strcat(dev, opt);
break;
case 1:
diff --git a/tools/hciattach_ath3k.c b/tools/hciattach_ath3k.c
index 23208c66..a76b4483 100644
--- a/tools/hciattach_ath3k.c
+++ b/tools/hciattach_ath3k.c
@@ -33,9 +33,9 @@
#include <sys/param.h>
#include <sys/ioctl.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
@@ -840,17 +840,8 @@ static int ath_ps_download(int fd)
goto download_cmplete;
}
- /*
- * It is not necessary that Patch file be available,
- * continue with PS Operations if patch file is not available.
- */
- if (patch_file[0] == '\0')
- err = 0;
-
stream = fopen(patch_file, "r");
- if (!stream)
- err = 0;
- else {
+ if(stream) {
patch_count = ps_patch_download(fd, stream);
fclose(stream);
diff --git a/tools/hciattach_bcm43xx.c b/tools/hciattach_bcm43xx.c
index 3d36c209..81f38cbb 100644
--- a/tools/hciattach_bcm43xx.c
+++ b/tools/hciattach_bcm43xx.c
@@ -36,9 +36,9 @@
#include <time.h>
#include <limits.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
diff --git a/tools/hciattach_intel.c b/tools/hciattach_intel.c
index 749098ef..2650dcb6 100644
--- a/tools/hciattach_intel.c
+++ b/tools/hciattach_intel.c
@@ -35,9 +35,9 @@
#include <sys/ioctl.h>
#include <time.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
diff --git a/tools/hciattach_qualcomm.c b/tools/hciattach_qualcomm.c
index 0e25905f..22ac6297 100644
--- a/tools/hciattach_qualcomm.c
+++ b/tools/hciattach_qualcomm.c
@@ -42,9 +42,9 @@
#include <sys/ioctl.h>
#include <sys/uio.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
diff --git a/tools/hciattach_st.c b/tools/hciattach_st.c
index dbb7c47b..474545a7 100644
--- a/tools/hciattach_st.c
+++ b/tools/hciattach_st.c
@@ -35,7 +35,7 @@
#include <dirent.h>
#include <sys/param.h>
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
#include "hciattach.h"
diff --git a/tools/hciattach_ti.c b/tools/hciattach_ti.c
index 9099bb44..14053d0b 100644
--- a/tools/hciattach_ti.c
+++ b/tools/hciattach_ti.c
@@ -37,9 +37,9 @@
#include <sys/param.h>
#include <sys/ioctl.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
diff --git a/tools/hciattach_tialt.c b/tools/hciattach_tialt.c
index a7c17061..f6ef068f 100644
--- a/tools/hciattach_tialt.c
+++ b/tools/hciattach_tialt.c
@@ -41,9 +41,9 @@
#include <sys/ioctl.h>
#include <sys/uio.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "hciattach.h"
diff --git a/tools/hciconfig.c b/tools/hciconfig.c
index 8ec1e8aa..6397e715 100644
--- a/tools/hciconfig.c
+++ b/tools/hciconfig.c
@@ -39,9 +39,9 @@
#include <sys/socket.h>
#include <sys/stat.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "src/textfile.h"
#include "src/shared/util.h"
@@ -624,6 +624,9 @@ static void cmd_features(int ctl, int hdev, char *opt)
exit(1);
}
+ if (max_page < 1 && (features[6] & LMP_SIMPLE_PAIR))
+ max_page = 1;
+
print_dev_hdr(&di);
printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
diff --git a/tools/hcieventmask.c b/tools/hcieventmask.c
index 87beac95..b5f818d3 100644
--- a/tools/hcieventmask.c
+++ b/tools/hcieventmask.c
@@ -31,9 +31,9 @@
#include <getopt.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
static struct option main_options[] = {
{ "device", 1, 0, 'i' },
diff --git a/tools/hcisecfilter.c b/tools/hcisecfilter.c
index 9ad4ce0c..18c90333 100644
--- a/tools/hcisecfilter.c
+++ b/tools/hcisecfilter.c
@@ -29,11 +29,11 @@
#include <stdio.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
-int main(void)
+int main(int argc, char *argv[])
{
uint32_t type_mask;
uint32_t event_mask[2];
diff --git a/tools/hcitool.1 b/tools/hcitool.1
index 85498dc6..7d065563 100644
--- a/tools/hcitool.1
+++ b/tools/hcitool.1
@@ -203,6 +203,52 @@ The clock can be
for the local clock or
.BR 1
for the piconet clock (which is default).
+.TP
+.BI lescan " [--privacy] [--passive] [--whitelist] [--discovery=g|l] \
+[--duplicates]"
+Start LE scan
+.TP
+.BI leinfo " [--static] [--random] <bdaddr>"
+Get LE remote information
+.TP
+.BI lewladd " [--random] <bdaddr>"
+Add device to LE White List
+.TP
+.BI lewlrm " <bdaddr>"
+Remove device from LE White List
+.TP
+.BI lewlsz
+Read size of LE White List
+.TP
+.BI lewlclr
+Clear LE White List
+.TP
+.BI lerladd " [--local irk] [--peer irk] [--random] <bdaddr>"
+Add device to LE Resolving List
+.TP
+.BI lerlrm " <bdaddr>"
+Remove device from LE Resolving List
+.TP
+.BI lerlclr
+Clear LE Resolving List
+.TP
+.BI lerlsz
+Read size of LE Resolving List
+.TP
+.BI lerlon
+Enable LE Address Resolution
+.TP
+.BI lerloff
+Disable LE Address Resolution
+.TP
+.BI lecc " [--static] [--random] <bdaddr> | [--whitelist]"
+Create a LE Connection
+.TP
+.BI ledc " <handle> [reason]"
+Disconnect a LE Connection
+.TP
+.BI lecup " <handle> <min> <max> <latency> <timeout>"
+LE Connection Update
.SH AUTHORS
Written by Maxim Krasnyansky <maxk@qualcomm.com> and Marcel Holtmann <marcel@holtmann.org>
.PP
diff --git a/tools/hcitool.c b/tools/hcitool.c
index 2c84dc7d..02c4ebe1 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -40,9 +40,9 @@
#include <sys/socket.h>
#include <signal.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
#include "src/oui.h"
@@ -967,6 +967,9 @@ static void cmd_info(int dev_id, int argc, char **argv)
hci_read_remote_ext_features(dd, handle, 0, &max_page,
features, 20000);
+ if (max_page < 1 && (features[6] & LMP_SIMPLE_PAIR))
+ max_page = 1;
+
printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
(max_page > 0) ? " page 0" : "",
@@ -2404,9 +2407,7 @@ failed:
static int print_advertising_devices(int dd, uint8_t filter_type)
{
- unsigned char buf_array[HCI_MAX_EVENT_SIZE+1] = {0};
- unsigned char *buf = buf_array;
- unsigned char *ptr = NULL;
+ unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
struct hci_filter nf, of;
struct sigaction sa;
socklen_t olen;
@@ -2433,14 +2434,11 @@ static int print_advertising_devices(int dd, uint8_t filter_type)
sigaction(SIGINT, &sa, NULL);
while (1) {
- evt_le_meta_event *meta = NULL;
- le_advertising_info *info = NULL;
- char addr_array[18];
- char *addr = addr_array;
-
- buf[HCI_MAX_EVENT_SIZE] = 0;
+ evt_le_meta_event *meta;
+ le_advertising_info *info;
+ char addr[18];
- while ((len = read(dd, buf, HCI_MAX_EVENT_SIZE)) < 0) {
+ while ((len = read(dd, buf, sizeof(buf))) < 0) {
if (errno == EINTR && signal_received == SIGINT) {
len = 0;
goto done;
@@ -2462,16 +2460,14 @@ static int print_advertising_devices(int dd, uint8_t filter_type)
/* Ignoring multiple reports */
info = (le_advertising_info *) (meta->data + 1);
if (check_report_filter(filter_type, info)) {
- char name_array[30];
- char *name = name_array;
+ char name[30];
- memset(name, 0, 30);
+ memset(name, 0, sizeof(name));
ba2str(&info->bdaddr, addr);
eir_parse_name(info->data, info->length,
- name, 29);
+ name, sizeof(name) - 1);
- name[29] = '\0';
printf("%s %s\n", addr, name);
}
}
@@ -3300,18 +3296,19 @@ static const char *lecup_help =
"Usage:\n"
"\tlecup <handle> <min> <max> <latency> <timeout>\n"
"\tOptions:\n"
- "\t -H, --handle <0xXXXX> LE connection handle\n"
- "\t -m, --min <interval> Range: 0x0006 to 0x0C80\n"
- "\t -M, --max <interval> Range: 0x0006 to 0x0C80\n"
- "\t -l, --latency <range> Slave latency. Range: 0x0000 to 0x03E8\n"
- "\t -t, --timeout <time> N * 10ms. Range: 0x000A to 0x0C80\n"
+ "\t --handle=<0xXXXX> LE connection handle\n"
+ "\t --min=<interval> Range: 0x0006 to 0x0C80\n"
+ "\t --max=<interval> Range: 0x0006 to 0x0C80\n"
+ "\t --latency=<range> Slave latency. Range: 0x0000 to 0x03E8\n"
+ "\t --timeout=<time> N * 10ms. Range: 0x000A to 0x0C80\n"
"\n\t min/max range: 7.5ms to 4s. Multiply factor: 1.25ms"
"\n\t timeout range: 100ms to 32.0s. Larger than max interval\n";
static void cmd_lecup(int dev_id, int argc, char **argv)
{
uint16_t handle = 0, min, max, latency, timeout;
- int opt, dd, base;
+ int opt, dd;
+ int options = 0;
/* Aleatory valid values */
min = 0x0C8;
@@ -3320,31 +3317,38 @@ static void cmd_lecup(int dev_id, int argc, char **argv)
timeout = 0x0C80;
for_each_opt(opt, lecup_options, NULL) {
- if (optarg && strncasecmp("0x", optarg, 2) == 0)
- base = 16;
- else
- base = 10;
-
switch (opt) {
case 'H':
- handle = strtoul(optarg, NULL, base);
+ handle = strtoul(optarg, NULL, 0);
break;
case 'm':
- min = strtoul(optarg, NULL, base);
+ min = strtoul(optarg, NULL, 0);
break;
case 'M':
- max = strtoul(optarg, NULL, base);
+ max = strtoul(optarg, NULL, 0);
break;
case 'l':
- latency = strtoul(optarg, NULL, base);
+ latency = strtoul(optarg, NULL, 0);
break;
case 't':
- timeout = strtoul(optarg, NULL, base);
+ timeout = strtoul(optarg, NULL, 0);
break;
default:
printf("%s", lecup_help);
return;
}
+
+ options = 1;
+ }
+
+ if (options == 0) {
+ helper_arg(5, 5, &argc, &argv, lecup_help);
+
+ handle = strtoul(argv[0], NULL, 0);
+ min = strtoul(argv[1], NULL, 0);
+ max = strtoul(argv[2], NULL, 0);
+ latency = strtoul(argv[3], NULL, 0);
+ timeout = strtoul(argv[4], NULL, 0);
}
if (handle == 0) {
diff --git a/tools/hex2hcd.c b/tools/hex2hcd.c
index d9b5d3b2..943531cd 100644
--- a/tools/hex2hcd.c
+++ b/tools/hex2hcd.c
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2012 Canonical
+ * Copyright (C) 2012-2013 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
@@ -25,119 +25,422 @@
#include <config.h>
#endif
-#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+
+static ssize_t process_record(int fd, const char *line, uint16_t *upper_addr)
+{
+ const char *ptr = line + 1;
+ char str[3];
+ size_t len;
+ uint8_t *buf;
+ uint32_t addr;
+ uint8_t sum = 0;
+ int n = 0;
+
+ if (line[0] != ':') {
+ fprintf(stderr, "Invalid record start code (%c)\n", line[0]);
+ return -EINVAL;
+ }
+
+ len = strlen(line);
+ if (len < 11) {
+ fprintf(stderr, "Record information is too short\n");
+ return -EILSEQ;
+ }
-#define RBUF_SIZE 640
+ buf = malloc((len / 2) + 3);
+ if (!buf) {
+ fprintf(stderr, "Failed to allocate memory for record data\n");
+ return -ENOMEM;
+ }
+
+ while (1) {
+ str[0] = *ptr++;
+ str[1] = *ptr++;
+ str[2] = '\0';
+
+ buf[3 + n] = strtol(str, NULL, 16);
+
+ if (*ptr == '\r' || *ptr == '\n')
+ break;
+
+ sum += buf[3 + n++];
+ }
+
+ sum = 0x100 - (sum & 0xff);
+
+ if (n < 4 || buf[3] + 4 != n) {
+ fprintf(stderr, "Record length is not matching data\n");
+ free(buf);
+ return -EILSEQ;
+ }
+
+ if (buf[3 + n] != sum) {
+ fprintf(stderr, "Checksum mismatch\n");
+ free(buf);
+ return -EILSEQ;
+ }
+
+ switch (buf[6]) {
+ case 0x00:
+ addr = (*upper_addr << 16) + (buf[4] << 8) + buf[5];
+
+ buf[0] = 0x4c;
+ buf[1] = 0xfc;
+ buf[2] = n;
+
+ buf[3] = (addr & 0x000000ff);
+ buf[4] = (addr & 0x0000ff00) >> 8;
+ buf[5] = (addr & 0x00ff0000) >> 16;
+ buf[6] = (addr & 0xff000000) >> 24;
+
+ if (write(fd, buf, n + 3) < 0) {
+ perror("Failed to write data record");
+ free(buf);
+ return -errno;
+ }
+ break;
+ case 0x01:
+ buf[0] = 0x4e;
+ buf[1] = 0xfc;
+ buf[2] = 0x04;
+
+ buf[3] = 0xff;
+ buf[4] = 0xff;
+ buf[5] = 0xff;
+ buf[6] = 0xff;
+
+ if (write(fd, buf, 7) < 0) {
+ perror("Failed to write end record");
+ free(buf);
+ return -errno;
+ }
+ break;
+ case 0x04:
+ *upper_addr = (buf[7] << 8) + buf[8];
+ break;
+ default:
+ fprintf(stderr, "Unsupported record type (%02X)\n", buf[3]);
+ free(buf);
+ return -EILSEQ;
+ }
-static unsigned int asc_to_int(char a)
+ free(buf);
+
+ return len;
+}
+
+static void convert_file(const char *input_path, const char *output_path)
{
- if (a >= 'A')
- return (a - 'A') + 10;
- else
- return a - '0';
+ uint16_t upper_addr = 0x0000;
+ size_t line_size = 1024;
+ char line_buffer[line_size];
+ char *path;
+ const char *ptr;
+ FILE *fp;
+ struct stat st;
+ off_t cur = 0;
+ int fd;
+
+ if (output_path) {
+ path = strdup(output_path);
+ if (!path) {
+ perror("Failed to allocate string");
+ return;
+ }
+ } else {
+ ptr = strrchr(input_path, '.');
+ if (ptr) {
+ path = malloc(ptr - input_path + 6);
+ if (!path) {
+ perror("Failed to allocate string");
+ return;
+ }
+ strncpy(path, input_path, ptr - input_path);
+ strcpy(path + (ptr - input_path), ".hcd");
+ } else {
+ if (asprintf(&path, "%s.hcd", input_path) < 0) {
+ perror("Failed to allocate string");
+ return;
+ }
+ }
+ }
+
+ printf("Converting %s to %s\n", input_path, path);
+
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+ free(path);
+
+ if (fd < 0) {
+ perror("Failed to create output file");
+ return;
+ }
+
+ if (stat(input_path, &st) < 0) {
+ fprintf(stderr, "Failed get file size\n");
+ close(fd);
+ return;
+ }
+
+ if (st.st_size == 0) {
+ fprintf(stderr, "Empty file\n");
+ close(fd);
+ return;
+ }
+
+ fp = fopen(input_path, "r");
+ if (!fp) {
+ fprintf(stderr, "Failed to open input file\n");
+ close(fd);
+ return;
+ }
+
+ while (1) {
+ char *str;
+ ssize_t len;
+
+ str = fgets(line_buffer, line_size - 1, fp);
+ if (!str)
+ break;
+
+ len = process_record(fd, str, &upper_addr);
+ if (len < 0)
+ goto done;
+
+ cur += len;
+ }
+
+ if (cur != st.st_size) {
+ fprintf(stderr, "Data length does not match file length\n");
+ goto done;
+ }
+
+done:
+ fclose(fp);
+
+ close(fd);
}
-static unsigned int hex_to_int(const char *h)
+struct ver_data {
+ uint16_t num;
+ char name[20];
+ char major[4];
+ char minor[4];
+ char build[4];
+ struct ver_data *next;
+};
+
+static struct ver_data *ver_list = NULL;
+
+static void ver_parse_file(const char *pathname)
{
- return asc_to_int(*h) * 0x10 + asc_to_int(*(h + 1));
+ struct ver_data *ver, *tmp, *prev;
+ char dummy1[5], dummy2[5];
+
+ if (strlen(pathname) < 7)
+ return;
+
+ if (strncmp(pathname, "BCM", 3))
+ return;
+
+ ver = malloc(sizeof(*ver));
+ if (!ver)
+ return;
+
+ memset(ver, 0, sizeof(*ver));
+
+ if (sscanf(pathname, "%[A-Z0-9]_%3c.%3c.%3c.%4c.%4c.hex",
+ ver->name, ver->major, ver->minor,
+ ver->build, dummy1, dummy2) != 6) {
+ printf("\t/* failed to parse %s */\n", pathname);
+ free(ver);
+ return;
+ }
+
+ ver->num = atoi(ver->build) + (atoi(ver->minor) << 8) +
+ (atoi(ver->major) << 13);
+
+ if (!ver_list) {
+ ver_list = ver;
+ return;
+ }
+
+ for (tmp = ver_list, prev = NULL; tmp; prev = tmp, tmp = tmp->next) {
+ if (ver->num == tmp->num) {
+ free(ver);
+ return;
+ }
+
+ if (ver->num < tmp->num) {
+ if (prev) {
+ prev->next = ver;
+ ver->next = tmp;
+ } else {
+ ver->next = ver_list;
+ ver_list = ver;
+ }
+ return;
+ }
+ }
+
+ prev->next = ver;
}
-static unsigned int lhex_to_int(const char *h)
+static void ver_parse_entry(const char *pathname)
{
- return hex_to_int(h) * 0x100 + hex_to_int(h + 2);
+ struct stat st;
+ int fd;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0) {
+ printf("\t/* failed to open %s */\n", pathname);
+ return;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ printf("\t/* failed to stat %s */\n", pathname);
+ goto done;
+ }
+
+ if (S_ISREG(st.st_mode)) {
+ ver_parse_file(basename(pathname));
+ goto done;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ DIR *dir;
+
+ dir = fdopendir(fd);
+ if (!dir)
+ goto done;
+
+ while (1) {
+ struct dirent *d;
+
+ d = readdir(dir);
+ if (!d)
+ break;
+
+ if (d->d_type == DT_REG)
+ ver_parse_file(d->d_name);
+ }
+
+ closedir(dir);
+ }
+
+done:
+ close(fd);
}
-static int check_sum(const char *str, int len)
+static void ver_print_table(int argc, char *argv[])
{
- unsigned int sum, cal;
- int i;
- sum = hex_to_int(str + len - 2);
- for (cal = 0, i = 1; i < len - 2; i += 2)
- cal += hex_to_int(str + i);
- cal = 0x100 - (cal & 0xFF);
- return sum == cal;
+ struct ver_data *ver;
+
+ printf("static const struct {\n");
+ printf("\tuint16_t ver;\n");
+ printf("\tconst char *str\n");
+ printf("} table[] = {\n");
+
+ if (argc > 0) {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ ver_parse_entry(argv[i]);
+ } else
+ ver_parse_entry(".");
+
+ for (ver = ver_list; ver; ) {
+ struct ver_data *tmp = ver;
+
+ printf("\t{ 0x%4.4x, \"%s\"\t},\t/* %s.%s.%s */\n",
+ ver->num, ver->name,
+ ver->major, ver->minor, ver->build);
+
+ ver = ver->next;
+ free(tmp);
+ }
+
+ printf(" { }\n");
+ printf("};\n");
}
-static int check_hex_line(const char *str, unsigned int len)
+static void usage(void)
{
- if ((str[0] != ':') || (len < 11) || !check_sum(str, len) ||
- (hex_to_int(str + 1) * 2 + 11 != len))
- return 0;
- return 1;
+ printf("Broadcom Bluetooth firmware converter\n"
+ "Usage:\n");
+ printf("\thex2hcd [options] <file>\n");
+ printf("Options:\n"
+ "\t-o, --output <file> Provide firmware output file\n"
+ "\t-h, --help Show help options\n");
}
+static const struct option main_options[] = {
+ { "table", no_argument, NULL, 'T' },
+ { "output", required_argument, NULL, 'o' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
int main(int argc, char *argv[])
{
- unsigned int i, addr = 0;
- FILE *ifp, *ofp;
- char *rbuf;
- ssize_t len;
- size_t buflen;
-
- if (argc != 3) {
- printf("Usage: %s <input hex file> <output file>\n", argv[0]);
- return 0;
- }
-
- ifp = fopen(argv[1], "r");
- ofp = fopen(argv[2], "w");
- if ((ifp == NULL) || (ofp == NULL)) {
- puts("failed to open file.");
- return -EIO;
- }
-
- rbuf = NULL;
- while ((len = getline(&rbuf, &buflen, ifp)) > 0) {
- int type;
- char obuf[7];
- unsigned int dest_addr;
- while ((rbuf[len - 1] == '\r') || (rbuf[len - 1] == '\n'))
- len--;
- printf("%d, %s\n", (int)len, rbuf);
- if (!check_hex_line(rbuf, len))
+ const char *output_path = NULL;
+ bool print_table = false;
+ int i;
+
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "To:vh", main_options, NULL);
+ if (opt < 0)
break;
- type = hex_to_int(rbuf + 7);
- switch (type) {
- case 4:
- addr = lhex_to_int(rbuf + 9) * 0x10000;
- printf("bump addr to 0x%08X\n", addr);
- break;
- case 0:
- dest_addr = addr + lhex_to_int(rbuf + 3);
- obuf[0] = 0x4c;
- obuf[1] = 0xfc;
- obuf[2] = hex_to_int(rbuf + 1) + 4;
- obuf[3] = dest_addr;
- obuf[4] = dest_addr >> 8;
- obuf[5] = dest_addr >> 16;
- obuf[6] = dest_addr >> 24;
- if (fwrite(obuf, 7, 1, ofp) != 1)
- goto output_err;
- for (i = 0; i < hex_to_int(rbuf + 1); i++) {
- obuf[0] = hex_to_int(rbuf + 9 + i * 2);
- if (fwrite(obuf, 1, 1, ofp) != 1)
- goto output_err;
- }
- break;
- case 1:
- if (fwrite("\x4e\xfc\x04\xff\xff\xff\xff", 7, 1, ofp) != 1)
- goto output_err;
- goto end;
- default:
- return -EINVAL;
+
+ switch (opt) {
+ case 'T':
+ print_table = true;
+ break;
+ case 'o':
+ output_path = optarg;
+ break;
+ case 'v':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
}
}
- puts("hex file formatting error");
- return -EINVAL;
+ if (print_table) {
+ ver_print_table(argc - optind, argv + optind);
+ return EXIT_SUCCESS;
+ }
-output_err:
- puts("error on writing output file");
- return -EIO;
+ if (argc - optind < 1) {
+ fprintf(stderr, "No input firmware files provided\n");
+ return EXIT_FAILURE;
+ }
-end:
- return 0;
-}
+ if (output_path && argc - optind > 1) {
+ fprintf(stderr, "Only single input firmware supported\n");
+ return EXIT_FAILURE;
+ }
+
+ for (i = optind; i < argc; i++)
+ convert_file(argv[i], output_path);
+ return EXIT_SUCCESS;
+}
diff --git a/tools/hid2hci.1 b/tools/hid2hci.1
index 8c5d520f..c6876a30 100644
--- a/tools/hid2hci.1
+++ b/tools/hid2hci.1
@@ -32,7 +32,7 @@ mode and back.
.B --mode= [hid, hci]
Sets the mode to switch the device into
.TP
-.B --method= [csr, logitech-hid, dell]
+.B --method= [csr, csr2, logitech-hid, dell]
Which vendor method to use for switching the device.
.TP
.B --devpath=
diff --git a/tools/hid2hci.c b/tools/hid2hci.c
index a183bfa3..8f060f25 100644
--- a/tools/hid2hci.c
+++ b/tools/hid2hci.c
@@ -59,7 +59,7 @@ struct usbfs_ctrltransfer {
uint16_t wIndex;
uint16_t wLength;
uint32_t timeout; /* in milliseconds */
- void *data; /* pointer to data */
+ const void *data; /* pointer to data */
};
@@ -77,7 +77,7 @@ struct usbfs_disconnect{
static int control_message(int fd, int requesttype, int request,
int value, int index,
- char *bytes, int size, int timeout)
+ const uint8_t *bytes, int size, int timeout)
{
struct usbfs_ctrltransfer transfer;
@@ -119,6 +119,52 @@ static int usb_switch_csr(int fd, enum mode mode)
return err;
}
+static int usb_switch_csr2(int fd, enum mode mode)
+{
+ int err = 0;
+ struct usbfs_disconnect disconnect;
+ const uint8_t report[] = {
+ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ switch (mode) {
+ case HCI:
+ /* send report as is */
+ disconnect.interface = 0;
+ disconnect.flags = USBFS_DISCONNECT_EXCEPT_DRIVER;
+ strcpy(disconnect.driver, "usbfs");
+
+ if (ioctl(fd, USBFS_IOCTL_DISCONNECT, &disconnect) < 0) {
+ fprintf(stderr, "Can't claim interface: %s (%d)\n",
+ strerror(errno), errno);
+ return -1;
+ }
+
+ /* Set_report request with
+ * report id: 0x01, report type: feature (0x03)
+ * on interface 0
+ */
+ err = control_message(fd,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ USB_REQ_SET_CONFIGURATION,
+ 0x01 | (0x03 << 8),
+ 0, report, sizeof(report), 5000);
+ /* unable to detect whether the previous state
+ * already was HCI (EALREADY)
+ */
+ break;
+ case HID:
+ /* currently unknown how to switch to HID */
+ fprintf(stderr,
+ "csr2: Switching to hid mode is not implemented\n");
+ err = -1;
+ break;
+ }
+
+ return err;
+}
+
static int hid_logitech_send_report(int fd, const char *buf, size_t size)
{
struct hiddev_report_info rinfo;
@@ -180,7 +226,7 @@ out:
static int usb_switch_dell(int fd, enum mode mode)
{
- char report[] = { 0x7f, 0x00, 0x00, 0x00 };
+ uint8_t report[] = { 0x7f, 0x00, 0x00, 0x00 };
struct usbfs_disconnect disconnect;
int err;
@@ -258,7 +304,7 @@ static void usage(const char *error)
printf("Usage: hid2hci [options]\n"
" --mode= mode to switch to [hid|hci] (default hci)\n"
" --devpath= sys device path\n"
- " --method= method to use to switch [csr|logitech-hid|dell]\n"
+ " --method= method to use to switch [csr|csr2|logitech-hid|dell]\n"
" --help\n\n");
}
@@ -311,6 +357,9 @@ int main(int argc, char *argv[])
if (!strcmp(optarg, "csr")) {
method = METHOD_CSR;
usb_switch = usb_switch_csr;
+ } else if (!strcmp(optarg, "csr2")) {
+ method = METHOD_CSR;
+ usb_switch = usb_switch_csr2;
} else if (!strcmp(optarg, "logitech-hid")) {
method = METHOD_LOGITECH_HID;
} else if (!strcmp(optarg, "dell")) {
diff --git a/tools/hwdb.c b/tools/hwdb.c
index 3b712e1d..8a42dce3 100644
--- a/tools/hwdb.c
+++ b/tools/hwdb.c
@@ -27,7 +27,7 @@
#include <stdio.h>
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
static const struct {
uint16_t vendor;
diff --git a/tools/ibeacon.c b/tools/ibeacon.c
index 28967de3..9d48e66b 100644
--- a/tools/ibeacon.c
+++ b/tools/ibeacon.c
@@ -36,8 +36,8 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include "monitor/mainloop.h"
#include "monitor/bt.h"
+#include "src/shared/mainloop.h"
#include "src/shared/timeout.h"
#include "src/shared/util.h"
#include "src/shared/hci.h"
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index cf0fa381..7f03591a 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -82,6 +82,9 @@ struct l2cap_data {
const void *pin;
uint8_t client_pin_len;
const void *client_pin;
+
+ bool addr_type_avail;
+ uint8_t addr_type;
};
static void mgmt_debug(const char *str, void *user_data)
@@ -441,6 +444,12 @@ static const struct l2cap_data le_client_connect_reject_test_1 = {
.expect_err = ECONNREFUSED,
};
+static const struct l2cap_data le_client_connect_reject_test_2 = {
+ .client_psm = 0x0080,
+ .addr_type_avail = true,
+ .addr_type = BDADDR_LE_PUBLIC,
+};
+
static const struct l2cap_data le_client_connect_nval_psm_test = {
.client_psm = 0x0080,
.expect_err = ECONNREFUSED,
@@ -943,6 +952,7 @@ failed:
static int create_l2cap_sock(struct test_data *data, uint16_t psm,
uint16_t cid, int sec_level)
{
+ const struct l2cap_data *l2data = data->test_data;
const uint8_t *master_bdaddr;
struct sockaddr_l2 addr;
int sk, err;
@@ -968,7 +978,10 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
addr.l2_psm = htobs(psm);
addr.l2_cid = htobs(cid);
bacpy(&addr.l2_bdaddr, (void *) master_bdaddr);
- if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+ if (l2data && l2data->addr_type_avail)
+ addr.l2_bdaddr_type = l2data->addr_type;
+ else if (data->hciemu_type == HCIEMU_TYPE_LE)
addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
else
addr.l2_bdaddr_type = BDADDR_BREDR;
@@ -1003,6 +1016,7 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
uint16_t cid)
{
+ const struct l2cap_data *l2data = data->test_data;
const uint8_t *client_bdaddr;
struct sockaddr_l2 addr;
int err;
@@ -1018,7 +1032,10 @@ static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
bacpy(&addr.l2_bdaddr, (void *) client_bdaddr);
addr.l2_psm = htobs(psm);
addr.l2_cid = htobs(cid);
- if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+ if (l2data && l2data->addr_type_avail)
+ addr.l2_bdaddr_type = l2data->addr_type;
+ else if (data->hciemu_type == HCIEMU_TYPE_LE)
addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
else
addr.l2_bdaddr_type = BDADDR_BREDR;
@@ -1084,6 +1101,27 @@ static void test_connect(const void *test_data)
tester_print("Connect in progress");
}
+static void test_connect_reject(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ int sk;
+
+ sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+ if (sk < 0) {
+ tester_test_failed();
+ return;
+ }
+
+ if (connect_l2cap_sock(data, sk, l2data->client_psm,
+ l2data->cid) < 0)
+ tester_test_passed();
+ else
+ tester_test_failed();
+
+ close(sk);
+}
+
static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -1396,6 +1434,9 @@ int main(int argc, char *argv[])
test_l2cap_le("L2CAP LE Client - Command Reject",
&le_client_connect_reject_test_1,
setup_powered_client, test_connect);
+ test_l2cap_bredr("L2CAP LE Client - Connection Reject",
+ &le_client_connect_reject_test_2,
+ setup_powered_client, test_connect_reject);
test_l2cap_le("L2CAP LE Client - Invalid PSM",
&le_client_connect_nval_psm_test,
setup_powered_client, test_connect);
diff --git a/tools/l2ping.c b/tools/l2ping.c
index 3dd437e8..fa97fe30 100644
--- a/tools/l2ping.c
+++ b/tools/l2ping.c
@@ -38,10 +38,10 @@
#include <poll.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
/* Defaults */
static bdaddr_t bdaddr;
diff --git a/tools/l2test.c b/tools/l2test.c
index a0636b97..83c5cbde 100644
--- a/tools/l2test.c
+++ b/tools/l2test.c
@@ -42,10 +42,10 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
#include "src/shared/util.h"
diff --git a/tools/mcaptest.c b/tools/mcaptest.c
index 42734ebf..30928737 100644
--- a/tools/mcaptest.c
+++ b/tools/mcaptest.c
@@ -30,12 +30,12 @@
#include <getopt.h>
#include <unistd.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
#include <glib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
#include "btio/btio.h"
#include "lib/l2cap.h"
#include "profiles/health/mcap.h"
@@ -71,20 +71,27 @@ static gboolean no_close = FALSE;
#define REQ_CLOCK_ACC 0x1400
-static void mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+static void mdl_close(struct mcap_mdl *mdl)
{
int fd = -1;
printf("%s\n", __func__);
- if (mdl_disconnect && mdl_disconnect_timeout >= 0) {
+ if (mdl_disconnect_timeout >= 0)
sleep(mdl_disconnect_timeout);
- fd = mcap_mdl_get_fd(mdl);
+ fd = mcap_mdl_get_fd(mdl);
- if (fd > 0)
- close(fd);
- }
+ if (fd > 0)
+ close(fd);
+}
+
+static void mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+{
+ printf("%s\n", __func__);
+
+ if (mdl_disconnect)
+ mdl_close(mdl);
}
static void mdl_closed_cb(struct mcap_mdl *mdl, void *data)
@@ -94,7 +101,13 @@ static void mdl_closed_cb(struct mcap_mdl *mdl, void *data)
if (mcl_disconnect && mcl_disconnect_timeout >= 0) {
sleep(mcl_disconnect_timeout);
+ printf("Closing MCAP communication link\n");
mcap_close_mcl(mcl, TRUE);
+
+ if (no_close)
+ return;
+
+ g_main_loop_quit(mloop);
}
}
@@ -102,6 +115,10 @@ static void mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
{
/* TODO */
printf("%s\n", __func__);
+
+ /* Disconnecting MDL latency timeout */
+ if (mdl_disconnect_timeout >= 0)
+ sleep(mdl_disconnect_timeout);
}
static void mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
@@ -152,7 +169,7 @@ static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
{
/* TODO */
- printf("MCL disconnected\n");
+ printf("%s\n", __func__);
if (no_close)
return;
@@ -163,14 +180,19 @@ static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
{
/* TODO */
- printf("MCL uncached unsupported\n");
+ printf("%s\n", __func__);
}
static void connect_mdl_cb(struct mcap_mdl *mdl, GError *gerr, gpointer data)
{
mdlid = mcap_mdl_get_mdlid(mdl);
- printf("MDL %d connected\n", mdlid);
+ printf("%s\n", __func__);
+
+ if (mdlid == MCAP_MDLID_RESERVED)
+ printf("MCAP mdlid is reserved");
+ else
+ printf("MDL %d connected\n", mdlid);
}
static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
@@ -178,6 +200,8 @@ static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
{
GError *err = NULL;
+ printf("%s\n", __func__);
+
if (gerr) {
printf("MDL error: %s\n", gerr->message);
@@ -234,6 +258,7 @@ static void trigger_mdl_action(int mode)
}
if (mode == MODE_CONNECT) {
+ printf("Creating MCAP Data End Point\n");
mcap_create_mdl(mcl, 1, 0, create_mdl_cb, NULL, NULL, &gerr);
if (gerr) {
printf("Could not connect MDL: %s\n", gerr->message);
@@ -286,6 +311,7 @@ static void create_mcl_cb(struct mcap_mcl *mcap_mcl, GError *err, gpointer data)
mcl = mcap_mcl_ref(mcap_mcl);
trigger_mdl_action(data_mode);
}
+
static void usage(void)
{
printf("mcaptest - MCAP testing ver %s\n", VERSION);
@@ -293,10 +319,12 @@ static void usage(void)
"\tmcaptest <control_mode> <data_mode> [options]\n");
printf("Control Link Mode:\n"
"\t-c connect <dst_addr>\n"
+ "\t-b close control link after closing data link\n"
"\t-e <timeout> disconnect MCL and quit after MDL is closed\n"
"\t-g send clock sync capability request if MCL connected\n");
printf("Data Link Mode:\n"
"\t-d connect\n"
+ "\t-a close data link immediately after being connected"
"\t-f <timeout> disconnect MDL after it's connected\n"
"\t-u send \'Unavailable\' on first MDL connection request\n");
printf("Options:\n"
@@ -313,6 +341,8 @@ static struct option main_options[] = {
{ "disconnect_cl", 1, 0, 'e' },
{ "synccap_req", 0, 0, 'g' },
{ "connect_dl", 0, 0, 'd' },
+ { "disconnect_da", 0, 0, 'a' },
+ { "disconnect_ca", 0, 0, 'b' },
{ "disconnect_dl", 1, 0, 'f' },
{ "unavailable_dl", 0, 0, 'u' },
{ "no exit mcl dis/err",0, 0, 'n' },
@@ -320,6 +350,7 @@ static struct option main_options[] = {
{ "data_ch", 1, 0, 'D' },
{ 0, 0, 0, 0 }
};
+
int main(int argc, char *argv[])
{
GError *err = NULL;
@@ -337,7 +368,7 @@ int main(int argc, char *argv[])
exit(1);
}
- while ((opt = getopt_long(argc, argv, "+i:c:C:D:e:f:dghun",
+ while ((opt = getopt_long(argc, argv, "+i:c:C:D:e:f:dghunab",
main_options, NULL)) != EOF) {
switch (opt) {
case 'i':
@@ -359,14 +390,22 @@ int main(int argc, char *argv[])
break;
- case 'e':
+ case 'a':
+ mdl_disconnect = TRUE;
+
+ break;
+
+ case 'b':
mcl_disconnect = TRUE;
+
+ break;
+
+ case 'e':
mcl_disconnect_timeout = atoi(optarg);
break;
case 'f':
- mdl_disconnect = TRUE;
mdl_disconnect_timeout = atoi(optarg);
break;
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 790426ad..e5fb8894 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -56,6 +56,7 @@ struct test_data {
unsigned int mgmt_settings_id;
unsigned int mgmt_alt_settings_id;
unsigned int mgmt_alt_ev_id;
+ unsigned int mgmt_discov_ev_id;
uint8_t mgmt_version;
uint16_t mgmt_revision;
uint16_t mgmt_index;
@@ -310,7 +311,7 @@ static void test_condition_complete(struct test_data *data)
user->test_data = data; \
user->expected_version = 0x08; \
user->expected_manufacturer = 0x003f; \
- user->expected_supported_settings = 0x00003fff; \
+ user->expected_supported_settings = 0x0000bfff; \
user->initial_settings = 0x00000080; \
user->unmet_conditions = 0; \
tester_add_full(name, data, \
@@ -348,7 +349,7 @@ static void test_condition_complete(struct test_data *data)
user->test_data = data; \
user->expected_version = 0x08; \
user->expected_manufacturer = 0x003f; \
- user->expected_supported_settings = 0x00003e1b; \
+ user->expected_supported_settings = 0x0000be1b; \
user->initial_settings = 0x00000200; \
user->unmet_conditions = 0; \
tester_add_full(name, data, \
@@ -406,6 +407,8 @@ struct generic_data {
bool client_enable_sc;
bool expect_sc_key;
bool force_power_off;
+ bool addr_type_avail;
+ uint8_t addr_type;
};
static const char dummy_data[] = { 0x00 };
@@ -2395,7 +2398,10 @@ static const void *pair_device_send_param_func(uint16_t *len)
static uint8_t param[8];
memcpy(param, hciemu_get_client_bdaddr(data->hciemu), 6);
- if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+ if (test->addr_type_avail)
+ param[6] = test->addr_type;
+ else if (data->hciemu_type == HCIEMU_TYPE_LE)
param[6] = 0x01; /* Address type */
else
param[6] = 0x00; /* Address type */
@@ -2409,10 +2415,14 @@ static const void *pair_device_send_param_func(uint16_t *len)
static const void *pair_device_expect_param_func(uint16_t *len)
{
struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
static uint8_t param[7];
memcpy(param, hciemu_get_client_bdaddr(data->hciemu), 6);
- if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+ if (test->addr_type_avail)
+ param[6] = test->addr_type;
+ else if (data->hciemu_type == HCIEMU_TYPE_LE)
param[6] = 0x01; /* Address type */
else
param[6] = 0x00; /* Address type */
@@ -2501,6 +2511,52 @@ static const void *client_bdaddr_param_func(uint8_t *len)
return bdaddr;
}
+static const struct generic_data pair_device_not_supported_test_1 = {
+ .setup_settings = settings_powered_bondable,
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_func = pair_device_send_param_func,
+ .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+ .expect_func = pair_device_expect_param_func,
+ .addr_type_avail = true,
+ .addr_type = BDADDR_BREDR,
+};
+
+static const struct generic_data pair_device_not_supported_test_2 = {
+ .setup_settings = settings_powered_bondable,
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_func = pair_device_send_param_func,
+ .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+ .expect_func = pair_device_expect_param_func,
+ .addr_type_avail = true,
+ .addr_type = BDADDR_LE_PUBLIC,
+};
+
+static uint16_t settings_powered_bondable_le[] = { MGMT_OP_SET_LE,
+ MGMT_OP_SET_BONDABLE,
+ MGMT_OP_SET_POWERED,
+ 0 };
+
+static const struct generic_data pair_device_reject_transport_not_enabled_1 = {
+ .setup_settings = settings_powered_bondable_le,
+ .setup_nobredr = true,
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_func = pair_device_send_param_func,
+ .expect_status = MGMT_STATUS_REJECTED,
+ .expect_func = pair_device_expect_param_func,
+ .addr_type_avail = true,
+ .addr_type = BDADDR_BREDR,
+};
+
+static const struct generic_data pair_device_reject_transport_not_enabled_2 = {
+ .setup_settings = settings_powered_bondable,
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_func = pair_device_send_param_func,
+ .expect_status = MGMT_STATUS_REJECTED,
+ .expect_func = pair_device_expect_param_func,
+ .addr_type_avail = true,
+ .addr_type = BDADDR_LE_PUBLIC,
+};
+
static const struct generic_data pair_device_reject_test_1 = {
.setup_settings = settings_powered_bondable,
.send_opcode = MGMT_OP_PAIR_DEVICE,
@@ -2833,6 +2889,25 @@ static const struct generic_data pair_device_smp_bredr_test_1 = {
.client_io_cap = 0x03, /* NoInputNoOutput */
};
+static const struct generic_data pair_device_smp_bredr_test_2 = {
+ .setup_settings = settings_powered_sc_bondable_le_ssp,
+ .client_enable_ssp = true,
+ .client_enable_le = true,
+ .client_enable_sc = true,
+ .expect_sc_key = true,
+ .send_opcode = MGMT_OP_PAIR_DEVICE,
+ .send_func = pair_device_send_param_func,
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_func = pair_device_expect_param_func,
+ .expect_alt_ev = MGMT_EV_NEW_LONG_TERM_KEY,
+ .expect_alt_ev_len = sizeof(struct mgmt_ev_new_long_term_key),
+ .verify_alt_ev_func = verify_ltk,
+ .expect_hci_command = BT_HCI_CMD_USER_CONFIRM_REQUEST_REPLY,
+ .expect_hci_func = client_bdaddr_param_func,
+ .io_cap = 0x01, /* DisplayYesNo */
+ .client_io_cap = 0x01, /* DisplayYesNo */
+};
+
static const struct generic_data pair_device_le_reject_test_1 = {
.setup_settings = settings_powered_bondable,
.io_cap = 0x02, /* KeyboardOnly */
@@ -3021,6 +3096,44 @@ static const struct generic_data pairing_acceptor_ssp_4 = {
.client_auth_req = 0x02, /* Dedicated Bonding - No MITM */
};
+static uint16_t settings_powered_sc_bondable_connectable_le_ssp[] = {
+ MGMT_OP_SET_BONDABLE,
+ MGMT_OP_SET_CONNECTABLE,
+ MGMT_OP_SET_LE,
+ MGMT_OP_SET_SSP,
+ MGMT_OP_SET_SECURE_CONN,
+ MGMT_OP_SET_POWERED,
+ 0 };
+
+static const struct generic_data pairing_acceptor_smp_bredr_1 = {
+ .setup_settings = settings_powered_sc_bondable_connectable_le_ssp,
+ .client_enable_ssp = true,
+ .client_enable_le = true,
+ .client_enable_sc = true,
+ .expect_sc_key = true,
+ .expect_alt_ev = MGMT_EV_NEW_LONG_TERM_KEY,
+ .expect_alt_ev_len = sizeof(struct mgmt_ev_new_long_term_key),
+ .verify_alt_ev_func = verify_ltk,
+ .just_works = true,
+ .io_cap = 0x03, /* NoInputNoOutput */
+ .client_io_cap = 0x03, /* No InputNoOutput */
+ .client_auth_req = 0x00, /* No Bonding - No MITM */
+};
+
+static const struct generic_data pairing_acceptor_smp_bredr_2 = {
+ .setup_settings = settings_powered_sc_bondable_connectable_le_ssp,
+ .client_enable_ssp = true,
+ .client_enable_le = true,
+ .client_enable_sc = true,
+ .expect_sc_key = true,
+ .expect_alt_ev = MGMT_EV_NEW_LONG_TERM_KEY,
+ .expect_alt_ev_len = sizeof(struct mgmt_ev_new_long_term_key),
+ .verify_alt_ev_func = verify_ltk,
+ .io_cap = 0x01, /* DisplayYesNo */
+ .client_io_cap = 0x01, /* DisplayYesNo */
+ .client_auth_req = 0x02, /* Dedicated Bonding - No MITM */
+};
+
static uint16_t settings_powered_bondable_connectable_advertising[] = {
MGMT_OP_SET_BONDABLE,
MGMT_OP_SET_CONNECTABLE,
@@ -3160,12 +3273,27 @@ static const struct generic_data unblock_device_invalid_param_test_1 = {
static const char set_static_addr_valid_param[] = {
0x11, 0x22, 0x33, 0x44, 0x55, 0xc0 };
+static const char set_static_addr_settings[] = { 0x00, 0x82, 0x00, 0x00 };
static const struct generic_data set_static_addr_success_test = {
.send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
.send_param = set_static_addr_valid_param,
.send_len = sizeof(set_static_addr_valid_param),
.expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = set_static_addr_settings,
+ .expect_len = sizeof(set_static_addr_settings),
+ .expect_settings_set = MGMT_SETTING_STATIC_ADDRESS,
+};
+
+static const char set_static_addr_settings_dual[] = { 0x80, 0x00, 0x00, 0x00 };
+
+static const struct generic_data set_static_addr_success_test_2 = {
+ .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
+ .send_param = set_static_addr_valid_param,
+ .send_len = sizeof(set_static_addr_valid_param),
+ .expect_status = MGMT_STATUS_SUCCESS,
+ .expect_param = set_static_addr_settings_dual,
+ .expect_len = sizeof(set_static_addr_settings_dual),
};
static const struct generic_data set_static_addr_failure_test = {
@@ -3176,6 +3304,14 @@ static const struct generic_data set_static_addr_failure_test = {
.expect_status = MGMT_STATUS_REJECTED,
};
+static const struct generic_data set_static_addr_failure_test_2 = {
+ .setup_settings = settings_powered,
+ .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
+ .send_param = set_static_addr_valid_param,
+ .send_len = sizeof(set_static_addr_valid_param),
+ .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+};
+
static const char set_scan_params_valid_param[] = { 0x60, 0x00, 0x30, 0x00 };
static const struct generic_data set_scan_params_success_test = {
@@ -3706,10 +3842,9 @@ static void discovering_event(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
struct test_data *data = tester_get_data();
- unsigned int id = PTR_TO_UINT(user_data);
const struct mgmt_ev_discovering *ev = param;
- mgmt_unregister(data->mgmt, id);
+ mgmt_unregister(data->mgmt, data->mgmt_discov_ev_id);
if (length != sizeof(*ev)) {
tester_warn("Incorrect discovering event length");
@@ -3743,10 +3878,11 @@ static void setup_start_discovery(const void *test_data)
const struct generic_data *test = data->test_data;
const void *send_param = test->setup_send_param;
uint16_t send_len = test->setup_send_len;
- unsigned int id = 0;
+ unsigned int id;
id = mgmt_register(data->mgmt, MGMT_EV_DISCOVERING, data->mgmt_index,
- discovering_event, UINT_TO_PTR(id), NULL);
+ discovering_event, NULL, NULL);
+ data->mgmt_discov_ev_id = id;
mgmt_send(data->mgmt, test->setup_send_opcode, data->mgmt_index,
send_len, send_param, setup_discovery_callback,
@@ -5006,6 +5142,18 @@ int main(int argc, char *argv[])
test_bredrle("Pair Device - Power off 1",
&pair_device_power_off_test_1,
NULL, test_command_generic);
+ test_le("Pair Device - Incorrect transport reject 1",
+ &pair_device_not_supported_test_1,
+ NULL, test_command_generic);
+ test_bredr("Pair Device - Incorrect transport reject 2",
+ &pair_device_not_supported_test_2,
+ NULL, test_command_generic);
+ test_bredrle("Pair Device - Reject on not enabled transport 1",
+ &pair_device_reject_transport_not_enabled_1,
+ NULL, test_command_generic);
+ test_bredrle("Pair Device - Reject on not enabled transport 2",
+ &pair_device_reject_transport_not_enabled_2,
+ NULL, test_command_generic);
test_bredrle("Pair Device - Invalid Parameters 1",
&pair_device_invalid_param_test_1,
NULL, test_command_generic);
@@ -5060,9 +5208,12 @@ int main(int argc, char *argv[])
test_bredrle("Pair Device - SSP Non-bondable 1",
&pair_device_ssp_nonbondable_1,
NULL, test_command_generic);
- test_bredrle("Pair Device - SMP over BR/EDR Just-Works Success 1",
+ test_bredrle("Pair Device - SMP over BR/EDR Success 1",
&pair_device_smp_bredr_test_1,
NULL, test_command_generic);
+ test_bredrle("Pair Device - SMP over BR/EDR Success 2",
+ &pair_device_smp_bredr_test_2,
+ NULL, test_command_generic);
test_le("Pair Device - LE Success 1",
&pair_device_le_success_test_1,
NULL, test_command_generic);
@@ -5109,6 +5260,12 @@ int main(int argc, char *argv[])
test_bredrle("Pairing Acceptor - SSP 4",
&pairing_acceptor_ssp_4, setup_pairing_acceptor,
test_pairing_acceptor);
+ test_bredrle("Pairing Acceptor - SMP over BR/EDR 1",
+ &pairing_acceptor_smp_bredr_1,
+ setup_pairing_acceptor, test_pairing_acceptor);
+ test_bredrle("Pairing Acceptor - SMP over BR/EDR 2",
+ &pairing_acceptor_smp_bredr_2,
+ setup_pairing_acceptor, test_pairing_acceptor);
test_le("Pairing Acceptor - LE 1",
&pairing_acceptor_le_1, setup_pairing_acceptor,
test_pairing_acceptor);
@@ -5147,12 +5304,18 @@ int main(int argc, char *argv[])
&unblock_device_invalid_param_test_1,
NULL, test_command_generic);
- test_bredrle("Set Static Address - Success",
+ test_le("Set Static Address - Success 1",
&set_static_addr_success_test,
NULL, test_command_generic);
- test_bredrle("Set Static Address - Failure",
+ test_bredrle("Set Static Address - Success 2",
+ &set_static_addr_success_test_2,
+ NULL, test_command_generic);
+ test_bredrle("Set Static Address - Failure 1",
&set_static_addr_failure_test,
NULL, test_command_generic);
+ test_bredr("Set Static Address - Failure 2",
+ &set_static_addr_failure_test_2,
+ NULL, test_command_generic);
test_bredrle("Set Scan Parameters - Success",
&set_scan_params_success_test,
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
deleted file mode 100755
index c94330cb..00000000
--- a/tools/mpris-player.c
+++ /dev/null
@@ -1,2593 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <getopt.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include <dbus/dbus.h>
-#include <glib.h>
-#include <gdbus/gdbus.h>
-
-#define BLUEZ_BUS_NAME "org.bluez"
-#define BLUEZ_PATH "/org/bluez"
-#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
-#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
-#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
-#define BLUEZ_MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1"
-#define BLUEZ_MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1"
-#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
-#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
-#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
-#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
-#define MPRIS_TRACKLIST_INTERFACE "org.mpris.MediaPlayer2.TrackList"
-#define MPRIS_PLAYLISTS_INTERFACE "org.mpris.MediaPlayer2.Playlists"
-#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
-#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
-
-static GMainLoop *main_loop;
-static GDBusProxy *adapter = NULL;
-static DBusConnection *sys = NULL;
-static DBusConnection *session = NULL;
-static GDBusClient *client = NULL;
-static GSList *players = NULL;
-static GSList *transports = NULL;
-
-static gboolean option_version = FALSE;
-static gboolean option_export = FALSE;
-
-struct tracklist {
- GDBusProxy *proxy;
- GSList *items;
-};
-
-struct player {
- char *bus_name;
- DBusConnection *conn;
- GDBusProxy *proxy;
- GDBusProxy *folder;
- GDBusProxy *device;
- GDBusProxy *transport;
- GDBusProxy *playlist;
- struct tracklist *tracklist;
-};
-
-typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
- DBusMessageIter *metadata);
-
-static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
- void *val);
-
-static void sig_term(int sig)
-{
- g_main_loop_quit(main_loop);
-}
-
-static DBusMessage *get_all(DBusConnection *conn, const char *name)
-{
- DBusMessage *msg, *reply;
- DBusError err;
- const char *iface = MPRIS_PLAYER_INTERFACE;
-
- msg = dbus_message_new_method_call(name, MPRIS_PLAYER_PATH,
- DBUS_INTERFACE_PROPERTIES, "GetAll");
- if (!msg) {
- fprintf(stderr, "Can't allocate new method call\n");
- return NULL;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface,
- DBUS_TYPE_INVALID);
-
- dbus_error_init(&err);
-
- reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
- dbus_message_unref(msg);
-
- if (!reply) {
- if (dbus_error_is_set(&err)) {
- fprintf(stderr, "%s\n", err.message);
- dbus_error_free(&err);
- }
- return NULL;
- }
-
- return reply;
-}
-
-static void append_variant(DBusMessageIter *iter, int type, void *val)
-{
- DBusMessageIter value;
- char sig[2] = { type, '\0' };
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
-
- dbus_message_iter_append_basic(&value, type, val);
-
- 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_array(DBusMessageIter *dict, const char *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, DBUS_TYPE_STRING, &key);
-
- append_array_variant(&entry, type, val, n_elements);
-
- dbus_message_iter_close_container(dict, &entry);
-}
-
-static void append_basic(DBusMessageIter *base, DBusMessageIter *iter,
- int type)
-{
- const void *value;
-
- dbus_message_iter_get_basic(iter, &value);
- dbus_message_iter_append_basic(base, type, &value);
-}
-
-static void append_iter(DBusMessageIter *base, DBusMessageIter *iter);
-static void append_container(DBusMessageIter *base, DBusMessageIter *iter,
- int type)
-{
- DBusMessageIter iter_sub, base_sub;
- char *sig;
-
- dbus_message_iter_recurse(iter, &iter_sub);
-
- switch (type) {
- case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_VARIANT:
- sig = dbus_message_iter_get_signature(&iter_sub);
- break;
- default:
- sig = NULL;
- break;
- }
-
- dbus_message_iter_open_container(base, type, sig, &base_sub);
-
- if (sig != NULL)
- dbus_free(sig);
-
- append_iter(&base_sub, &iter_sub);
-
- dbus_message_iter_close_container(base, &base_sub);
-}
-
-static void append_iter(DBusMessageIter *base, DBusMessageIter *iter)
-{
- int type;
-
- while ((type = dbus_message_iter_get_arg_type(iter)) !=
- DBUS_TYPE_INVALID) {
- if (dbus_type_is_basic(type))
- append_basic(base, iter, type);
- else if (dbus_type_is_container(type))
- append_container(base, iter, type);
-
- dbus_message_iter_next(iter);
- }
-}
-
-static void dict_append_iter(DBusMessageIter *dict, const char *key,
- DBusMessageIter *iter)
-{
- DBusMessageIter entry;
-
- dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
-
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
- append_iter(&entry, iter);
-
- dbus_message_iter_close_container(dict, &entry);
-}
-
-static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
- DBusMessageIter *metadata)
-{
- if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
- return -EINVAL;
-
- dict_append_iter(metadata, key, entry);
-
- return 0;
-}
-
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
- parse_metadata_func func)
-{
- DBusMessageIter dict;
- int ctype;
-
- ctype = dbus_message_iter_get_arg_type(args);
- if (ctype != DBUS_TYPE_ARRAY)
- return -EINVAL;
-
- dbus_message_iter_recurse(args, &dict);
-
- while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
- DBUS_TYPE_INVALID) {
- DBusMessageIter entry;
- const char *key;
-
- if (ctype != DBUS_TYPE_DICT_ENTRY)
- return -EINVAL;
-
- dbus_message_iter_recurse(&dict, &entry);
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
- return -EINVAL;
-
- dbus_message_iter_get_basic(&entry, &key);
- dbus_message_iter_next(&entry);
-
- if (func(&entry, key, metadata) < 0)
- return -EINVAL;
-
- dbus_message_iter_next(&dict);
- }
-
- return 0;
-}
-
-static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
- parse_metadata_func func)
-{
- DBusMessageIter value, metadata;
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
- &value);
-
- dbus_message_iter_open_container(&value, 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, &metadata);
-
- parse_metadata(dict, &metadata, func);
-
- dbus_message_iter_close_container(&value, &metadata);
- dbus_message_iter_close_container(iter, &value);
-}
-
-static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
- void *val)
-{
- DBusMessageIter entry;
-
- if (type == DBUS_TYPE_STRING) {
- const char *str = *((const char **) val);
- if (str == NULL)
- return;
- }
-
- dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
-
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
- if (strcasecmp(key, "Metadata") == 0)
- append_metadata(&entry, val, parse_metadata_entry);
- else
- append_variant(&entry, type, val);
-
- dbus_message_iter_close_container(dict, &entry);
-}
-
-static char *sender2path(const char *sender)
-{
- char *path;
-
- path = g_strconcat("/", sender, NULL);
- return g_strdelimit(path, ":.", '_');
-}
-
-static void copy_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *msg = user_data;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusMessage *copy;
- DBusMessageIter args, iter;
-
- copy = dbus_message_new_method_return(msg);
- if (copy == NULL) {
- dbus_message_unref(reply);
- return;
- }
-
- dbus_message_iter_init_append(copy, &iter);
-
- if (!dbus_message_iter_init(reply, &args))
- goto done;
-
- append_iter(&iter, &args);
-
- dbus_connection_send(sys, copy, NULL);
-
-done:
- dbus_message_unref(copy);
- dbus_message_unref(reply);
-}
-
-static DBusHandlerResult player_message(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- char *owner = data;
- DBusMessage *copy;
- DBusMessageIter args, iter;
- DBusPendingCall *call;
-
- dbus_message_iter_init(msg, &args);
-
- copy = dbus_message_new_method_call(owner,
- MPRIS_PLAYER_PATH,
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- if (copy == NULL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- dbus_message_iter_init_append(copy, &iter);
- append_iter(&iter, &args);
-
- if (!dbus_connection_send_with_reply(session, copy, &call, -1))
- goto done;
-
- dbus_message_ref(msg);
- dbus_pending_call_set_notify(call, copy_reply, msg, NULL);
- dbus_pending_call_unref(call);
-
-done:
- dbus_message_unref(copy);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static struct player *find_player_by_bus_name(const char *name)
-{
- GSList *l;
-
- for (l = players; l; l = l->next) {
- struct player *player = l->data;
-
- if (strcmp(player->bus_name, name) == 0)
- return player;
- }
-
- return NULL;
-}
-
-static const DBusObjectPathVTable player_table = {
- .message_function = player_message,
-};
-
-static void add_player(DBusConnection *conn, const char *name,
- const char *sender)
-{
- DBusMessage *reply = NULL;
- DBusMessage *msg;
- DBusMessageIter iter, args;
- DBusError err;
- char *path, *owner;
- struct player *player;
-
- if (!adapter)
- return;
-
- player = find_player_by_bus_name(name);
- if (player == NULL) {
- reply = get_all(conn, name);
- if (reply == NULL)
- return;
- dbus_message_iter_init(reply, &args);
- }
-
- msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
- g_dbus_proxy_get_path(adapter),
- BLUEZ_MEDIA_INTERFACE,
- "RegisterPlayer");
- if (!msg) {
- fprintf(stderr, "Can't allocate new method call\n");
- return;
- }
-
- path = sender2path(sender);
- dbus_connection_get_object_path_data(sys, path, (void **) &owner);
-
- if (owner != NULL)
- goto done;
-
- dbus_message_iter_init_append(msg, &iter);
-
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
-
- if (player != NULL) {
- if (!g_dbus_get_properties(player->conn,
- MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE,
- &iter))
- goto done;
- } else {
- append_iter(&iter, &args);
- dbus_message_unref(reply);
- }
-
- dbus_error_init(&err);
-
- owner = strdup(sender);
-
- if (!dbus_connection_register_object_path(sys, path, &player_table,
- owner)) {
- fprintf(stderr, "Can't register object path for player\n");
- free(owner);
- goto done;
- }
-
- reply = dbus_connection_send_with_reply_and_block(sys, msg, -1, &err);
- if (!reply) {
- fprintf(stderr, "Can't register player\n");
- free(owner);
- if (dbus_error_is_set(&err)) {
- fprintf(stderr, "%s\n", err.message);
- dbus_error_free(&err);
- }
- }
-
-done:
- if (reply)
- dbus_message_unref(reply);
- dbus_message_unref(msg);
- g_free(path);
-}
-
-static void remove_player(DBusConnection *conn, const char *sender)
-{
- DBusMessage *msg;
- char *path, *owner;
-
- if (!adapter)
- return;
-
- path = sender2path(sender);
- dbus_connection_get_object_path_data(sys, path, (void **) &owner);
-
- if (owner == NULL) {
- g_free(path);
- return;
- }
-
- msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
- g_dbus_proxy_get_path(adapter),
- BLUEZ_MEDIA_INTERFACE,
- "UnregisterPlayer");
- if (!msg) {
- fprintf(stderr, "Can't allocate new method call\n");
- g_free(path);
- return;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-
- dbus_connection_send(sys, msg, NULL);
-
- dbus_connection_unregister_object_path(sys, path);
-
- dbus_message_unref(msg);
- g_free(path);
- g_free(owner);
-}
-
-static gboolean player_signal(DBusConnection *conn, DBusMessage *msg,
- void *user_data)
-{
- DBusMessage *signal;
- DBusMessageIter iter, args;
- char *path, *owner;
-
- dbus_message_iter_init(msg, &iter);
-
- path = sender2path(dbus_message_get_sender(msg));
- dbus_connection_get_object_path_data(sys, path, (void **) &owner);
-
- if (owner == NULL)
- goto done;
-
- signal = dbus_message_new_signal(path, dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- if (signal == NULL) {
- fprintf(stderr, "Unable to allocate new %s.%s signal",
- dbus_message_get_interface(msg),
- dbus_message_get_member(msg));
- goto done;
- }
-
- dbus_message_iter_init_append(signal, &args);
-
- append_iter(&args, &iter);
-
- dbus_connection_send(sys, signal, NULL);
- dbus_message_unref(signal);
-
-done:
- g_free(path);
-
- return TRUE;
-}
-
-static gboolean name_owner_changed(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- const char *name, *old, *new;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &old,
- DBUS_TYPE_STRING, &new,
- DBUS_TYPE_INVALID)) {
- fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- if (!g_str_has_prefix(name, "org.mpris"))
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (*new == '\0') {
- printf("player %s at %s disappear\n", name, old);
- remove_player(conn, old);
- } else if (option_export || find_player_by_bus_name(name) == NULL) {
- printf("player %s at %s found\n", name, new);
- add_player(conn, name, new);
- }
-
- return TRUE;
-}
-
-static char *get_name_owner(DBusConnection *conn, const char *name)
-{
- DBusMessage *msg, *reply;
- DBusError err;
- char *owner;
-
- msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS, "GetNameOwner");
-
- if (!msg) {
- fprintf(stderr, "Can't allocate new method call\n");
- return NULL;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID);
-
- dbus_error_init(&err);
-
- reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
- dbus_message_unref(msg);
-
- if (!reply) {
- if (dbus_error_is_set(&err)) {
- fprintf(stderr, "%s\n", err.message);
- dbus_error_free(&err);
- }
- return NULL;
- }
-
- if (!dbus_message_get_args(reply, NULL,
- DBUS_TYPE_STRING, &owner,
- DBUS_TYPE_INVALID)) {
- dbus_message_unref(reply);
- return NULL;
- }
-
- owner = g_strdup(owner);
-
- dbus_message_unref(reply);
-
- dbus_connection_flush(conn);
-
- return owner;
-}
-
-static void parse_list_names(DBusConnection *conn, DBusMessageIter *args)
-{
- DBusMessageIter array;
- int ctype;
-
- ctype = dbus_message_iter_get_arg_type(args);
- if (ctype != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(args, &array);
-
- while ((ctype = dbus_message_iter_get_arg_type(&array)) !=
- DBUS_TYPE_INVALID) {
- const char *name;
- char *owner;
-
- if (ctype != DBUS_TYPE_STRING)
- goto next;
-
- dbus_message_iter_get_basic(&array, &name);
-
- if (!g_str_has_prefix(name, "org.mpris"))
- goto next;
-
- owner = get_name_owner(conn, name);
-
- if (owner == NULL)
- goto next;
-
- printf("player %s at %s found\n", name, owner);
-
- add_player(conn, name, owner);
-
- g_free(owner);
-next:
- dbus_message_iter_next(&array);
- }
-}
-
-static void list_names(DBusConnection *conn)
-{
- DBusMessage *msg, *reply;
- DBusMessageIter iter;
- DBusError err;
-
- msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS, "ListNames");
-
- if (!msg) {
- fprintf(stderr, "Can't allocate new method call\n");
- return;
- }
-
- dbus_error_init(&err);
-
- reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
- dbus_message_unref(msg);
-
- if (!reply) {
- if (dbus_error_is_set(&err)) {
- fprintf(stderr, "%s\n", err.message);
- dbus_error_free(&err);
- }
- return;
- }
-
- dbus_message_iter_init(reply, &iter);
-
- parse_list_names(conn, &iter);
-
- dbus_message_unref(reply);
-
- dbus_connection_flush(conn);
-}
-
-static void usage(void)
-{
- printf("Bluetooth mpris-player ver %s\n\n", VERSION);
-
- printf("Usage:\n");
-}
-
-static GOptionEntry options[] = {
- { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
- "Show version information and exit" },
- { "export", 'e', 0, G_OPTION_ARG_NONE, &option_export,
- "Export remote players" },
- { NULL },
-};
-
-static void connect_handler(DBusConnection *connection, void *user_data)
-{
- printf("org.bluez appeared\n");
-}
-
-static void disconnect_handler(DBusConnection *connection, void *user_data)
-{
- printf("org.bluez disappeared\n");
-}
-
-static void unregister_tracklist(struct player *player)
-{
- struct tracklist *tracklist = player->tracklist;
-
- g_slist_free(tracklist->items);
- g_dbus_proxy_unref(tracklist->proxy);
- g_free(tracklist);
- player->tracklist = NULL;
-}
-
-static void player_free(void *data)
-{
- struct player *player = data;
-
- if (player->tracklist != NULL)
- unregister_tracklist(player);
-
- if (player->conn) {
- dbus_connection_close(player->conn);
- dbus_connection_unref(player->conn);
- }
-
- g_dbus_proxy_unref(player->device);
- g_dbus_proxy_unref(player->proxy);
-
- if (player->transport)
- g_dbus_proxy_unref(player->transport);
-
- if (player->playlist)
- g_dbus_proxy_unref(player->playlist);
-
- g_free(player->bus_name);
- g_free(player);
-}
-
-struct pending_call {
- struct player *player;
- DBusMessage *msg;
-};
-
-static void pending_call_free(void *data)
-{
- struct pending_call *p = data;
-
- if (p->msg)
- dbus_message_unref(p->msg);
-
- g_free(p);
-}
-
-static void player_reply(DBusMessage *message, void *user_data)
-{
- struct pending_call *p = user_data;
- struct player *player = p->player;
- DBusMessage *msg = p->msg;
- DBusMessage *reply;
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, message)) {
- fprintf(stderr, "error: %s", err.name);
- reply = g_dbus_create_error(msg, err.name, "%s", err.message);
- dbus_error_free(&err);
- } else
- reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-
- g_dbus_send_message(player->conn, reply);
-}
-
-static void player_control(struct player *player, DBusMessage *msg,
- const char *name)
-{
- struct pending_call *p;
-
- p = g_new0(struct pending_call, 1);
- p->player = player;
- p->msg = dbus_message_ref(msg);
-
- g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
- p, pending_call_free);
-}
-
-static const char *status_to_playback(const char *status)
-{
- if (strcasecmp(status, "playing") == 0)
- return "Playing";
- else if (strcasecmp(status, "paused") == 0)
- return "Paused";
- else
- return "Stopped";
-}
-
-static const char *player_get_status(struct player *player)
-{
- const char *status;
- DBusMessageIter value;
-
- if (g_dbus_proxy_get_property(player->proxy, "Status", &value)) {
- dbus_message_iter_get_basic(&value, &status);
- return status_to_playback(status);
- }
-
- if (player->transport == NULL)
- goto done;
-
- if (!g_dbus_proxy_get_property(player->transport, "State", &value))
- goto done;
-
- dbus_message_iter_get_basic(&value, &status);
-
- if (strcasecmp(status, "active") == 0)
- return "Playing";
-
-done:
- return "Stopped";
-}
-
-static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
- const char *status;
-
- status = player_get_status(player);
-
- if (strcasecmp(status, "Playing") == 0)
- player_control(player, msg, "Pause");
- else
- player_control(player, msg, "Play");
-
- return NULL;
-}
-
-static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
-
- player_control(player, msg, "Play");
-
- return NULL;
-}
-
-static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
-
- player_control(player, msg, "Pause");
-
- return NULL;
-}
-
-static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
-
- player_control(player, msg, "Stop");
-
- return NULL;
-}
-
-static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
-
- player_control(player, msg, "Next");
-
- return NULL;
-}
-
-static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
-
- player_control(player, msg, "Previous");
-
- return NULL;
-}
-
-static gboolean status_exists(const GDBusPropertyTable *property, void *data)
-{
- struct player *player = data;
-
- return player_get_status(player) != NULL;
-}
-
-static gboolean get_status(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- const char *status;
-
- status = player_get_status(player);
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
-
- return TRUE;
-}
-
-static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
-{
- DBusMessageIter iter;
- struct player *player = data;
-
- return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
-}
-
-static const char *repeat_to_loopstatus(const char *value)
-{
- if (strcasecmp(value, "off") == 0)
- return "None";
- else if (strcasecmp(value, "singletrack") == 0)
- return "Track";
- else if (strcasecmp(value, "alltracks") == 0)
- return "Playlist";
-
- return NULL;
-}
-
-static gboolean get_repeat(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- DBusMessageIter value;
- const char *status;
-
- if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
- return FALSE;
-
- dbus_message_iter_get_basic(&value, &status);
-
- status = repeat_to_loopstatus(status);
- if (status == NULL)
- return FALSE;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
-
- return TRUE;
-}
-
-static const char *loopstatus_to_repeat(const char *value)
-{
- if (strcasecmp(value, "None") == 0)
- return "off";
- else if (strcasecmp(value, "Track") == 0)
- return "singletrack";
- else if (strcasecmp(value, "Playlist") == 0)
- return "alltracks";
-
- return NULL;
-}
-
-static void property_result(const DBusError *err, void *user_data)
-{
- GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
-
- if (!dbus_error_is_set(err))
- return g_dbus_pending_property_success(id);
-
- g_dbus_pending_property_error(id, err->name, err->message);
-}
-
-static void set_repeat(const GDBusPropertyTable *property,
- DBusMessageIter *iter, GDBusPendingPropertySet id,
- void *data)
-{
- struct player *player = data;
- const char *value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
- g_dbus_pending_property_error(id,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
- return;
- }
-
- dbus_message_iter_get_basic(iter, &value);
-
- value = loopstatus_to_repeat(value);
- if (value == NULL) {
- g_dbus_pending_property_error(id,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
- return;
- }
-
- g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
- DBUS_TYPE_STRING, &value,
- property_result, GUINT_TO_POINTER(id),
- NULL);
-}
-
-static gboolean get_double(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- double value = 1.0;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
-
- return TRUE;
-}
-
-static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
-{
- DBusMessageIter iter;
- struct player *player = data;
-
- return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
-}
-
-static gboolean get_shuffle(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- DBusMessageIter value;
- const char *string;
- dbus_bool_t shuffle;
-
- if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
- return FALSE;
-
- dbus_message_iter_get_basic(&value, &string);
-
- shuffle = strcmp(string, "off") != 0;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
-
- return TRUE;
-}
-
-static void set_shuffle(const GDBusPropertyTable *property,
- DBusMessageIter *iter, GDBusPendingPropertySet id,
- void *data)
-{
- struct player *player = data;
- dbus_bool_t shuffle;
- const char *value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
- g_dbus_pending_property_error(id,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
- return;
- }
-
- dbus_message_iter_get_basic(iter, &shuffle);
- value = shuffle ? "alltracks" : "off";
-
- g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
- DBUS_TYPE_STRING, &value,
- property_result, GUINT_TO_POINTER(id),
- NULL);
-}
-
-static gboolean position_exists(const GDBusPropertyTable *property, void *data)
-{
- DBusMessageIter iter;
- struct player *player = data;
-
- return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
-}
-
-static gboolean get_position(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- DBusMessageIter var;
- uint32_t position;
- int64_t value;
-
- if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
- return FALSE;
-
- dbus_message_iter_get_basic(&var, &position);
-
- value = position * 1000;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
-
- return TRUE;
-}
-
-static gboolean track_exists(const GDBusPropertyTable *property, void *data)
-{
- DBusMessageIter iter;
- struct player *player = data;
-
- return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
-}
-
-static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
- DBusMessageIter *metadata)
-{
- const char *value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
- return FALSE;
-
- dbus_message_iter_get_basic(iter, &value);
-
- dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
-
- return TRUE;
-}
-
-static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
- DBusMessageIter *metadata)
-{
- char **value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
- return FALSE;
-
- value = dbus_malloc0(sizeof(char *));
-
- dbus_message_iter_get_basic(iter, &(value[0]));
-
- dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
-
- dbus_free(value);
-
- return TRUE;
-}
-
-static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
- DBusMessageIter *metadata)
-{
- uint32_t duration;
- int64_t value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
- return FALSE;
-
- dbus_message_iter_get_basic(iter, &duration);
-
- value = duration * 1000;
-
- dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
-
- return TRUE;
-}
-
-static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
- DBusMessageIter *metadata)
-{
- uint32_t value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
- return FALSE;
-
- dbus_message_iter_get_basic(iter, &value);
-
- dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
-
- return TRUE;
-}
-
-static gboolean parse_path_metadata(DBusMessageIter *iter, const char *key,
- DBusMessageIter *metadata)
-{
- const char *value;
-
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
- return FALSE;
-
- dbus_message_iter_get_basic(iter, &value);
-
- dict_append_entry(metadata, key, DBUS_TYPE_OBJECT_PATH, &value);
-
- return TRUE;
-}
-
-static int parse_track_entry(DBusMessageIter *entry, const char *key,
- DBusMessageIter *metadata)
-{
- DBusMessageIter var;
-
- if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
- return -EINVAL;
-
- dbus_message_iter_recurse(entry, &var);
-
- if (strcasecmp(key, "Title") == 0) {
- if (!parse_string_metadata(&var, "xesam:title", metadata))
- return -EINVAL;
- } else if (strcasecmp(key, "Artist") == 0) {
- if (!parse_array_metadata(&var, "xesam:artist", metadata))
- return -EINVAL;
- } else if (strcasecmp(key, "Album") == 0) {
- if (!parse_string_metadata(&var, "xesam:album", metadata))
- return -EINVAL;
- } else if (strcasecmp(key, "Genre") == 0) {
- if (!parse_array_metadata(&var, "xesam:genre", metadata))
- return -EINVAL;
- } else if (strcasecmp(key, "Duration") == 0) {
- if (!parse_int64_metadata(&var, "mpris:length", metadata))
- return -EINVAL;
- } else if (strcasecmp(key, "TrackNumber") == 0) {
- if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
- return -EINVAL;
- } else if (strcasecmp(key, "Item") == 0) {
- if (!parse_path_metadata(&var, "mpris:trackid", metadata))
- return -EINVAL;
- }
-
- return 0;
-}
-
-static gboolean get_track(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- DBusMessageIter var, metadata;
-
- if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
- return FALSE;
-
- 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, &metadata);
-
- parse_metadata(&var, &metadata, parse_track_entry);
-
- dbus_message_iter_close_container(iter, &metadata);
-
- return TRUE;
-}
-
-static gboolean get_enable(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- dbus_bool_t value = TRUE;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
- return TRUE;
-}
-
-
-static gboolean get_volume(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- double value = 0.0;
- uint16_t volume;
- DBusMessageIter var;
-
- if (player->transport == NULL)
- goto done;
-
- if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
- goto done;
-
- dbus_message_iter_get_basic(&var, &volume);
-
- value = (double) volume / 127;
-
-done:
- dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
-
- return TRUE;
-}
-
-static const GDBusMethodTable player_methods[] = {
- { GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
- { GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
- { GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
- { GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
- { GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
- { GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
- { }
-};
-
-static const GDBusSignalTable player_signals[] = {
- { GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
- { }
-};
-
-static const GDBusPropertyTable player_properties[] = {
- { "PlaybackStatus", "s", get_status, NULL, status_exists },
- { "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
- { "Rate", "d", get_double, NULL, NULL },
- { "MinimumRate", "d", get_double, NULL, NULL },
- { "MaximumRate", "d", get_double, NULL, NULL },
- { "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
- { "Position", "x", get_position, NULL, position_exists },
- { "Metadata", "a{sv}", get_track, NULL, track_exists },
- { "Volume", "d", get_volume, NULL, NULL },
- { "CanGoNext", "b", get_enable, NULL, NULL },
- { "CanGoPrevious", "b", get_enable, NULL, NULL },
- { "CanPlay", "b", get_enable, NULL, NULL },
- { "CanPause", "b", get_enable, NULL, NULL },
- { "CanSeek", "b", get_enable, NULL, NULL },
- { "CanControl", "b", get_enable, NULL, NULL },
- { }
-};
-
-static gboolean get_disable(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- dbus_bool_t value = FALSE;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
- return TRUE;
-}
-
-static gboolean get_name(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- DBusMessageIter var;
- const char *alias;
- char *name;
-
- if (!g_dbus_proxy_get_property(player->device, "Alias", &var))
- return FALSE;
-
- dbus_message_iter_get_basic(&var, &alias);
-
- if (g_dbus_proxy_get_property(player->proxy, "Name", &var)) {
- dbus_message_iter_get_basic(&var, &name);
- name = g_strconcat(alias, " ", name, NULL);
- } else
- name = g_strdup(alias);
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
-
- g_free(name);
-
- return TRUE;
-}
-
-static const GDBusMethodTable mpris_methods[] = {
- { }
-};
-
-static gboolean get_tracklist(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- dbus_bool_t value;
-
- value = player->tracklist != NULL ? TRUE : FALSE;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
- return TRUE;
-}
-
-static const GDBusPropertyTable mpris_properties[] = {
- { "CanQuit", "b", get_disable, NULL, NULL },
- { "Fullscreen", "b", get_disable, NULL, NULL },
- { "CanSetFullscreen", "b", get_disable, NULL, NULL },
- { "CanRaise", "b", get_disable, NULL, NULL },
- { "HasTrackList", "b", get_tracklist, NULL, NULL },
- { "Identity", "s", get_name, NULL, NULL },
- { }
-};
-
-static GDBusProxy *find_item(struct player *player, const char *path)
-{
- struct tracklist *tracklist = player->tracklist;
- GSList *l;
-
- for (l = tracklist->items; l; l = l->next) {
- GDBusProxy *proxy = l->data;
- const char *p = g_dbus_proxy_get_path(proxy);
-
- if (g_str_equal(path, p))
- return proxy;
- }
-
- return NULL;
-}
-
-static void append_item_metadata(void *data, void *user_data)
-{
- GDBusProxy *item = data;
- DBusMessageIter *iter = user_data;
- DBusMessageIter var, metadata;
- const char *path = g_dbus_proxy_get_path(item);
-
- 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, &metadata);
-
- dict_append_entry(&metadata, "mpris:trackid", DBUS_TYPE_OBJECT_PATH,
- &path);
-
- if (g_dbus_proxy_get_property(item, "Metadata", &var))
- parse_metadata(&var, &metadata, parse_track_entry);
-
- dbus_message_iter_close_container(iter, &metadata);
-
- return;
-}
-
-static DBusMessage *tracklist_get_metadata(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct player *player = data;
- DBusMessage *reply;
- DBusMessageIter args, array;
- GSList *l = NULL;
-
- dbus_message_iter_init(msg, &args);
-
- if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- dbus_message_iter_recurse(&args, &array);
-
- while (dbus_message_iter_get_arg_type(&array) ==
- DBUS_TYPE_OBJECT_PATH) {
- const char *path;
- GDBusProxy *item;
-
- dbus_message_iter_get_basic(&array, &path);
-
- item = find_item(player, path);
- if (item == NULL)
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- l = g_slist_append(l, item);
-
- dbus_message_iter_next(&array);
- }
-
- reply = dbus_message_new_method_return(msg);
-
- dbus_message_iter_init_append(reply, &args);
-
- dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING
- DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
- &array);
-
- g_slist_foreach(l, append_item_metadata, &array);
-
- dbus_message_iter_close_container(&args, &array);
-
- return reply;
-}
-
-static void item_play_reply(DBusMessage *message, void *user_data)
-{
- struct pending_call *p = user_data;
- struct player *player = p->player;
- DBusMessage *msg = p->msg;
- DBusMessage *reply;
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, message)) {
- fprintf(stderr, "error: %s", err.name);
- reply = g_dbus_create_error(msg, err.name, "%s", err.message);
- dbus_error_free(&err);
- } else
- reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-
- g_dbus_send_message(player->conn, reply);
-}
-
-static void item_play(struct player *player, DBusMessage *msg,
- GDBusProxy *item)
-{
- struct pending_call *p;
-
- p = g_new0(struct pending_call, 1);
- p->player = player;
- p->msg = dbus_message_ref(msg);
-
- g_dbus_proxy_method_call(item, "Play", NULL, item_play_reply,
- p, pending_call_free);
-}
-
-static DBusMessage *tracklist_goto(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct player *player = data;
- GDBusProxy *item;
- const char *path;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments");
-
- item = find_item(player, path);
- if (item == NULL)
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments");
-
- item_play(player, msg, item);
-
- return NULL;
-}
-
-static DBusMessage *tracklist_add_track(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return g_dbus_create_error(msg, ERROR_INTERFACE ".NotImplemented",
- "Not implemented");
-}
-
-static DBusMessage *tracklist_remove_track(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return g_dbus_create_error(msg, ERROR_INTERFACE ".NotImplemented",
- "Not implemented");
-}
-
-static const GDBusMethodTable tracklist_methods[] = {
- { GDBUS_METHOD("GetTracksMetadata",
- GDBUS_ARGS({ "tracks", "ao" }),
- GDBUS_ARGS({ "metadata", "aa{sv}" }),
- tracklist_get_metadata) },
- { GDBUS_METHOD("AddTrack",
- GDBUS_ARGS({ "uri", "s" }, { "after", "o" },
- { "current", "b" }),
- NULL,
- tracklist_add_track) },
- { GDBUS_METHOD("RemoveTrack",
- GDBUS_ARGS({ "track", "o" }), NULL,
- tracklist_remove_track) },
- { GDBUS_ASYNC_METHOD("GoTo",
- GDBUS_ARGS({ "track", "o" }), NULL,
- tracklist_goto) },
- { },
-};
-
-static const GDBusSignalTable tracklist_signals[] = {
- { GDBUS_SIGNAL("TrackAdded", GDBUS_ARGS({"metadata", "a{sv}"},
- {"after", "o"})) },
- { GDBUS_SIGNAL("TrackRemoved", GDBUS_ARGS({"track", "o"})) },
- { GDBUS_SIGNAL("TrackMetadataChanged", GDBUS_ARGS({"track", "o"},
- {"metadata", "a{sv}"})) },
- { }
-};
-
-static gboolean tracklist_exists(const GDBusPropertyTable *property, void *data)
-{
- struct player *player = data;
-
- return player->tracklist != NULL;
-}
-
-static void append_path(gpointer data, gpointer user_data)
-{
- GDBusProxy *proxy = data;
- DBusMessageIter *iter = user_data;
- const char *path = g_dbus_proxy_get_path(proxy);
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
-}
-
-static gboolean get_tracks(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- struct tracklist *tracklist = player->tracklist;
- DBusMessageIter value;
-
- if (tracklist == NULL)
- return FALSE;
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING,
- &value);
- g_slist_foreach(player->tracklist->items, append_path, &value);
- dbus_message_iter_close_container(iter, &value);
-
- return TRUE;
-}
-
-static const GDBusPropertyTable tracklist_properties[] = {
- { "Tracks", "ao", get_tracks, NULL, tracklist_exists },
- { "CanEditTracks", "b", get_disable, NULL, NULL },
- { }
-};
-
-static void list_items_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 change_folder_reply(DBusMessage *message, void *user_data)
-{
- struct player *player = user_data;
- struct tracklist *tracklist = player->tracklist;
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, message)) {
- fprintf(stderr, "error: %s", err.name);
- return;
- }
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYLISTS_INTERFACE,
- "ActivePlaylist");
-
- g_dbus_proxy_method_call(tracklist->proxy, "ListItems",
- list_items_setup, NULL, NULL, NULL);
-}
-
-static void change_folder_setup(DBusMessageIter *iter, void *user_data)
-{
- struct player *player = user_data;
- const char *path;
-
- path = g_dbus_proxy_get_path(player->playlist);
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
-}
-
-static DBusMessage *playlist_activate(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct player *player = data;
- struct tracklist *tracklist = player->tracklist;
- const char *path;
-
- if (player->playlist == NULL || tracklist == NULL)
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- if (!g_str_equal(path, g_dbus_proxy_get_path(player->playlist)))
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- g_dbus_proxy_method_call(tracklist->proxy, "ChangeFolder",
- change_folder_setup, change_folder_reply,
- player, NULL);
-
- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *playlist_get(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct player *player = data;
- uint32_t index, count;
- const char *order;
- dbus_bool_t reverse;
- DBusMessage *reply;
- DBusMessageIter iter, entry, value, name;
- const char *string, *path;
- const char *empty = "";
-
- if (player->playlist == NULL)
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_UINT32, &index,
- DBUS_TYPE_UINT32, &count,
- DBUS_TYPE_STRING, &order,
- DBUS_TYPE_BOOLEAN, &reverse,
- DBUS_TYPE_INVALID))
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid Arguments");
-
- path = g_dbus_proxy_get_path(player->playlist);
-
- reply = dbus_message_new_method_return(msg);
-
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(oss)",
- &entry);
- dbus_message_iter_open_container(&entry, DBUS_TYPE_STRUCT, NULL,
- &value);
- dbus_message_iter_append_basic(&value, DBUS_TYPE_OBJECT_PATH, &path);
- if (g_dbus_proxy_get_property(player->playlist, "Name", &name)) {
- dbus_message_iter_get_basic(&name, &string);
- dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING,
- &string);
- } else {
- dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING,
- &path);
- }
- dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &empty);
- dbus_message_iter_close_container(&entry, &value);
- dbus_message_iter_close_container(&iter, &entry);
-
- return reply;
-}
-
-static const GDBusMethodTable playlist_methods[] = {
- { GDBUS_METHOD("ActivatePlaylist",
- GDBUS_ARGS({ "playlist", "o" }), NULL,
- playlist_activate) },
- { GDBUS_METHOD("GetPlaylists",
- GDBUS_ARGS({ "index", "u" }, { "maxcount", "u"},
- { "order", "s" }, { "reverse", "b" }),
- GDBUS_ARGS({ "playlists", "a(oss)"}),
- playlist_get) },
- { },
-};
-
-static gboolean playlist_exists(const GDBusPropertyTable *property, void *data)
-{
- struct player *player = data;
-
- return player->playlist != NULL;
-}
-
-static gboolean get_playlist_count(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- uint32_t count = 1;
-
- if (player->playlist == NULL)
- return FALSE;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &count);
-
- return TRUE;
-}
-
-static gboolean get_orderings(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- DBusMessageIter value;
- const char *order = "User";
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING,
- &value);
- dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &order);
- dbus_message_iter_close_container(iter, &value);
-
- return TRUE;
-}
-
-static gboolean get_active_playlist(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
-{
- struct player *player = data;
- DBusMessageIter value, entry;
- dbus_bool_t enabled = TRUE;
- const char *path, *empty = "";
-
- if (player->playlist == NULL)
- return FALSE;
-
- path = g_dbus_proxy_get_path(player->playlist);
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
- NULL, &value);
- dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &enabled);
- dbus_message_iter_open_container(&value, DBUS_TYPE_STRUCT, NULL,
- &entry);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, &path);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &path);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &empty);
- dbus_message_iter_close_container(&value, &entry);
- dbus_message_iter_close_container(iter, &value);
-
- return TRUE;
-}
-
-static const GDBusPropertyTable playlist_properties[] = {
- { "PlaylistCount", "u", get_playlist_count, NULL, playlist_exists },
- { "Orderings", "as", get_orderings, NULL, NULL },
- { "ActivePlaylist", "(b(oss))", get_active_playlist, NULL,
- playlist_exists },
- { }
-};
-
-#define a_z "abcdefghijklmnopqrstuvwxyz"
-#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define _0_9 "_0123456789"
-
-static char *mpris_busname(char *name)
-{
- if (g_ascii_isdigit(name[0]))
- return g_strconcat(MPRIS_BUS_NAME, "bt_",
- g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
- else
- return g_strconcat(MPRIS_BUS_NAME,
- g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
-}
-
-static GDBusProxy *find_transport_by_path(const char *path)
-{
- GSList *l;
-
- for (l = transports; l; l = l->next) {
- GDBusProxy *transport = l->data;
- DBusMessageIter iter;
- const char *value;
-
- if (!g_dbus_proxy_get_property(transport, "Device", &iter))
- continue;
-
- dbus_message_iter_get_basic(&iter, &value);
-
- if (strcmp(path, value) == 0)
- return transport;
- }
-
- return NULL;
-}
-
-static struct player *find_player(GDBusProxy *proxy)
-{
- GSList *l;
-
- for (l = players; l; l = l->next) {
- struct player *player = l->data;
- const char *path, *p;
-
- if (player->proxy == proxy)
- return player;
-
- path = g_dbus_proxy_get_path(proxy);
- p = g_dbus_proxy_get_path(player->proxy);
- if (g_str_equal(path, p))
- return player;
- }
-
- return NULL;
-}
-
-static void register_tracklist(GDBusProxy *proxy)
-{
- struct player *player;
- struct tracklist *tracklist;
-
- player = find_player(proxy);
- if (player == NULL)
- return;
-
- if (player->tracklist != NULL)
- return;
-
- tracklist = g_new0(struct tracklist, 1);
- tracklist->proxy = g_dbus_proxy_ref(proxy);
-
- player->tracklist = tracklist;
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_INTERFACE,
- "HasTrackList");
-
- if (player->playlist == NULL)
- return;
-
- g_dbus_proxy_method_call(player->tracklist->proxy, "ChangeFolder",
- change_folder_setup, change_folder_reply,
- player, NULL);
-}
-
-static void register_player(GDBusProxy *proxy)
-{
- struct player *player;
- DBusMessageIter iter;
- const char *path, *alias, *name;
- char *busname;
- GDBusProxy *device, *transport;
-
- if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
- return;
-
- dbus_message_iter_get_basic(&iter, &path);
-
- device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
- if (device == NULL)
- return;
-
- if (!g_dbus_proxy_get_property(device, "Alias", &iter))
- return;
-
- dbus_message_iter_get_basic(&iter, &alias);
-
- if (g_dbus_proxy_get_property(proxy, "Name", &iter)) {
- dbus_message_iter_get_basic(&iter, &name);
- busname = g_strconcat(alias, " ", name, NULL);
- } else
- busname = g_strdup(alias);
-
- player = g_new0(struct player, 1);
- player->bus_name = mpris_busname(busname);
- player->proxy = g_dbus_proxy_ref(proxy);
- player->device = device;
-
- g_free(busname);
-
- players = g_slist_prepend(players, player);
-
- printf("Player %s created\n", player->bus_name);
-
- player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
- NULL);
- if (!session) {
- fprintf(stderr, "Could not register bus name %s",
- player->bus_name);
- goto fail;
- }
-
- if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_INTERFACE,
- mpris_methods,
- NULL,
- mpris_properties,
- player, NULL)) {
- fprintf(stderr, "Could not register interface %s",
- MPRIS_INTERFACE);
- goto fail;
- }
-
- if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE,
- player_methods,
- player_signals,
- player_properties,
- player, player_free)) {
- fprintf(stderr, "Could not register interface %s",
- MPRIS_PLAYER_INTERFACE);
- goto fail;
- }
-
- if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE,
- tracklist_methods,
- tracklist_signals,
- tracklist_properties,
- player, NULL)) {
- fprintf(stderr, "Could not register interface %s",
- MPRIS_TRACKLIST_INTERFACE);
- goto fail;
- }
-
- if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYLISTS_INTERFACE,
- playlist_methods,
- NULL,
- playlist_properties,
- player, NULL)) {
- fprintf(stderr, "Could not register interface %s",
- MPRIS_PLAYLISTS_INTERFACE);
- goto fail;
- }
-
- transport = find_transport_by_path(path);
- if (transport)
- player->transport = g_dbus_proxy_ref(transport);
-
- return;
-
-fail:
- players = g_slist_remove(players, player);
- player_free(player);
-}
-
-static struct player *find_player_by_device(const char *device)
-{
- GSList *l;
-
- for (l = players; l; l = l->next) {
- struct player *player = l->data;
- const char *path = g_dbus_proxy_get_path(player->device);
-
- if (g_strcmp0(device, path) == 0)
- return player;
- }
-
- return NULL;
-}
-
-static void register_transport(GDBusProxy *proxy)
-{
- struct player *player;
- DBusMessageIter iter;
- const char *path;
-
- if (g_slist_find(transports, proxy) != NULL)
- return;
-
- if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
- return;
-
- if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
- return;
-
- dbus_message_iter_get_basic(&iter, &path);
-
- transports = g_slist_append(transports, proxy);
-
- player = find_player_by_device(path);
- if (player == NULL || player->transport != NULL)
- return;
-
- player->transport = g_dbus_proxy_ref(proxy);
-}
-
-static struct player *find_player_by_item(const char *item)
-{
- GSList *l;
-
- for (l = players; l; l = l->next) {
- struct player *player = l->data;
- const char *path = g_dbus_proxy_get_path(player->proxy);
-
- if (g_str_has_prefix(item, path))
- return player;
- }
-
- return NULL;
-}
-
-static void register_playlist(struct player *player, GDBusProxy *proxy)
-{
- const char *path;
- DBusMessageIter iter;
-
- if (!g_dbus_proxy_get_property(player->proxy, "Playlist", &iter))
- return;
-
- dbus_message_iter_get_basic(&iter, &path);
-
- if (!g_str_equal(path, g_dbus_proxy_get_path(proxy)))
- return;
-
- player->playlist = g_dbus_proxy_ref(proxy);
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYLISTS_INTERFACE,
- "PlaylistCount");
-
- if (player->tracklist == NULL)
- return;
-
- g_dbus_proxy_method_call(player->tracklist->proxy, "ChangeFolder",
- change_folder_setup, change_folder_reply,
- player, NULL);
-}
-
-static void register_item(struct player *player, GDBusProxy *proxy)
-{
- struct tracklist *tracklist;
- const char *path, *playlist;
- DBusMessage *signal;
- DBusMessageIter iter, args, metadata;
- GSList *l;
- GDBusProxy *after;
-
- if (player->playlist == NULL) {
- register_playlist(player, proxy);
- return;
- }
-
- tracklist = player->tracklist;
- if (tracklist == NULL)
- return;
-
- path = g_dbus_proxy_get_path(proxy);
- playlist = g_dbus_proxy_get_path(player->playlist);
- if (!g_str_has_prefix(path, playlist))
- return;
-
- l = g_slist_last(tracklist->items);
- tracklist->items = g_slist_append(tracklist->items, proxy);
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE,
- "Tracks");
-
- if (l == NULL)
- return;
-
- signal = dbus_message_new_signal(MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE,
- "TrackAdded");
- if (!signal) {
- fprintf(stderr, "Unable to allocate new %s.TrackAdded signal",
- MPRIS_TRACKLIST_INTERFACE);
- return;
- }
-
- dbus_message_iter_init_append(signal, &args);
-
- if (!g_dbus_proxy_get_property(proxy, "Metadata", &iter)) {
- dbus_message_unref(signal);
- return;
- }
-
- dbus_message_iter_open_container(&args, 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, &metadata);
-
- parse_metadata(&iter, &metadata, parse_track_entry);
-
- dbus_message_iter_close_container(&args, &metadata);
-
- after = l->data;
- path = g_dbus_proxy_get_path(after);
- dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &path);
-
- g_dbus_send_message(player->conn, signal);
-}
-
-static void proxy_added(GDBusProxy *proxy, void *user_data)
-{
- const char *interface;
- const char *path;
-
- interface = g_dbus_proxy_get_interface(proxy);
- path = g_dbus_proxy_get_path(proxy);
-
- if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
- if (adapter != NULL)
- return;
-
- printf("Bluetooth Adapter %s found\n", path);
- adapter = proxy;
- list_names(session);
- } else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
- printf("Bluetooth Player %s found\n", path);
- register_player(proxy);
- } else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
- printf("Bluetooth Transport %s found\n", path);
- register_transport(proxy);
- } else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE)) {
- printf("Bluetooth Folder %s found\n", path);
- register_tracklist(proxy);
- } else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE)) {
- struct player *player;
-
- player = find_player_by_item(path);
- if (player == NULL)
- return;
-
- printf("Bluetooth Item %s found\n", path);
- register_item(player, proxy);
- }
-}
-
-static void unregister_player(struct player *player)
-{
- players = g_slist_remove(players, player);
-
- if (player->tracklist != NULL) {
- g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYLISTS_INTERFACE);
- g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE);
- }
-
- g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_INTERFACE);
-
- g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE);
-}
-
-static struct player *find_player_by_transport(GDBusProxy *proxy)
-{
- GSList *l;
-
- for (l = players; l; l = l->next) {
- struct player *player = l->data;
-
- if (player->transport == proxy)
- return player;
- }
-
- return NULL;
-}
-
-static void unregister_transport(GDBusProxy *proxy)
-{
- struct player *player;
-
- if (g_slist_find(transports, proxy) == NULL)
- return;
-
- transports = g_slist_remove(transports, proxy);
-
- player = find_player_by_transport(proxy);
- if (player == NULL)
- return;
-
- g_dbus_proxy_unref(player->transport);
- player->transport = NULL;
-}
-
-static void unregister_item(struct player *player, GDBusProxy *proxy)
-{
- struct tracklist *tracklist = player->tracklist;
- const char *path;
-
- if (tracklist == NULL)
- return;
-
- if (g_slist_find(tracklist->items, proxy) == NULL)
- return;
-
- path = g_dbus_proxy_get_path(proxy);
-
- tracklist->items = g_slist_remove(tracklist->items, proxy);
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE,
- "Tracks");
-
- g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE, "TrackRemoved",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-}
-
-static void remove_players(DBusConnection *conn)
-{
- char **paths;
- int i;
-
- dbus_connection_list_registered(conn, "/", &paths);
-
- for (i = 0; paths[i]; i++) {
- char *path;
- void *data;
-
- path = g_strdup_printf("/%s", paths[i]);
- dbus_connection_get_object_path_data(sys, path, &data);
- dbus_connection_unregister_object_path(sys, path);
-
- g_free(path);
- g_free(data);
- }
-
- dbus_free_string_array(paths);
-}
-
-static void proxy_removed(GDBusProxy *proxy, void *user_data)
-{
- const char *interface;
- const char *path;
-
- if (adapter == NULL)
- return;
-
- interface = g_dbus_proxy_get_interface(proxy);
- path = g_dbus_proxy_get_path(proxy);
-
- if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
- if (adapter != proxy)
- return;
- printf("Bluetooth Adapter %s removed\n", path);
- adapter = NULL;
- remove_players(sys);
- } else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
- struct player *player;
-
- player = find_player(proxy);
- if (player == NULL)
- return;
-
- printf("Bluetooth Player %s removed\n", path);
- unregister_player(player);
- } else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
- printf("Bluetooth Transport %s removed\n", path);
- unregister_transport(proxy);
- } else if (strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE) == 0) {
- struct player *player;
-
- player = find_player_by_item(path);
- if (player == NULL)
- return;
-
- printf("Bluetooth Item %s removed\n", path);
- unregister_item(player, proxy);
- }
-}
-
-static const char *property_to_mpris(const char *property)
-{
- if (strcasecmp(property, "Repeat") == 0)
- return "LoopStatus";
- else if (strcasecmp(property, "Shuffle") == 0)
- return "Shuffle";
- else if (strcasecmp(property, "Status") == 0)
- return "PlaybackStatus";
- else if (strcasecmp(property, "Position") == 0)
- return "Position";
- else if (strcasecmp(property, "Track") == 0)
- return "Metadata";
-
- return NULL;
-}
-
-static void player_property_changed(GDBusProxy *proxy, const char *name,
- DBusMessageIter *iter, void *user_data)
-{
- struct player *player;
- const char *property;
- uint32_t position;
- uint64_t value;
-
- player = find_player(proxy);
- if (player == NULL)
- return;
-
- property = property_to_mpris(name);
- if (property == NULL)
- return;
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE,
- property);
-
- if (strcasecmp(name, "Position") != 0)
- return;
-
- dbus_message_iter_get_basic(iter, &position);
-
- value = position * 1000;
-
- g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE, "Seeked",
- DBUS_TYPE_INT64, &value,
- DBUS_TYPE_INVALID);
-}
-
-static void transport_property_changed(GDBusProxy *proxy, const char *name,
- DBusMessageIter *iter, void *user_data)
-{
- struct player *player;
- DBusMessageIter var;
- const char *path;
-
- if (strcasecmp(name, "Volume") != 0 && strcasecmp(name, "State") != 0)
- return;
-
- if (!g_dbus_proxy_get_property(proxy, "Device", &var))
- return;
-
- dbus_message_iter_get_basic(&var, &path);
-
- player = find_player_by_device(path);
- if (player == NULL)
- return;
-
- if (strcasecmp(name, "State") == 0) {
- if (!g_dbus_proxy_get_property(player->proxy, "Status", &var))
- g_dbus_emit_property_changed(player->conn,
- MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE,
- "PlaybackStatus");
- return;
- }
-
- g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
- MPRIS_PLAYER_INTERFACE,
- name);
-}
-
-static void item_property_changed(GDBusProxy *proxy, const char *name,
- DBusMessageIter *iter, void *user_data)
-{
- struct player *player;
- DBusMessage *signal;
- DBusMessageIter args;
- const char *path;
-
- path = g_dbus_proxy_get_path(proxy);
-
- player = find_player_by_item(path);
- if (player == NULL)
- return;
-
- if (strcasecmp(name, "Metadata") != 0)
- return;
-
- signal = dbus_message_new_signal(MPRIS_PLAYER_PATH,
- MPRIS_TRACKLIST_INTERFACE,
- "TrackMetadataChanged");
- if (!signal) {
- fprintf(stderr, "Unable to allocate new %s.TrackAdded signal",
- MPRIS_TRACKLIST_INTERFACE);
- return;
- }
-
- dbus_message_iter_init_append(signal, &args);
-
- dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &path);
-
- append_iter(&args, iter);
-
- g_dbus_send_message(player->conn, signal);
-}
-
-static void property_changed(GDBusProxy *proxy, const char *name,
- DBusMessageIter *iter, void *user_data)
-{
- const char *interface;
-
- interface = g_dbus_proxy_get_interface(proxy);
-
- if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
- return player_property_changed(proxy, name, iter, user_data);
-
- if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
- return transport_property_changed(proxy, name, iter,
- user_data);
-
- if (strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE) == 0)
- return item_property_changed(proxy, name, iter, user_data);
-}
-
-int main(int argc, char *argv[])
-{
- GOptionContext *context;
- GError *error = NULL;
- guint owner_watch, properties_watch, signal_watch;
- struct sigaction sa;
-
- context = g_option_context_new(NULL);
- g_option_context_add_main_entries(context, options, NULL);
-
- if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
- if (error != NULL) {
- g_printerr("%s\n", error->message);
- g_error_free(error);
- } else
- g_printerr("An unknown error occurred\n");
- exit(1);
- }
-
- g_option_context_free(context);
-
- if (option_version == TRUE) {
- usage();
- exit(0);
- }
-
- main_loop = g_main_loop_new(NULL, FALSE);
-
- sys = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
- if (!sys) {
- fprintf(stderr, "Can't get on system bus");
- exit(1);
- }
-
- session = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
- if (!session) {
- fprintf(stderr, "Can't get on session bus");
- exit(1);
- }
-
- owner_watch = g_dbus_add_signal_watch(session, NULL, NULL,
- DBUS_INTERFACE_DBUS,
- "NameOwnerChanged",
- name_owner_changed,
- NULL, NULL);
-
- properties_watch = g_dbus_add_properties_watch(session, NULL, NULL,
- MPRIS_PLAYER_INTERFACE,
- player_signal,
- NULL, NULL);
-
- signal_watch = g_dbus_add_signal_watch(session, NULL, NULL,
- MPRIS_PLAYER_INTERFACE,
- NULL, player_signal,
- NULL, NULL);
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_flags = SA_NOCLDSTOP;
- sa.sa_handler = sig_term;
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
-
- client = g_dbus_client_new(sys, BLUEZ_BUS_NAME, BLUEZ_PATH);
-
- g_dbus_client_set_connect_watch(client, connect_handler, NULL);
- g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
-
- g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
- property_changed, NULL);
-
- g_main_loop_run(main_loop);
-
- g_dbus_remove_watch(session, owner_watch);
- g_dbus_remove_watch(session, properties_watch);
- g_dbus_remove_watch(session, signal_watch);
-
- g_dbus_client_unref(client);
-
- dbus_connection_unref(session);
- dbus_connection_unref(sys);
-
- g_main_loop_unref(main_loop);
-
- return 0;
-}
diff --git a/tools/mpris-proxy.c b/tools/mpris-proxy.c
index 397f0647..693055ed 100644
--- a/tools/mpris-proxy.c
+++ b/tools/mpris-proxy.c
@@ -36,7 +36,8 @@
#include <dbus/dbus.h>
#include <glib.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
#define BLUEZ_BUS_NAME "org.bluez"
#define BLUEZ_PATH "/org/bluez"
diff --git a/tools/obex-client-tool.c b/tools/obex-client-tool.c
index 4716a8c1..4f931f6d 100644
--- a/tools/obex-client-tool.c
+++ b/tools/obex-client-tool.c
@@ -36,7 +36,7 @@
#include <readline/readline.h>
#include <readline/history.h>
-#include <gobex/gobex.h>
+#include "gobex/gobex.h"
#include "btio/btio.h"
static GMainLoop *main_loop = NULL;
diff --git a/tools/obex-server-tool.c b/tools/obex-server-tool.c
index 3fed6dc9..a16c46f8 100644
--- a/tools/obex-server-tool.c
+++ b/tools/obex-server-tool.c
@@ -33,7 +33,7 @@
#include <string.h>
#include <errno.h>
-#include <gobex/gobex.h>
+#include "gobex/gobex.h"
#include "btio/btio.h"
static GMainLoop *main_loop = NULL;
diff --git a/tools/obexctl.c b/tools/obexctl.c
index 512a145a..4faff6b6 100644
--- a/tools/obexctl.c
+++ b/tools/obexctl.c
@@ -33,13 +33,14 @@
#include <signal.h>
#include <sys/signalfd.h>
#include <inttypes.h>
+#include <wordexp.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <glib.h>
-#include <gdbus.h>
-#include <client/display.h>
+#include "gdbus/gdbus.h"
+#include "client/display.h"
/* String display constants */
#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
@@ -1232,7 +1233,6 @@ static void list_messages_reply(DBusMessage *message, void *user_data)
{
DBusError error;
DBusMessageIter iter, array;
- int ctype;
dbus_error_init(&error);
@@ -1249,8 +1249,8 @@ static void list_messages_reply(DBusMessage *message, void *user_data)
dbus_message_iter_recurse(&iter, &array);
- while ((ctype = dbus_message_iter_get_arg_type(&array)) ==
- DBUS_TYPE_DICT_ENTRY) {
+ while ((dbus_message_iter_get_arg_type(&array)) ==
+ DBUS_TYPE_DICT_ENTRY) {
DBusMessageIter entry;
const char *obj;
@@ -2030,8 +2030,9 @@ static char **cmd_completion(const char *text, int start, int end)
static void rl_handler(char *input)
{
+ wordexp_t w;
int argc;
- char **argv = NULL;
+ char **argv;
int i;
if (!input) {
@@ -2045,18 +2046,16 @@ static void rl_handler(char *input)
if (!strlen(input))
goto done;
- g_strstrip(input);
add_history(input);
- argv = g_strsplit(input, " ", -1);
- if (argv == NULL)
+ if (wordexp(input, &w, WRDE_NOCMD))
goto done;
- for (argc = 0; argv[argc];)
- argc++;
+ if (w.we_wordc == 0)
+ goto free_we;
- if (argc == 0)
- goto done;
+ argv = w.we_wordv;
+ argc = w.we_wordc;
for (i = 0; cmd_table[i].cmd; i++) {
if (strcmp(argv[0], cmd_table[i].cmd))
@@ -2064,13 +2063,13 @@ static void rl_handler(char *input)
if (cmd_table[i].func) {
cmd_table[i].func(argc, argv);
- goto done;
+ goto free_we;
}
}
if (strcmp(argv[0], "help")) {
printf("Invalid command\n");
- goto done;
+ goto free_we;
}
printf("Available commands:\n");
@@ -2083,8 +2082,9 @@ static void rl_handler(char *input)
cmd_table[i].desc ? : "");
}
+free_we:
+ wordfree(&w);
done:
- g_strfreev(argv);
free(input);
}
diff --git a/tools/oobtest.c b/tools/oobtest.c
new file mode 100644
index 00000000..9cc6c162
--- /dev/null
+++ b/tools/oobtest.c
@@ -0,0 +1,800 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <getopt.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "src/shared/mainloop.h"
+#include "src/shared/util.h"
+#include "src/shared/mgmt.h"
+
+static bool use_bredr = false;
+static bool use_le = false;
+static bool use_sc = false;
+static bool use_sconly = false;
+static bool use_legacy = false;
+static bool use_random = false;
+static bool use_debug = false;
+static bool use_cross = false;
+static bool provide_p192 = false;
+static bool provide_p256 = false;
+
+static struct mgmt *mgmt;
+static uint16_t index1 = MGMT_INDEX_NONE;
+static uint16_t index2 = MGMT_INDEX_NONE;
+static bdaddr_t bdaddr1;
+static bdaddr_t bdaddr2;
+
+static void pin_code_request_event(uint16_t index, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_pin_code_request *ev = param;
+ struct mgmt_cp_pin_code_reply cp;
+ char str[18];
+
+ ba2str(&ev->addr.bdaddr, str);
+
+ printf("[Index %u]\n", index);
+ printf(" Pin code request: %s\n", str);
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
+ cp.pin_len = 4;
+ memset(cp.pin_code, '0', 4);
+
+ mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, sizeof(cp), &cp,
+ NULL, NULL, NULL);
+}
+
+static void new_link_key_event(uint16_t index, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_new_link_key *ev = param;
+ const char *type;
+ char str[18];
+ int i;
+
+ ba2str(&ev->key.addr.bdaddr, str);
+
+ switch (ev->key.type) {
+ case 0x00:
+ type = "Legacy";
+ break;
+ case 0x01:
+ type = "Local Unit";
+ break;
+ case 0x02:
+ type = "Remote Unit";
+ break;
+ case 0x03:
+ type = "Debug";
+ break;
+ case 0x04:
+ type = "Unauthenticated, P-192";
+ break;
+ case 0x05:
+ type = "Authenticated, P-192";
+ break;
+ case 0x06:
+ type = "Changed";
+ break;
+ case 0x07:
+ type = "Unauthenticated, P-256";
+ break;
+ case 0x08:
+ type = "Authenticated, P-256";
+ break;
+ default:
+ type = "<unknown>";
+ break;
+ }
+
+ printf("[Index %u]\n", index);
+ printf(" New link key: %s\n", str);
+ printf(" Type: %s (%u)\n", type, ev->key.type);
+ printf(" Key: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", ev->key.val[i]);
+ printf("\n");
+}
+
+static void new_long_term_key_event(uint16_t index, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_new_long_term_key *ev = param;
+ const char *type;
+ char str[18];
+ int i;
+
+ ba2str(&ev->key.addr.bdaddr, str);
+
+ switch (ev->key.type) {
+ case 0x00:
+ if (ev->key.master)
+ type = "Unauthenticated, Master";
+ else
+ type = "Unauthenticated, Slave";
+ break;
+ case 0x01:
+ if (ev->key.master)
+ type = "Authenticated, Master";
+ else
+ type = "Authenticated, Slave";
+ break;
+ case 0x02:
+ type = "Unauthenticated, P-256";
+ break;
+ case 0x03:
+ type = "Authenticated, P-256";
+ break;
+ case 0x04:
+ type = "Debug";
+ break;
+ default:
+ type = "<unknown>";
+ break;
+ }
+
+ printf("[Index %u]\n", index);
+ printf(" New long term key: %s\n", str);
+ printf(" Type: %s (%u)\n", type, ev->key.type);
+ printf(" Key: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", ev->key.val[i]);
+ printf("\n");
+}
+
+static void pair_device_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ uint16_t index = PTR_TO_UINT(user_data);
+
+ if (status) {
+ fprintf(stderr, "Pair device from index %u failed: %s\n",
+ index, mgmt_errstr(status));
+ }
+
+ mainloop_quit();
+}
+
+static void pair_device(uint16_t index, const bdaddr_t *bdaddr)
+{
+ struct mgmt_cp_pair_device cp;
+ char str[18];
+
+ ba2str(bdaddr, str);
+
+ printf("[Index %u]\n", index);
+ printf(" Starting pairing: %s\n", str);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, bdaddr);
+ if (use_bredr)
+ cp.addr.type = BDADDR_BREDR;
+ else if (use_random)
+ cp.addr.type = BDADDR_LE_RANDOM;
+ else
+ cp.addr.type = BDADDR_LE_PUBLIC;
+ cp.io_cap = 0x03;
+
+ mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
+ pair_device_complete,
+ UINT_TO_PTR(index), NULL);
+}
+
+static void add_remote_oob_data_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_addr_info *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ char str[18];
+
+ if (status) {
+ fprintf(stderr, "Adding OOB data for index %u failed: %s\n",
+ index, mgmt_errstr(status));
+ }
+
+ ba2str(&rp->bdaddr, str);
+
+ printf("[Index %u]\n", index);
+ printf(" Remote data added: %s\n", str);
+
+ if (index == index1) {
+ uint8_t val = 0x01;
+
+ mgmt_send(mgmt, MGMT_OP_SET_CONNECTABLE, index2, 1, &val,
+ NULL, NULL, NULL);
+
+ if (use_le)
+ mgmt_send(mgmt, MGMT_OP_SET_ADVERTISING, index2,
+ 1, &val, NULL, NULL, NULL);
+
+ pair_device(index1, &bdaddr2);
+ }
+}
+
+static void add_remote_oob_data(uint16_t index, const bdaddr_t *bdaddr,
+ const uint8_t *hash192, const uint8_t *rand192,
+ const uint8_t *hash256, const uint8_t *rand256)
+{
+ struct mgmt_cp_add_remote_oob_data cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, bdaddr);
+ if (use_bredr)
+ cp.addr.type = BDADDR_BREDR;
+ else if (use_random)
+ cp.addr.type = BDADDR_LE_RANDOM;
+ else
+ cp.addr.type = BDADDR_LE_PUBLIC;
+ if (hash192 && rand192) {
+ memcpy(cp.hash192, hash192, 16);
+ memcpy(cp.rand192, rand192, 16);
+ } else {
+ memset(cp.hash192, 0, 16);
+ memset(cp.rand192, 0, 16);
+ }
+ if (hash256 && rand256) {
+ memcpy(cp.hash256, hash256, 16);
+ memcpy(cp.rand256, rand256, 16);
+ } else {
+ memset(cp.hash256, 0, 16);
+ memset(cp.rand256, 0, 16);
+ }
+
+ mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index, sizeof(cp), &cp,
+ add_remote_oob_data_complete,
+ UINT_TO_PTR(index), NULL);
+}
+
+static void read_oob_data_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_local_oob_ext_data *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ const uint8_t *hash192, *rand192, *hash256, *rand256;
+ int i;
+
+ if (status) {
+ fprintf(stderr, "Reading OOB data for index %u failed: %s\n",
+ index, mgmt_errstr(status));
+ mainloop_quit();
+ return;
+ }
+
+ printf("[Index %u]\n", index);
+
+ if (provide_p192) {
+ hash192 = rp->hash192;
+ rand192 = rp->randomizer192;
+ } else {
+ hash192 = NULL;
+ rand192 = NULL;
+ }
+
+ printf(" Hash C from P-192: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", rp->hash192[i]);
+ printf("\n");
+
+ printf(" Randomizer R with P-192: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", rp->randomizer192[i]);
+ printf("\n");
+
+ if (len < sizeof(*rp)) {
+ hash256 = NULL;
+ rand256 = NULL;
+ goto done;
+ }
+
+ if (provide_p256) {
+ hash256 = rp->hash256;
+ rand256 = rp->randomizer256;
+ } else {
+ hash256 = NULL;
+ rand256 = NULL;
+ }
+
+ printf(" Hash C from P-256: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", rp->hash256[i]);
+ printf("\n");
+
+ printf(" Randomizer R with P-256: ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", rp->randomizer256[i]);
+ printf("\n");
+
+done:
+ if (index == index1)
+ add_remote_oob_data(index2, &bdaddr1,
+ hash192, rand192, hash256, rand256);
+ else if (index == index2)
+ add_remote_oob_data(index1, &bdaddr2,
+ hash192, rand192, hash256, rand256);
+}
+
+static void set_powered_complete(uint8_t status, uint16_t len,
+ const void *param, void *user_data)
+{
+ uint16_t index = PTR_TO_UINT(user_data);
+ uint32_t settings;
+ uint8_t val;
+
+ if (status) {
+ fprintf(stderr, "Powering on for index %u failed: %s\n",
+ index, mgmt_errstr(status));
+ mainloop_quit();
+ return;
+ }
+
+ settings = get_le32(param);
+
+ if (!(settings & MGMT_SETTING_POWERED)) {
+ fprintf(stderr, "Controller is not powered\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_debug) {
+ if (index == index1) {
+ val = 0x02;
+ mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+ NULL, NULL, NULL);
+ } else if (index == index2) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+ }
+
+ if (use_bredr && (provide_p192 || provide_p256)) {
+ mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
+ read_oob_data_complete,
+ UINT_TO_PTR(index), NULL);
+ } else {
+ if (index == index1)
+ add_remote_oob_data(index2, &bdaddr1,
+ NULL, NULL, NULL, NULL);
+ else if (index == index2)
+ add_remote_oob_data(index1, &bdaddr2,
+ NULL, NULL, NULL, NULL);
+ }
+}
+
+static void clear_link_keys(uint16_t index)
+{
+ struct mgmt_cp_load_link_keys cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.debug_keys = 0x00;
+ cp.key_count = cpu_to_le16(0);
+
+ mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index,
+ sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void clear_long_term_keys(uint16_t index)
+{
+ struct mgmt_cp_load_long_term_keys cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.key_count = cpu_to_le16(0);
+
+ mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index,
+ sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void clear_remote_oob_data(uint16_t index)
+{
+ struct mgmt_cp_remove_remote_oob_data cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, BDADDR_ANY);
+ cp.addr.type = BDADDR_BREDR;
+
+ mgmt_send(mgmt, MGMT_OP_REMOVE_REMOTE_OOB_DATA, index,
+ sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void read_info(uint8_t status, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_rp_read_info *rp = param;
+ uint16_t index = PTR_TO_UINT(user_data);
+ uint32_t supported_settings;
+ uint8_t val;
+ char str[18];
+
+ if (status) {
+ fprintf(stderr, "Reading info for index %u failed: %s\n",
+ index, mgmt_errstr(status));
+ mainloop_quit();
+ return;
+ }
+
+ ba2str(&rp->bdaddr, str);
+
+ printf("[Index %u]\n", index);
+ printf(" Address: %s\n", str);
+
+ if (index == index1)
+ bacpy(&bdaddr1, &rp->bdaddr);
+ else if (index == index2)
+ bacpy(&bdaddr2, &rp->bdaddr);
+
+ supported_settings = le32_to_cpu(rp->supported_settings);
+
+ if (use_bredr && !(supported_settings & MGMT_SETTING_BREDR)) {
+ fprintf(stderr, "BR/EDR support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (!use_legacy && !(supported_settings & MGMT_SETTING_SSP)) {
+ fprintf(stderr, "Secure Simple Pairing support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_le && !(supported_settings & MGMT_SETTING_LE)) {
+ fprintf(stderr, "Low Energy support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_sc && !(supported_settings & MGMT_SETTING_SECURE_CONN)) {
+ fprintf(stderr, "Secure Connections support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_sconly && !(supported_settings & MGMT_SETTING_SECURE_CONN)) {
+ fprintf(stderr, "Secure Connections Only support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_debug && !(supported_settings & MGMT_SETTING_DEBUG_KEYS)) {
+ fprintf(stderr, "Debug keys support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_cross && (!(supported_settings & MGMT_SETTING_BREDR) ||
+ !(supported_settings & MGMT_SETTING_LE))) {
+ fprintf(stderr, "Dual-mode support is support missing\n");
+ mainloop_quit();
+ return;
+ }
+
+ mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index,
+ pin_code_request_event,
+ UINT_TO_PTR(index), NULL);
+
+ mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index,
+ new_link_key_event,
+ UINT_TO_PTR(index), NULL);
+
+ mgmt_register(mgmt, MGMT_EV_NEW_LONG_TERM_KEY, index,
+ new_long_term_key_event,
+ UINT_TO_PTR(index), NULL);
+
+ val = 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
+ NULL, NULL, NULL);
+
+ clear_link_keys(index);
+ clear_long_term_keys(index);
+ clear_remote_oob_data(index);
+
+ if (use_bredr) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
+ NULL, NULL, NULL);
+
+ val = use_cross ? 0x01 : 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
+ NULL, NULL, NULL);
+
+ val = use_legacy ? 0x00 : 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_SSP, index, 1, &val,
+ NULL, NULL, NULL);
+ } else if (use_le) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
+ NULL, NULL, NULL);
+
+ val = use_cross ? 0x01 : 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
+ NULL, NULL, NULL);
+ } else {
+ fprintf(stderr, "Invalid transport for pairing\n");
+ mainloop_quit();
+ return;
+ }
+
+ if (use_random) {
+ bdaddr_t bdaddr;
+
+ str2ba("c0:00:aa:bb:00:00", &bdaddr);
+ bdaddr.b[0] = index;
+
+ mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
+ 6, &bdaddr, NULL, NULL, NULL);
+
+ if (index == index1)
+ bacpy(&bdaddr1, &bdaddr);
+ else if (index == index2)
+ bacpy(&bdaddr2, &bdaddr);
+ } else {
+ bdaddr_t bdaddr;
+
+ bacpy(&bdaddr, BDADDR_ANY);
+
+ mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
+ 6, &bdaddr, NULL, NULL, NULL);
+ }
+
+ if (use_sc) {
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+ NULL, NULL, NULL);
+ } else if (use_sconly) {
+ val = 0x02;
+ mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+ NULL, NULL, NULL);
+ } else {
+ val = 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+ NULL, NULL, NULL);
+ }
+
+ val = 0x00;
+ mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+ NULL, NULL, NULL);
+
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, 1, &val,
+ NULL, NULL, NULL);
+
+ val = 0x01;
+ mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
+ set_powered_complete,
+ UINT_TO_PTR(index), NULL);
+}
+
+static void read_index_list(uint8_t status, uint16_t len, const void *param,
+ void *user_data)
+{
+ const struct mgmt_rp_read_index_list *rp = param;
+ uint16_t count;
+ int i;
+
+ if (status) {
+ fprintf(stderr, "Reading index list failed: %s\n",
+ mgmt_errstr(status));
+ mainloop_quit();
+ return;
+ }
+
+ count = le16_to_cpu(rp->num_controllers);
+
+ if (count < 2) {
+ fprintf(stderr, "At least 2 controllers are required\n");
+ mainloop_quit();
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ uint16_t index = cpu_to_le16(rp->index[i]);
+
+ if (index < index1)
+ index1 = index;
+ }
+
+ for (i = 0; i < count; i++) {
+ uint16_t index = cpu_to_le16(rp->index[i]);
+
+ if (index < index2 && index > index1)
+ index2 = index;
+ }
+
+ printf("Selecting index %u for initiator\n", index1);
+ printf("Selecting index %u for acceptor\n", index2);
+
+ mgmt_send(mgmt, MGMT_OP_READ_INFO, index1, 0, NULL,
+ read_info, UINT_TO_PTR(index1), NULL);
+ mgmt_send(mgmt, MGMT_OP_READ_INFO, index2, 0, NULL,
+ read_info, UINT_TO_PTR(index2), NULL);
+}
+
+static void signal_callback(int signum, void *user_data)
+{
+ switch (signum) {
+ case SIGINT:
+ case SIGTERM:
+ mainloop_quit();
+ break;
+ }
+}
+
+static void usage(void)
+{
+ printf("oobtest - Out-of-band pairing testing\n"
+ "Usage:\n");
+ printf("\toobtest [options]\n");
+ printf("options:\n"
+ "\t-B, --bredr Use BR/EDR transport\n"
+ "\t-L, --le Use LE transport\n"
+ "\t-S, --sc Use Secure Connections\n"
+ "\t-O, --sconly Use Secure Connections Only\n"
+ "\t-P, --legacy Use Legacy Pairing\n"
+ "\t-R, --random Use Static random address\n"
+ "\t-D, --debug Use Pairing debug keys\n"
+ "\t-C, --cross Use cross-transport pairing\n"
+ "\t-1, --p192 Provide P-192 OOB data\n"
+ "\t-2, --p256 Provide P-256 OOB data\n"
+ "\t-h, --help Show help options\n");
+}
+
+static const struct option main_options[] = {
+ { "bredr", no_argument, NULL, 'B' },
+ { "le", no_argument, NULL, 'L' },
+ { "sc", no_argument, NULL, 'S' },
+ { "sconly", no_argument, NULL, 'O' },
+ { "legacy", no_argument, NULL, 'P' },
+ { "random", no_argument, NULL, 'R' },
+ { "static", no_argument, NULL, 'R' },
+ { "debug", no_argument, NULL, 'D' },
+ { "cross", no_argument, NULL, 'C' },
+ { "dual", no_argument, NULL, 'C' },
+ { "p192", no_argument, NULL, '1' },
+ { "p256", no_argument, NULL, '2' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { }
+};
+
+int main(int argc ,char *argv[])
+{
+ sigset_t mask;
+ int exit_status;
+
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "BLSOPRDC12vh",
+ main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'B':
+ use_bredr = true;
+ break;
+ case 'L':
+ use_le = true;
+ break;
+ case 'S':
+ use_sc = true;
+ break;
+ case 'O':
+ use_sconly = true;
+ break;
+ case 'P':
+ use_legacy = true;
+ break;
+ case 'R':
+ use_random = true;
+ break;
+ case 'D':
+ use_debug = true;
+ break;
+ case 'C':
+ use_cross = true;
+ break;
+ case '1':
+ provide_p192 = true;
+ break;
+ case '2':
+ provide_p256 = true;
+ break;
+ case 'v':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (argc - optind > 0) {
+ fprintf(stderr, "Invalid command line parameters\n");
+ return EXIT_FAILURE;
+ }
+
+ if (use_bredr == use_le) {
+ fprintf(stderr, "Specify either --bredr or --le\n");
+ return EXIT_FAILURE;
+ }
+
+ if (use_legacy && !use_bredr) {
+ fprintf(stderr, "Specify --legacy with --bredr\n");
+ return EXIT_FAILURE;
+ }
+
+ if (use_random && !use_le) {
+ fprintf(stderr, "Specify --random with --le\n");
+ return EXIT_FAILURE;
+ }
+
+ if (use_random && use_cross) {
+ fprintf(stderr, "Only --random or --cross can be used\n");
+ return EXIT_FAILURE;
+ }
+
+ if (use_sc && use_sconly) {
+ fprintf(stderr, "Only --sc or --sconly can be used\n");
+ return EXIT_FAILURE;
+ }
+
+ mainloop_init();
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+ mgmt = mgmt_new_default();
+ if (!mgmt) {
+ fprintf(stderr, "Failed to open management socket\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
+ MGMT_INDEX_NONE, 0, NULL,
+ read_index_list, NULL, NULL)) {
+ fprintf(stderr, "Failed to read index list\n");
+ exit_status = EXIT_FAILURE;
+ goto done;
+ }
+
+ exit_status = mainloop_run();
+
+done:
+ mgmt_unref(mgmt);
+
+ return exit_status;
+}
diff --git a/tools/parser/hci.c b/tools/parser/hci.c
index cd52cb53..0918eeea 100644
--- a/tools/parser/hci.c
+++ b/tools/parser/hci.c
@@ -127,7 +127,7 @@ static char *event_str[EVENT_NUM + 1] = {
"AMP Status Change",
};
-#define LE_EV_NUM 5
+#define LE_EV_NUM 11
static char *ev_le_meta_str[LE_EV_NUM + 1] = {
"Unknown",
"LE Connection Complete",
@@ -135,6 +135,12 @@ static char *ev_le_meta_str[LE_EV_NUM + 1] = {
"LE Connection Update Complete",
"LE Read Remote Used Features Complete",
"LE Long Term Key Request",
+ "LE Remote Connection Parameter Request",
+ "LE Data Length Change",
+ "LE Read Local P-256 Public Key Complete",
+ "LE Generate DHKey Complete",
+ "LE Enhanced Connection Complete",
+ "LE Direct Advertising Report",
};
#define CMD_LINKCTL_NUM 60
@@ -446,9 +452,9 @@ static char *error_code_str[ERROR_CODE_NUM + 1] = {
"SCO Offset Rejected",
"SCO Interval Rejected",
"SCO Air Mode Rejected",
- "Invalid LMP Parameters",
+ "Invalid LMP Parameters / Invalid LL Parameters",
"Unspecified Error",
- "Unsupported LMP Parameter Value",
+ "Unsupported LMP Parameter Value / Unsupported LL Parameter Value",
"Role Change Not Allowed",
"LMP Response Timeout",
"LMP Error Transaction Collision",
@@ -475,7 +481,7 @@ static char *error_code_str[ERROR_CODE_NUM + 1] = {
"Host Busy - Pairing",
"Connection Rejected due to No Suitable Channel Found",
"Controller Busy",
- "Unacceptable Connection Interval",
+ "Unacceptable Connection Parameters",
"Directed Advertising Timeout",
"Connection Terminated Due to MIC Failure",
"Connection Failed to be Established",
@@ -3667,7 +3673,11 @@ static inline void le_meta_ev_dump(int level, struct frame *frm)
frm->len -= EVT_LE_META_EVENT_SIZE;
p_indent(level, frm);
- printf("%s\n", ev_le_meta_str[subevent]);
+
+ if (subevent <= LE_EV_NUM)
+ printf("%s\n", ev_le_meta_str[subevent]);
+ else
+ printf("%s\n", ev_le_meta_str[0]);
switch (mevt->subevent) {
case EVT_LE_CONN_COMPLETE:
diff --git a/tools/rctest.c b/tools/rctest.c
index 11ae37fb..bdc1eb56 100644
--- a/tools/rctest.c
+++ b/tools/rctest.c
@@ -40,12 +40,12 @@
#include <sys/socket.h>
#include <sys/stat.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/rfcomm.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
#include "src/shared/util.h"
diff --git a/tools/rfcomm-tester.c b/tools/rfcomm-tester.c
index ba324bef..55b6ac63 100644
--- a/tools/rfcomm-tester.c
+++ b/tools/rfcomm-tester.c
@@ -409,20 +409,20 @@ static gboolean client_received_data(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_client_data *client_data = data->test_data;
+ const struct rfcomm_client_data *cli = data->test_data;
int sk;
ssize_t ret;
char buf[248];
sk = g_io_channel_unix_get_fd(io);
- ret = read(sk, buf, client_data->data_len);
- if (client_data->data_len != ret) {
+ ret = read(sk, buf, cli->data_len);
+ if (cli->data_len != ret) {
tester_test_failed();
return false;
}
- if (memcmp(client_data->read_data, buf, client_data->data_len))
+ if (memcmp(cli->read_data, buf, cli->data_len))
tester_test_failed();
else
tester_test_passed();
@@ -431,13 +431,15 @@ static gboolean client_received_data(GIOChannel *io, GIOCondition cond,
}
static gboolean rc_connect_cb(GIOChannel *io, GIOCondition cond,
- gpointer user_data)
+ gpointer user_data)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_client_data *client_data = data->test_data;
+ const struct rfcomm_client_data *cli = data->test_data;
socklen_t len = sizeof(int);
int sk, err, sk_err;
+ tester_print("Connected");
+
data->io_id = 0;
sk = g_io_channel_unix_get_fd(io);
@@ -447,27 +449,30 @@ static gboolean rc_connect_cb(GIOChannel *io, GIOCondition cond,
else
err = -sk_err;
- if (client_data->expected_connect_err &&
- err == client_data->expected_connect_err) {
+ if (cli->expected_connect_err && err == cli->expected_connect_err) {
tester_test_passed();
return false;
}
- if (client_data->send_data) {
+ if (cli->send_data) {
ssize_t ret;
- ret = write(sk, client_data->send_data, client_data->data_len);
- if (client_data->data_len != ret)
+ tester_print("Writing %u bytes of data", cli->data_len);
+
+ ret = write(sk, cli->send_data, cli->data_len);
+ if (cli->data_len != ret) {
+ tester_warn("Failed to write %u bytes: %s (%d)",
+ cli->data_len, strerror(errno), errno);
tester_test_failed();
+ }
return false;
- } else if (client_data->read_data) {
+ } else if (cli->read_data) {
g_io_add_watch(io, G_IO_IN, client_received_data, NULL);
bthost_send_rfcomm_data(hciemu_client_get_host(data->hciemu),
data->conn_handle,
- client_data->client_channel,
- client_data->read_data,
- client_data->data_len);
+ cli->client_channel,
+ cli->read_data, cli->data_len);
return false;
}
@@ -483,15 +488,17 @@ static void client_hook_func(const void *data, uint16_t len,
void *user_data)
{
struct test_data *test_data = tester_get_data();
- const struct rfcomm_client_data *client_data = test_data->test_data;
+ const struct rfcomm_client_data *cli = test_data->test_data;
ssize_t ret;
- if (client_data->data_len != len) {
+ tester_print("bthost received %u bytes of data", len);
+
+ if (cli->data_len != len) {
tester_test_failed();
return;
}
- ret = memcmp(client_data->send_data, data, len);
+ ret = memcmp(cli->send_data, data, len);
if (ret)
tester_test_failed();
else
@@ -502,15 +509,15 @@ static void server_hook_func(const void *data, uint16_t len,
void *user_data)
{
struct test_data *test_data = tester_get_data();
- const struct rfcomm_server_data *server_data = test_data->test_data;
+ const struct rfcomm_server_data *srv = test_data->test_data;
ssize_t ret;
- if (server_data->data_len != len) {
+ if (srv->data_len != len) {
tester_test_failed();
return;
}
- ret = memcmp(server_data->send_data, data, len);
+ ret = memcmp(srv->send_data, data, len);
if (ret)
tester_test_failed();
else
@@ -521,14 +528,14 @@ static void rfcomm_connect_cb(uint16_t handle, uint16_t cid,
void *user_data, bool status)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_client_data *client_data = data->test_data;
+ const struct rfcomm_client_data *cli = data->test_data;
struct bthost *bthost = hciemu_client_get_host(data->hciemu);
- if (client_data->send_data)
+ if (cli->send_data)
bthost_add_rfcomm_chan_hook(bthost, handle,
- client_data->client_channel,
+ cli->client_channel,
client_hook_func, NULL);
- else if (client_data->read_data)
+ else if (cli->read_data)
data->conn_handle = handle;
}
@@ -536,13 +543,13 @@ static void test_connect(const void *test_data)
{
struct test_data *data = tester_get_data();
struct bthost *bthost = hciemu_client_get_host(data->hciemu);
- const struct rfcomm_client_data *client_data = data->test_data;
+ const struct rfcomm_client_data *cli = data->test_data;
const uint8_t *client_addr, *master_addr;
GIOChannel *io;
int sk;
bthost_add_l2cap_server(bthost, 0x0003, NULL, NULL);
- bthost_add_rfcomm_server(bthost, client_data->server_channel,
+ bthost_add_rfcomm_server(bthost, cli->server_channel,
rfcomm_connect_cb, NULL);
master_addr = hciemu_get_master_bdaddr(data->hciemu);
@@ -551,7 +558,7 @@ static void test_connect(const void *test_data)
sk = create_rfcomm_sock((bdaddr_t *) master_addr, 0);
if (connect_rfcomm_sock(sk, (const bdaddr_t *) client_addr,
- client_data->client_channel) < 0) {
+ cli->client_channel) < 0) {
close(sk);
tester_test_failed();
return;
@@ -571,20 +578,20 @@ static gboolean server_received_data(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_server_data *server_data = data->test_data;
+ const struct rfcomm_server_data *srv = data->test_data;
char buf[1024];
ssize_t ret;
int sk;
sk = g_io_channel_unix_get_fd(io);
- ret = read(sk, buf, server_data->data_len);
- if (ret != server_data->data_len) {
+ ret = read(sk, buf, srv->data_len);
+ if (ret != srv->data_len) {
tester_test_failed();
return false;
}
- if (memcmp(buf, server_data->read_data, server_data->data_len))
+ if (memcmp(buf, srv->read_data, srv->data_len))
tester_test_failed();
else
tester_test_passed();
@@ -596,7 +603,7 @@ static gboolean rfcomm_listen_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_server_data *server_data = data->test_data;
+ const struct rfcomm_server_data *srv = data->test_data;
int sk, new_sk;
data->io_id = 0;
@@ -609,17 +616,16 @@ static gboolean rfcomm_listen_cb(GIOChannel *io, GIOCondition cond,
return false;
}
- if (server_data->send_data) {
+ if (srv->send_data) {
ssize_t ret;
- ret = write(new_sk, server_data->send_data,
- server_data->data_len);
- if (ret != server_data->data_len)
+ ret = write(new_sk, srv->send_data, srv->data_len);
+ if (ret != srv->data_len)
tester_test_failed();
close(new_sk);
return false;
- } else if (server_data->read_data) {
+ } else if (srv->read_data) {
GIOChannel *new_io;
new_io = g_io_channel_unix_new(new_sk);
@@ -643,21 +649,20 @@ static void connection_cb(uint16_t handle, uint16_t cid, void *user_data,
bool status)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_server_data *server_data = data->test_data;
+ const struct rfcomm_server_data *srv = data->test_data;
struct bthost *bthost = hciemu_client_get_host(data->hciemu);
- if (server_data->read_data) {
+ if (srv->read_data) {
data->conn_handle = handle;
bthost_send_rfcomm_data(bthost, data->conn_handle,
- server_data->client_channel,
- server_data->read_data,
- server_data->data_len);
+ srv->client_channel,
+ srv->read_data, srv->data_len);
return;
- } else if (server_data->data_len) {
+ } else if (srv->data_len) {
return;
}
- if (server_data->expected_status == status)
+ if (srv->expected_status == status)
tester_test_passed();
else
tester_test_failed();
@@ -666,21 +671,20 @@ static void connection_cb(uint16_t handle, uint16_t cid, void *user_data,
static void client_new_conn(uint16_t handle, void *user_data)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_server_data *server_data = data->test_data;
+ const struct rfcomm_server_data *srv = data->test_data;
struct bthost *bthost;
bthost = hciemu_client_get_host(data->hciemu);
- bthost_add_rfcomm_chan_hook(bthost, handle,
- server_data->client_channel,
+ bthost_add_rfcomm_chan_hook(bthost, handle, srv->client_channel,
server_hook_func, NULL);
- bthost_connect_rfcomm(bthost, handle, server_data->client_channel,
+ bthost_connect_rfcomm(bthost, handle, srv->client_channel,
connection_cb, NULL);
}
static void test_server(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct rfcomm_server_data *server_data = data->test_data;
+ const struct rfcomm_server_data *srv = data->test_data;
const uint8_t *master_addr;
struct bthost *bthost;
GIOChannel *io;
@@ -688,8 +692,7 @@ static void test_server(const void *test_data)
master_addr = hciemu_get_master_bdaddr(data->hciemu);
- sk = create_rfcomm_sock((bdaddr_t *) master_addr,
- server_data->server_channel);
+ sk = create_rfcomm_sock((bdaddr_t *) master_addr, srv->server_channel);
if (sk < 0) {
tester_test_failed();
return;
diff --git a/tools/rfcomm.c b/tools/rfcomm.c
index 659bbec0..809c2404 100644
--- a/tools/rfcomm.c
+++ b/tools/rfcomm.c
@@ -40,10 +40,10 @@
#include <sys/socket.h>
#include <sys/wait.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/rfcomm.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/rfcomm.h"
static int rfcomm_raw_tty = 0;
static int auth = 0;
diff --git a/tools/scotest.c b/tools/scotest.c
index d033ae0b..596e403c 100644
--- a/tools/scotest.c
+++ b/tools/scotest.c
@@ -37,8 +37,8 @@
#include <sys/time.h>
#include <sys/socket.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sco.h>
+#include "lib/bluetooth.h"
+#include "lib/sco.h"
#include "src/shared/util.h"
diff --git a/tools/sdptool.c b/tools/sdptool.c
index 1fef8006..891d3883 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -36,15 +36,14 @@
#include <string.h>
#include <getopt.h>
#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
#include <netinet/in.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
#include "src/sdp-xml.h"
#ifndef APPLE_AGENT_SVCLASS_ID
diff --git a/tools/update_compids.sh b/tools/update_compids.sh
index 95c961d6..95c961d6 100755..100644
--- a/tools/update_compids.sh
+++ b/tools/update_compids.sh