Merge BlueZ 5.20 into master
Change-Id: I2d69df1b233a4e0135fd5137bc792a7040897f2a
diff --git a/Makefile.plugins b/Makefile.plugins
index 7a02d9f..dbcb491 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -5,6 +5,9 @@
builtin_modules += wiimote
builtin_sources += plugins/wiimote.c
+builtin_modules += gfrm
+builtin_sources += plugins/gfrm.c
+
builtin_modules += autopair
builtin_sources += plugins/autopair.c
diff --git a/Makefile.tools b/Makefile.tools
index c24bdf7..966dd64 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -176,7 +176,8 @@
if TOOLS
bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
tools/rfcomm tools/rctest tools/l2test tools/l2ping \
- tools/sdptool tools/ciptool tools/bccmd tools/bluemoon
+ tools/sdptool tools/ciptool tools/bccmd tools/bluemoon \
+ tools/btmgmt
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_st.c \
@@ -248,6 +249,14 @@
src/shared/queue.h src/shared/queue.c \
src/shared/ringbuf.h src/shared/ringbuf.c
+tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c \
+ monitor/mainloop.h monitor/mainloop.c \
+ src/shared/io.h src/shared/io-mainloop.c \
+ src/shared/queue.h src/shared/queue.c \
+ src/shared/util.h src/shared/util.c \
+ src/shared/mgmt.h src/shared/mgmt.c
+tools_btmgmt_LDADD = lib/libbluetooth-internal.la
+
dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
tools/hcitool.1 tools/hcidump.1 \
tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
@@ -421,4 +430,4 @@
test/service-ftp.xml test/simple-player test/test-nap \
test/test-heartrate test/test-alert test/test-hfp \
test/test-cyclingspeed test/opp-client test/ftp-client \
- test/pbap-client test/map-client
+ test/pbap-client test/map-client test/gfiber-agent
diff --git a/lib/hci.c b/lib/hci.c
index 005578a..89ec869 100644
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -2185,6 +2185,57 @@
return 0;
}
+int hci_read_page_scan_type(int dd, uint8_t *type, int to)
+{
+ read_page_scan_type_rp rp;
+ struct hci_request rq;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_READ_PAGE_SCAN_TYPE;
+ rq.rparam = &rp;
+ rq.rlen = READ_PAGE_SCAN_TYPE_RP_SIZE;
+
+ if (hci_send_req(dd, &rq, to) < 0)
+ return -1;
+
+ if (rp.status) {
+ errno = EIO;
+ return -1;
+ }
+
+ *type = rp.type;
+ return 0;
+}
+
+int hci_write_page_scan_type(int dd, uint8_t type, int to)
+{
+ write_page_scan_type_cp cp;
+ write_page_scan_type_rp rp;
+ struct hci_request rq;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.type = type;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.ogf = OGF_HOST_CTL;
+ rq.ocf = OCF_WRITE_PAGE_SCAN_TYPE;
+ rq.cparam = &cp;
+ rq.clen = WRITE_PAGE_SCAN_TYPE_CP_SIZE;
+ rq.rparam = &rp;
+ rq.rlen = WRITE_PAGE_SCAN_TYPE_RP_SIZE;
+
+ if (hci_send_req(dd, &rq, to) < 0)
+ return -1;
+
+ if (rp.status) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
int hci_read_inquiry_mode(int dd, uint8_t *mode, int to)
{
read_inquiry_mode_rp rp;
diff --git a/lib/hci.h b/lib/hci.h
index 0c94829..760b3fa 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -1070,10 +1070,23 @@
#define WRITE_INQUIRY_MODE_RP_SIZE 1
#define OCF_READ_PAGE_SCAN_TYPE 0x0046
+typedef struct {
+ uint8_t status;
+ uint8_t type;
+} __attribute__ ((packed)) read_page_scan_type_rp;
+#define READ_PAGE_SCAN_TYPE_RP_SIZE 2
#define OCF_WRITE_PAGE_SCAN_TYPE 0x0047
- #define PAGE_SCAN_TYPE_STANDARD 0x00
- #define PAGE_SCAN_TYPE_INTERLACED 0x01
+typedef struct {
+ uint8_t type;
+} __attribute__ ((packed)) write_page_scan_type_cp;
+#define WRITE_PAGE_SCAN_TYPE_CP_SIZE 1
+typedef struct {
+ uint8_t status;
+} __attribute__ ((packed)) write_page_scan_type_rp;
+#define WRITE_PAGE_SCAN_TYPE_RP_SIZE 1
+#define PAGE_SCAN_TYPE_STANDARD 0x00
+#define PAGE_SCAN_TYPE_INTERLACED 0x01
#define OCF_READ_AFH_MODE 0x0048
typedef struct {
diff --git a/lib/hci_lib.h b/lib/hci_lib.h
index 50744c3..5e7e11d 100644
--- a/lib/hci_lib.h
+++ b/lib/hci_lib.h
@@ -92,6 +92,8 @@
int hci_exit_park_mode(int dd, uint16_t handle, int to);
int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to);
int hci_write_inquiry_scan_type(int dd, uint8_t type, int to);
+int hci_read_page_scan_type(int dd, uint8_t *type, int to);
+int hci_write_page_scan_type(int dd, uint8_t type, int to);
int hci_read_inquiry_mode(int dd, uint8_t *mode, int to);
int hci_write_inquiry_mode(int dd, uint8_t mode, int to);
int hci_read_afh_mode(int dd, uint8_t *mode, int to);
diff --git a/plugins/gfrm.c b/plugins/gfrm.c
new file mode 100644
index 0000000..4588ef4
--- /dev/null
+++ b/plugins/gfrm.c
@@ -0,0 +1,252 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/log.h"
+
+#define BD_ADDR_FIFO "/tmp/bd-addr-fifo"
+
+struct gfrm_device {
+ char *name;
+ uint8_t oui[3];
+ uint8_t bdaddr_type;
+ uint16_t vid;
+ uint16_t pid;
+};
+
+static struct gfrm_device gfrm_devs[] = {
+ { "GFRM100", {0x00, 0x24, 0x1C}, BDADDR_BREDR, 0x58, 0x2000 },
+ { "GFRM200", {0x20, 0xCD, 0x39}, BDADDR_LE_PUBLIC, 0x471, 0x2210 },
+ { "HID AdvRemote", {0x90, 0x59, 0xAF}, BDADDR_LE_PUBLIC, 0xD, 0x0 },
+};
+
+static struct gfrm_device *gfrm_find_dev_by_vid_pid(uint16_t vid, uint16_t pid)
+{
+ uint16_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(gfrm_devs); ++i) {
+ if (vid == gfrm_devs[i].vid && pid == gfrm_devs[i].pid) {
+ return &gfrm_devs[i];
+ }
+ }
+
+ return NULL;
+}
+
+static struct gfrm_device *gfrm_find_dev_by_oui(uint8_t oui0, uint8_t oui1,
+ uint8_t oui2)
+{
+ uint16_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(gfrm_devs); ++i) {
+ if (oui0 == gfrm_devs[i].oui[0] &&
+ oui1 == gfrm_devs[i].oui[1] &&
+ oui2 == gfrm_devs[i].oui[2]) {
+ return &gfrm_devs[i];
+ }
+ }
+
+ return NULL;
+}
+
+static ssize_t gfrm_pincb(struct btd_adapter *adapter, struct btd_device *device,
+ char *pinbuf, bool *display, unsigned int attempt)
+{
+ uint16_t vid, pid;
+ char addr[18], name[25];
+
+ /*
+ * Only try the pin code once per device.
+ * If it's not correct then it's an unknown device.
+ */
+ if (attempt > 1)
+ return 0;
+
+ ba2str(device_get_address(device), addr);
+
+ vid = btd_device_get_vendor(device);
+ pid = btd_device_get_product(device);
+ DBG("vendor 0x%x product 0x%x", vid, pid);
+
+ device_get_name(device, name, sizeof(name));
+ name[sizeof(name) - 1] = 0;
+
+ if (gfrm_find_dev_by_vid_pid(vid, pid)) {
+ DBG("Forcing PIN 0000 on %s at %s", name, addr);
+ memcpy(pinbuf, "0000", 4);
+ return 4;
+ }
+
+ return 0;
+}
+
+static void gfrm_start_bd_addr_fifo_watch(
+ gboolean (*callback)(GIOChannel *, GIOCondition, gpointer))
+{
+ int fd;
+ GIOChannel *io;
+
+ if ((fd = open(BD_ADDR_FIFO, O_RDONLY | O_NONBLOCK)) < 0) {
+ DBG("open failed");
+ return;
+ }
+
+ if ((io = g_io_channel_unix_new(fd)) == NULL) {
+ DBG("g_io_channel_unix_new failed");
+ close(fd);
+ return;
+ }
+
+ if (!g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ callback, NULL)) {
+ DBG("g_io_add_watch failed");
+ }
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_unref(io);
+}
+
+static gboolean gfrm_add_device(GIOChannel *io, GIOCondition condition,
+ gpointer data)
+{
+ int fd;
+ bdaddr_t bdaddr_be;
+ bdaddr_t bdaddr;
+ char bdaddr_str[18];
+ struct gfrm_device *gfrm_dev;
+ struct btd_adapter *adapter;
+ struct btd_device *device;
+
+ if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ DBG("io error: condition %u", condition);
+ }
+
+ if (!(condition & (G_IO_IN))) {
+ DBG("pipe has no data to read");
+ goto reopen;
+ }
+
+ /* Read BD address from FIFO */
+ fd = g_io_channel_unix_get_fd(io);
+
+ if (read(fd, &bdaddr_be, sizeof(bdaddr_be)) != 6) {
+ DBG("read failed");
+ goto reopen;
+ }
+
+ baswap(&bdaddr, &bdaddr_be);
+ ba2str(&bdaddr, bdaddr_str);
+
+ gfrm_dev = gfrm_find_dev_by_oui(bdaddr.b[5], bdaddr.b[4], bdaddr.b[3]);
+ if (!gfrm_dev)
+ goto reopen;
+
+ DBG("Discovered %s at %s", gfrm_dev->name, bdaddr_str);
+
+ /* Add device to BlueZ stack */
+ adapter = btd_adapter_get_default();
+ if (!adapter) {
+ DBG("btd_adapter_get_default failed");
+ goto reopen;
+ }
+
+ device = btd_adapter_find_device(adapter, &bdaddr, gfrm_dev->bdaddr_type);
+ if (device) {
+ btd_device_set_temporary(device, TRUE);
+ btd_adapter_remove_device(adapter, device);
+ }
+
+ device = btd_adapter_get_device(adapter, &bdaddr, gfrm_dev->bdaddr_type);
+ btd_device_device_set_name(device, gfrm_dev->name);
+ btd_device_set_pnpid(device, 0x1, gfrm_dev->vid, gfrm_dev->pid, 0x0);
+ btd_device_set_temporary(device, FALSE);
+
+ /*
+ * Pairing the remote is handled in Python script:
+ * test/gfiber-agent
+ */
+
+reopen:
+ /* Reopen the FIFO (new fd, io channel, and watch) */
+ gfrm_start_bd_addr_fifo_watch(gfrm_add_device);
+
+ /*
+ * Return FALSE, so that the watch on the old io channel is removed.
+ * That, in turn, triggers closing of io channel and file descriptor.
+ */
+ return FALSE;
+}
+
+static int gfrm_probe(struct btd_adapter *adapter)
+{
+ btd_adapter_register_pin_cb(adapter, gfrm_pincb);
+}
+
+static void gfrm_remove(struct btd_adapter *adapter)
+{
+ btd_adapter_unregister_pin_cb(adapter, gfrm_pincb);
+}
+
+static struct btd_adapter_driver gfrm_driver = {
+ .name = "gfrm",
+ .probe = gfrm_probe,
+ .remove = gfrm_remove,
+};
+
+static int gfrm_init(void)
+{
+ btd_register_adapter_driver(&gfrm_driver);
+
+ /* Create FIFO for IR-assisted pairing */
+ if (mkfifo(BD_ADDR_FIFO, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
+ S_IROTH | S_IWOTH) < 0 && errno != EEXIST) {
+ DBG("mkfifo failed");
+ return 0;
+ }
+
+ /* Start watching the FIFO */
+ gfrm_start_bd_addr_fifo_watch(gfrm_add_device);
+
+ return 0;
+}
+
+static void gfrm_exit(void)
+{
+ btd_unregister_adapter_driver(&gfrm_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(gfrm, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_HIGH, gfrm_init, gfrm_exit)
diff --git a/profiles/input/device.c b/profiles/input/device.c
index a61b2c7..e37e7b9 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -92,6 +92,7 @@
static int idle_timeout = 0;
static bool uhid_enabled = false;
+static bool encryption_enabled = true;
void input_set_idle_timeout(int timeout)
{
@@ -103,6 +104,11 @@
uhid_enabled = state;
}
+void input_enable_encryption(bool state)
+{
+ encryption_enabled = state;
+}
+
static void input_device_enter_reconnect_mode(struct input_device *idev);
static int connection_disconnect(struct input_device *idev, uint32_t flags);
@@ -968,7 +974,7 @@
device_get_name(idev->device, req->name, sizeof(req->name));
/* Encryption is mandatory for keyboards */
- if (req->subclass & 0x40) {
+ if (encryption_enabled && (req->subclass & 0x40)) {
if (!bt_io_set(idev->intr_io, &gerr,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
BT_IO_OPT_INVALID)) {
diff --git a/profiles/input/device.h b/profiles/input/device.h
index 51a9aee..4edc965 100644
--- a/profiles/input/device.h
+++ b/profiles/input/device.h
@@ -29,6 +29,7 @@
void input_set_idle_timeout(int timeout);
void input_enable_userspace_hid(bool state);
+void input_enable_encryption(bool state);
int input_device_register(struct btd_service *service);
void input_device_unregister(struct btd_service *service);
diff --git a/profiles/input/manager.c b/profiles/input/manager.c
index 9712d2c..2302f95 100644
--- a/profiles/input/manager.c
+++ b/profiles/input/manager.c
@@ -98,6 +98,7 @@
if (config) {
int idle_timeout;
gboolean uhid_enabled;
+ gboolean encryption;
idle_timeout = g_key_file_get_integer(config, "General",
"IdleTimeout", &err);
@@ -115,6 +116,15 @@
input_enable_userspace_hid(uhid_enabled);
} else
g_clear_error(&err);
+
+ encryption = g_key_file_get_boolean(config, "General",
+ "Encryption", &err);
+ if (!err) {
+ DBG("input.conf: Encryption=%s", encryption ?
+ "true" : "false");
+ input_enable_encryption(encryption);
+ } else
+ g_clear_error(&err);
}
btd_profile_register(&input_profile);
diff --git a/profiles/input/uhid_copy.h b/profiles/input/uhid_copy.h
index 23a6287..9eb11fd 100644
--- a/profiles/input/uhid_copy.h
+++ b/profiles/input/uhid_copy.h
@@ -21,6 +21,7 @@
#include <linux/input.h>
#include <linux/types.h>
+#include <linux/hid.h>
enum uhid_event_type {
UHID_CREATE,
@@ -34,6 +35,8 @@
UHID_INPUT,
UHID_FEATURE,
UHID_FEATURE_ANSWER,
+ UHID_CREATE2,
+ UHID_INPUT2,
};
struct uhid_create_req {
@@ -50,6 +53,19 @@
__u32 country;
} __attribute__((__packed__));
+struct uhid_create2_req {
+ __u8 name[128];
+ __u8 phys[64];
+ __u8 uniq[64];
+ __u16 rd_size;
+ __u16 bus;
+ __u32 vendor;
+ __u32 product;
+ __u32 version;
+ __u32 country;
+ __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
+} __attribute__((__packed__));
+
#define UHID_DATA_MAX 4096
enum uhid_report_type {
@@ -63,6 +79,11 @@
__u16 size;
} __attribute__((__packed__));
+struct uhid_input2_req {
+ __u16 size;
+ __u8 data[UHID_DATA_MAX];
+} __attribute__((__packed__));
+
struct uhid_output_req {
__u8 data[UHID_DATA_MAX];
__u16 size;
@@ -100,6 +121,8 @@
struct uhid_output_ev_req output_ev;
struct uhid_feature_req feature;
struct uhid_feature_answer_req feature_answer;
+ struct uhid_create2_req create2;
+ struct uhid_input2_req input2;
} u;
} __attribute__((__packed__));
diff --git a/src/adapter.c b/src/adapter.c
index f5f8c8c..b4878a3 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -6573,6 +6573,10 @@
if (adapter->current_settings & MGMT_SETTING_POWERED)
adapter_start(adapter);
+ else
+ set_mode(adapter, MGMT_OP_SET_POWERED, 0x01);
+
+ set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, 0x01);
return;
diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index c438ab3..e2b0e7a 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -33,6 +33,10 @@
#include "src/shared/util.h"
#include "src/shared/crypto.h"
+#ifdef PF_ALG
+#undef PF_ALG
+#endif
+
#ifndef PF_ALG
#include <linux/types.h>
diff --git a/test/gfiber-agent b/test/gfiber-agent
new file mode 100755
index 0000000..2e66cbe
--- /dev/null
+++ b/test/gfiber-agent
@@ -0,0 +1,162 @@
+#!/usr/bin/python -u
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import dbus
+import dbus.exceptions
+import dbus.service
+import dbus.mainloop.glib
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+
+BLUEZ_BUS = 'org.bluez'
+BLUEZ_ROOT_OBJ = '/org/bluez'
+AGENT_INTF = 'org.bluez.Agent1'
+AGENT_MGR_INTF = 'org.bluez.AgentManager1'
+DEVICE_INTF = 'org.bluez.Device1'
+OBJECT_MGR_INTF = 'org.freedesktop.DBus.ObjectManager'
+PROPERTY_INTF = 'org.freedesktop.DBus.Properties'
+AGENT_PATH = '/com/google/gfiber/agent'
+AGENT_CAPABILITY = 'NoInputNoOutput'
+DEV_NAME_GFRM100 = 'GFRM100'
+DEV_NAME_GFRM200 = 'GFRM200'
+DEV_NAME_TIARC = 'HID AdvRemote'
+DEV_OUI_GFRM100 = '00:24:1C'
+DEV_OUI_GFRM200 = '20:CD:39'
+DEV_OUI_TIARC = '90:59:AF'
+
+bus = None
+agent = None
+
+def dev_trusted(path):
+ obj = bus.get_object(BLUEZ_BUS, path)
+ props = dbus.Interface(obj, PROPERTY_INTF)
+ props.Set(DEVICE_INTF, "Trusted", True)
+
+class Rejected(dbus.DBusException):
+ _dbus_error_name = "org.bluez.Error.Rejected"
+
+class Agent(dbus.service.Object):
+ exit_on_release = True
+
+ def set_exit_on_release(self, exit_on_release):
+ self.exit_on_release = exit_on_release
+
+ @dbus.service.method(AGENT_INTF, in_signature="", out_signature="")
+ def Release(self):
+ print("Release")
+ if self.exit_on_release:
+ mainloop.quit()
+
+ @dbus.service.method(AGENT_INTF, in_signature="os", out_signature="")
+ def AuthorizeService(self, device, uuid):
+ print("AuthorizeService (%s, %s)" % (device, uuid))
+ raise Rejected("Not implemented")
+
+ @dbus.service.method(AGENT_INTF, in_signature="o", out_signature="s")
+ def RequestPinCode(self, device):
+ print("RequestPinCode (%s)" % (device))
+ dev_trusted(device)
+ return '0000'
+
+ @dbus.service.method(AGENT_INTF, in_signature="o", out_signature="u")
+ def RequestPasskey(self, device):
+ print("RequestPasskey (%s)" % (device))
+ dev_trusted(device)
+ return dbus.UInt32('0000')
+
+ @dbus.service.method(AGENT_INTF, in_signature="ouq", out_signature="")
+ def DisplayPasskey(self, device, passkey, entered):
+ print("DisplayPasskey (%s, %06u entered %u)" %
+ (device, passkey, entered))
+
+ @dbus.service.method(AGENT_INTF, in_signature="os", out_signature="")
+ def DisplayPinCode(self, device, pincode):
+ print("DisplayPinCode (%s, %s)" % (device, pincode))
+
+ @dbus.service.method(AGENT_INTF, in_signature="ou", out_signature="")
+ def RequestConfirmation(self, device, passkey):
+ print("RequestConfirmation (%s, %06d)" % (device, passkey))
+ raise Rejected("Not implemented")
+
+ @dbus.service.method(AGENT_INTF, in_signature="o", out_signature="")
+ def RequestAuthorization(self, device):
+ print("RequestAuthorization (%s)" % (device))
+ raise Rejected("Not implemented")
+
+ @dbus.service.method(AGENT_INTF, in_signature="", out_signature="")
+ def Cancel(self):
+ print("Cancel")
+
+def register_agent():
+ obj = bus.get_object(BLUEZ_BUS, BLUEZ_ROOT_OBJ)
+ mgr = dbus.Interface(obj, AGENT_MGR_INTF)
+ mgr.RegisterAgent(AGENT_PATH, AGENT_CAPABILITY)
+ mgr.RequestDefaultAgent(AGENT_PATH)
+ print("Agent registered")
+
+def unregister_agent():
+ obj = bus.get_object(BLUEZ_BUS, BLUEZ_ROOT_OBJ)
+ mgr = dbus.Interface(obj, AGENT_MGR_INTF)
+ mgr.UnregisterAgent(AGENT_PATH)
+ print("Agent unregistered")
+
+def dev_pair_and_connect(path):
+ obj = bus.get_object(BLUEZ_BUS, path)
+ dev = dbus.Interface(obj, DEVICE_INTF)
+ props = dbus.Interface(obj, PROPERTY_INTF)
+ paired = props.Get(DEVICE_INTF, "Paired")
+ if paired == True:
+ print("%s is already paired" % (path))
+ return
+ dev.Pair()
+ props.Set(DEVICE_INTF, "Trusted", True)
+ dev.Connect()
+
+def interfaces_added(path, interfaces):
+ if not DEVICE_INTF in interfaces:
+ return
+ obj = bus.get_object(BLUEZ_BUS, path)
+ props = dbus.Interface(obj, PROPERTY_INTF)
+ addr = props.Get(DEVICE_INTF, "Address")
+ try:
+ name = props.Get(DEVICE_INTF, "Name")
+ except dbus.exceptions.DBusException:
+ name = ''
+ print("Discovered %s [%s] [%s]" % (path, addr, name))
+
+ if (name == DEV_NAME_GFRM100 or
+ name == DEV_NAME_GFRM200 or
+ name == DEV_NAME_TIARC or
+ addr.startswith(DEV_OUI_GFRM100) or
+ addr.startswith(DEV_OUI_GFRM200) or
+ addr.startswith(DEV_OUI_TIARC)):
+ print("Pair with %s [%s] [%s]" % (path, addr, name))
+ dev_pair_and_connect(path)
+
+def main():
+ global bus
+ global agent
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+ agent = Agent(bus, AGENT_PATH)
+
+ register_agent()
+ bus.add_signal_receiver(interfaces_added, bus_name=BLUEZ_BUS,
+ dbus_interface=OBJECT_MGR_INTF,
+ signal_name="InterfacesAdded")
+
+ mainloop = GObject.MainLoop()
+ mainloop.run()
+
+ bus.remove_signal_receiver(interfaces_added, bus_name=BLUEZ_BUS,
+ dbus_interface=OBJECT_MGR_INTF,
+ signal_name="InterfacesAdded")
+ unregister_agent()
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/hciconfig.c b/tools/hciconfig.c
index 765d980..1a2df42 100644
--- a/tools/hciconfig.c
+++ b/tools/hciconfig.c
@@ -1463,6 +1463,43 @@
}
}
+static void cmd_page_type(int ctl, int hdev, char *opt)
+{
+ int dd;
+
+ dd = hci_open_dev(hdev);
+ if (dd < 0) {
+ fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ if (opt) {
+ uint8_t type = atoi(opt);
+
+ if (hci_write_page_scan_type(dd, type, 2000) < 0) {
+ fprintf(stderr, "Can't set page scan type on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+ } else {
+ uint8_t type;
+
+ if (hci_read_page_scan_type(dd, &type, 1000) < 0) {
+ fprintf(stderr, "Can't read page scan type on hci%d: %s (%d)\n",
+ hdev, strerror(errno), errno);
+ exit(1);
+ }
+
+ print_dev_hdr(&di);
+ printf("\tPage scan type: %s\n",
+ type == PAGE_SCAN_TYPE_INTERLACED ?
+ "Interlaced Page Scan" : "Standard Page Scan");
+ }
+
+ hci_close_dev(dd);
+}
+
static void cmd_page_parms(int ctl, int hdev, char *opt)
{
struct hci_request rq;
@@ -1932,6 +1969,7 @@
{ "inqdata", cmd_inq_data, "[data]", "Get/Set inquiry data" },
{ "inqtype", cmd_inq_type, "[type]", "Get/Set inquiry scan type" },
{ "inqparms", cmd_inq_parms, "[win:int]", "Get/Set inquiry scan window and interval" },
+ { "pagetype", cmd_page_type, "[type]", "Get/Set page scan type" },
{ "pageparms", cmd_page_parms, "[win:int]", "Get/Set page scan window and interval" },
{ "pageto", cmd_page_to, "[to]", "Get/Set page timeout" },
{ "afhmode", cmd_afh_mode, "[mode]", "Get/Set AFH mode" },