2017-10-18 01:58:05

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 01/11] adapter: Add btd_request_authorization_cable_configured()

Add btd_request_authorization_cable_configured() function to allow
cable configured devices to ask the user straight away about whether the
device should be allowed to connect to the computer.

This allows us to ask the user at the time of the USB connection and
initial setup, rather than when the first Bluetooth connection is made.

The fact that the device might not be connected to the adapter when
this event is triggered is mentioned in the Agent API docs.
---
doc/agent-api.txt | 5 ++++-
src/adapter.c | 42 ++++++++++++++++++++++++++++++++++++------
src/adapter.h | 2 ++
3 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index 801ccb665..0d9347cab 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -163,7 +163,10 @@ Methods void Release()
This method gets called to request the user to
authorize an incoming pairing attempt which
would in other circumstances trigger the just-works
- model.
+ model, or when the user plugged in a device that
+ implements cable pairing. In the latter case, the
+ device would not be connected to the adapter via
+ Bluetooth yet.

Possible errors: org.bluez.Error.Rejected
org.bluez.Error.Canceled
diff --git a/src/adapter.c b/src/adapter.c
index 19205ed07..32a89d533 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -266,6 +266,11 @@ struct btd_adapter {
bool is_default; /* true if adapter is default one */
};

+typedef enum {
+ ADAPTER_AUTHORIZE_DISCONNECTED = 0,
+ ADAPTER_AUTHORIZE_CHECK_CONNECTED
+} adapter_authorize_type;
+
static struct btd_adapter *btd_adapter_lookup(uint16_t index)
{
GList *list;
@@ -6136,8 +6141,9 @@ static void svc_complete(struct btd_device *dev, int err, void *user_data)
}

static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
- const char *uuid, service_auth_cb cb,
- void *user_data)
+ const char *uuid,
+ adapter_authorize_type check_for_connection,
+ service_auth_cb cb, void *user_data)
{
struct service_auth *auth;
struct btd_device *device;
@@ -6153,7 +6159,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
}

/* Device connected? */
- if (!g_slist_find(adapter->connections, device))
+ if (check_for_connection && !g_slist_find(adapter->connections, device))
btd_error(adapter->dev_id,
"Authorization request for non-connected device!?");

@@ -6167,7 +6173,12 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
auth->device = device;
auth->adapter = adapter;
auth->id = ++id;
- auth->svc_id = device_wait_for_svc_complete(device, svc_complete, auth);
+ if (check_for_connection)
+ auth->svc_id = device_wait_for_svc_complete(device, svc_complete, auth);
+ else {
+ if (adapter->auth_idle_id == 0)
+ adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
+ }

g_queue_push_tail(adapter->auths, auth);

@@ -6186,7 +6197,8 @@ guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
if (!adapter)
return 0;

- return adapter_authorize(adapter, dst, uuid, cb, user_data);
+ return adapter_authorize(adapter, dst, uuid,
+ ADAPTER_AUTHORIZE_CHECK_CONNECTED, cb, user_data);
}

for (l = adapters; l != NULL; l = g_slist_next(l)) {
@@ -6194,7 +6206,8 @@ guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,

adapter = l->data;

- id = adapter_authorize(adapter, dst, uuid, cb, user_data);
+ id = adapter_authorize(adapter, dst, uuid,
+ ADAPTER_AUTHORIZE_CHECK_CONNECTED, cb, user_data);
if (id != 0)
return id;
}
@@ -6202,6 +6215,23 @@ guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
return 0;
}

+guint btd_request_authorization_cable_configured(const bdaddr_t *src, const bdaddr_t *dst,
+ const char *uuid, service_auth_cb cb,
+ void *user_data)
+{
+ struct btd_adapter *adapter;
+
+ if (bacmp(src, BDADDR_ANY) == 0)
+ return 0;
+
+ adapter = adapter_find(src);
+ if (!adapter)
+ return 0;
+
+ return adapter_authorize(adapter, dst, uuid,
+ ADAPTER_AUTHORIZE_DISCONNECTED, cb, user_data);
+}
+
static struct service_auth *find_authorization(guint id)
{
GSList *l;
diff --git a/src/adapter.h b/src/adapter.h
index f9178d59e..a85327cd1 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -120,6 +120,8 @@ int btd_register_adapter_driver(struct btd_adapter_driver *driver);
void btd_unregister_adapter_driver(struct btd_adapter_driver *driver);
guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
const char *uuid, service_auth_cb cb, void *user_data);
+guint btd_request_authorization_cable_configured(const bdaddr_t *src, const bdaddr_t *dst,
+ const char *uuid, service_auth_cb cb, void *user_data);
int btd_cancel_authorization(guint id);

int btd_adapter_restore_powered(struct btd_adapter *adapter);
--
2.14.2



2017-10-27 11:34:18

by Bastien Nocera

[permalink] [raw]
Subject: Re: [PATCH v2 01/11] adapter: Add btd_request_authorization_cable_configured()

On Fri, 2017-10-27 at 10:00 +0200, Szymon Janc wrote:
> Hi Bastien,
>
> <snip>
>
> Patches 1-8 are now applied, thanks.

For those following along on the mailing-list, I asked Szymon not to
commit the Wireless Keypad patches as they don't use pairing at all,
making it insecure.

It's possible to pair the PS3 Wireless keypad properly, like a normal
keyboard, by turning it on with the blue button (left trigger) pressed.
I'll see whether we can support cable pairing with actual pairing, in a
way that makes it easier for the user.

Cheers

2017-10-27 08:00:34

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH v2 01/11] adapter: Add btd_request_authorization_cable_configured()

Hi Bastien,

On Wednesday, 18 October 2017 03:58:05 CEST Bastien Nocera wrote:
> Add btd_request_authorization_cable_configured() function to allow
> cable configured devices to ask the user straight away about whether the
> device should be allowed to connect to the computer.
>
> This allows us to ask the user at the time of the USB connection and
> initial setup, rather than when the first Bluetooth connection is made.
>
> The fact that the device might not be connected to the adapter when
> this event is triggered is mentioned in the Agent API docs.
> ---
> doc/agent-api.txt | 5 ++++-
> src/adapter.c | 42 ++++++++++++++++++++++++++++++++++++------
> src/adapter.h | 2 ++
> 3 files changed, 42 insertions(+), 7 deletions(-)
>
> diff --git a/doc/agent-api.txt b/doc/agent-api.txt
> index 801ccb665..0d9347cab 100644
> --- a/doc/agent-api.txt
> +++ b/doc/agent-api.txt
> @@ -163,7 +163,10 @@ Methods void Release()
> This method gets called to request the user to
> authorize an incoming pairing attempt which
> would in other circumstances trigger the just-works
> - model.
> + model, or when the user plugged in a device that
> + implements cable pairing. In the latter case, the
> + device would not be connected to the adapter via
> + Bluetooth yet.
>
> Possible errors: org.bluez.Error.Rejected
> org.bluez.Error.Canceled
> diff --git a/src/adapter.c b/src/adapter.c
> index 19205ed07..32a89d533 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -266,6 +266,11 @@ struct btd_adapter {
> bool is_default; /* true if adapter is default one */
> };
>
> +typedef enum {
> + ADAPTER_AUTHORIZE_DISCONNECTED = 0,
> + ADAPTER_AUTHORIZE_CHECK_CONNECTED
> +} adapter_authorize_type;
> +
> static struct btd_adapter *btd_adapter_lookup(uint16_t index)
> {
> GList *list;
> @@ -6136,8 +6141,9 @@ static void svc_complete(struct btd_device *dev, int
> err, void *user_data) }
>
> static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t
> *dst, - const char *uuid, service_auth_cb cb,
> - void *user_data)
> + const char *uuid,
> + adapter_authorize_type check_for_connection,
> + service_auth_cb cb, void *user_data)
> {
> struct service_auth *auth;
> struct btd_device *device;
> @@ -6153,7 +6159,7 @@ static int adapter_authorize(struct btd_adapter
> *adapter, const bdaddr_t *dst, }
>
> /* Device connected? */
> - if (!g_slist_find(adapter->connections, device))
> + if (check_for_connection && !g_slist_find(adapter->connections, device))
> btd_error(adapter->dev_id,
> "Authorization request for non-connected device!?");
>
> @@ -6167,7 +6173,12 @@ static int adapter_authorize(struct btd_adapter
> *adapter, const bdaddr_t *dst, auth->device = device;
> auth->adapter = adapter;
> auth->id = ++id;
> - auth->svc_id = device_wait_for_svc_complete(device, svc_complete, auth);
> + if (check_for_connection)
> + auth->svc_id = device_wait_for_svc_complete(device, svc_complete,
auth);
> + else {
> + if (adapter->auth_idle_id == 0)
> + adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
> + }
>
> g_queue_push_tail(adapter->auths, auth);
>
> @@ -6186,7 +6197,8 @@ guint btd_request_authorization(const bdaddr_t *src,
> const bdaddr_t *dst, if (!adapter)
> return 0;
>
> - return adapter_authorize(adapter, dst, uuid, cb, user_data);
> + return adapter_authorize(adapter, dst, uuid,
> + ADAPTER_AUTHORIZE_CHECK_CONNECTED, cb, user_data);
> }
>
> for (l = adapters; l != NULL; l = g_slist_next(l)) {
> @@ -6194,7 +6206,8 @@ guint btd_request_authorization(const bdaddr_t *src,
> const bdaddr_t *dst,
>
> adapter = l->data;
>
> - id = adapter_authorize(adapter, dst, uuid, cb, user_data);
> + id = adapter_authorize(adapter, dst, uuid,
> + ADAPTER_AUTHORIZE_CHECK_CONNECTED, cb, user_data);
> if (id != 0)
> return id;
> }
> @@ -6202,6 +6215,23 @@ guint btd_request_authorization(const bdaddr_t *src,
> const bdaddr_t *dst, return 0;
> }
>
> +guint btd_request_authorization_cable_configured(const bdaddr_t *src, const
> bdaddr_t *dst, + const char *uuid, service_auth_cb cb,
> + void *user_data)
> +{
> + struct btd_adapter *adapter;
> +
> + if (bacmp(src, BDADDR_ANY) == 0)
> + return 0;
> +
> + adapter = adapter_find(src);
> + if (!adapter)
> + return 0;
> +
> + return adapter_authorize(adapter, dst, uuid,
> + ADAPTER_AUTHORIZE_DISCONNECTED, cb, user_data);
> +}
> +
> static struct service_auth *find_authorization(guint id)
> {
> GSList *l;
> diff --git a/src/adapter.h b/src/adapter.h
> index f9178d59e..a85327cd1 100644
> --- a/src/adapter.h
> +++ b/src/adapter.h
> @@ -120,6 +120,8 @@ int btd_register_adapter_driver(struct
> btd_adapter_driver *driver); void btd_unregister_adapter_driver(struct
> btd_adapter_driver *driver); guint btd_request_authorization(const bdaddr_t
> *src, const bdaddr_t *dst, const char *uuid, service_auth_cb cb, void
> *user_data);
> +guint btd_request_authorization_cable_configured(const bdaddr_t *src, const
> bdaddr_t *dst, + const char *uuid, service_auth_cb cb, void
*user_data);
> int btd_cancel_authorization(guint id);
>
> int btd_adapter_restore_powered(struct btd_adapter *adapter);

Patches 1-8 are now applied, thanks.

--
pozdrawiam
Szymon Janc

2017-10-18 01:58:10

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 06/11] plugins/sixaxis: Rename sixaxis specific functions

And provide wrappers to prepare for the addition of other device types.
---
plugins/sixaxis.c | 39 ++++++++++++++++++++++++++++++++-------
1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index 1bc64e1c4..69b1041e1 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -55,13 +55,14 @@ struct authentication_closure {
struct btd_device *device;
int fd;
bdaddr_t bdaddr; /* device bdaddr */
+ CablePairingType type;
};

static struct udev *ctx = NULL;
static struct udev_monitor *monitor = NULL;
static guint watch_id = 0;

-static int get_device_bdaddr(int fd, bdaddr_t *bdaddr)
+static int sixaxis_get_device_bdaddr(int fd, bdaddr_t *bdaddr)
{
uint8_t buf[18];
int ret;
@@ -82,7 +83,14 @@ static int get_device_bdaddr(int fd, bdaddr_t *bdaddr)
return 0;
}

-static int get_master_bdaddr(int fd, bdaddr_t *bdaddr)
+static int get_device_bdaddr(int fd, bdaddr_t *bdaddr, CablePairingType type)
+{
+ if (type == CABLE_PAIRING_SIXAXIS)
+ return sixaxis_get_device_bdaddr(fd, bdaddr);
+ return -1;
+}
+
+static int sixaxis_get_master_bdaddr(int fd, bdaddr_t *bdaddr)
{
uint8_t buf[8];
int ret;
@@ -103,7 +111,14 @@ static int get_master_bdaddr(int fd, bdaddr_t *bdaddr)
return 0;
}

-static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
+static int get_master_bdaddr(int fd, bdaddr_t *bdaddr, CablePairingType type)
+{
+ if (type == CABLE_PAIRING_SIXAXIS)
+ return sixaxis_get_master_bdaddr(fd, bdaddr);
+ return -1;
+}
+
+static int sixaxis_set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
{
uint8_t buf[8];
int ret;
@@ -121,6 +136,14 @@ static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
return ret;
}

+static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr,
+ CablePairingType type)
+{
+ if (type == CABLE_PAIRING_SIXAXIS)
+ return sixaxis_set_master_bdaddr(fd, bdaddr);
+ return -1;
+}
+
static void agent_auth_cb(DBusError *derr,
void *user_data)
{
@@ -136,12 +159,12 @@ static void agent_auth_cb(DBusError *derr,

btd_device_set_temporary(closure->device, false);

- if (get_master_bdaddr(closure->fd, &master_bdaddr) < 0)
+ if (get_master_bdaddr(closure->fd, &master_bdaddr, closure->type) < 0)
goto error;

adapter_bdaddr = btd_adapter_get_address(closure->adapter);
if (bacmp(adapter_bdaddr, &master_bdaddr)) {
- if (set_master_bdaddr(closure->fd, adapter_bdaddr) < 0)
+ if (set_master_bdaddr(closure->fd, adapter_bdaddr, closure->type) < 0)
goto error;
}

@@ -164,6 +187,7 @@ static bool setup_device(int fd,
uint16_t vid,
uint16_t pid,
uint16_t version,
+ CablePairingType type,
struct btd_adapter *adapter)
{
bdaddr_t device_bdaddr;
@@ -171,7 +195,7 @@ static bool setup_device(int fd,
struct btd_device *device;
struct authentication_closure *closure;

- if (get_device_bdaddr(fd, &device_bdaddr) < 0)
+ if (get_device_bdaddr(fd, &device_bdaddr, type) < 0)
return false;

/* This can happen if controller was plugged while already connected
@@ -206,6 +230,7 @@ static bool setup_device(int fd,
closure->device = device;
closure->fd = fd;
bacpy(&closure->bdaddr, &device_bdaddr);
+ closure->type = type;
adapter_bdaddr = btd_adapter_get_address(adapter);
btd_request_authorization_cable_configured(adapter_bdaddr, &device_bdaddr,
HID_UUID, agent_auth_cb, closure);
@@ -271,7 +296,7 @@ static void device_added(struct udev_device *udevice)
}

/* Only close the fd if an authentication is not pending */
- if (!setup_device(fd, name, source, vid, pid, version, adapter))
+ if (!setup_device(fd, name, source, vid, pid, version, type, adapter))
close(fd);

g_free(name);
--
2.14.2


2017-10-18 01:58:08

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 04/11] profiles/input: Use sixaxis header to simplify device detection

Use the shared header to recognise whether a device is a Sixaxis device
or not.
---
profiles/input/server.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/profiles/input/server.c b/profiles/input/server.c
index eb3fcf843..121c334d3 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -43,6 +43,7 @@
#include "src/device.h"
#include "src/profile.h"

+#include "sixaxis.h"
#include "device.h"
#include "server.h"

@@ -123,6 +124,7 @@ static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)
{
struct btd_device *device;
uint16_t vid, pid;
+ CablePairingType type;

device = btd_adapter_find_device(adapter_find(src), dst, BDADDR_BREDR);
if (!device)
@@ -131,18 +133,14 @@ static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)
vid = btd_device_get_vendor(device);
pid = btd_device_get_product(device);

- /* DualShock 3 */
- if (vid == 0x054c && pid == 0x0268)
+ type = get_pairing_type(vid, pid, NULL, NULL, NULL);
+ if (type == CABLE_PAIRING_SIXAXIS)
return true;

/* DualShock 4 */
if (vid == 0x054c && pid == 0x05c4)
return true;

- /* Navigation Controller */
- if (vid == 0x054c && pid == 0x042f)
- return true;
-
return false;
}

--
2.14.2


2017-10-18 01:58:13

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 09/11] profiles/input: Add support for detecting PS3 Keypads

Add device information about the PS3 wireless keypads and consider those
as "sixaxis" devices.
---
profiles/input/server.c | 3 ++-
profiles/input/sixaxis.h | 9 +++++++++
2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/profiles/input/server.c b/profiles/input/server.c
index ef428fefe..41d7b3ccf 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -135,7 +135,8 @@ static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)

type = get_pairing_type(vid, pid, NULL, NULL, NULL);
if (type == CABLE_PAIRING_SIXAXIS ||
- type == CABLE_PAIRING_DS4)
+ type == CABLE_PAIRING_DS4 ||
+ type == CABLE_PAIRING_PS3_WIRELESS_KEYPAD)
return true;

return false;
diff --git a/profiles/input/sixaxis.h b/profiles/input/sixaxis.h
index 17a7dc3f7..497a3f2a5 100644
--- a/profiles/input/sixaxis.h
+++ b/profiles/input/sixaxis.h
@@ -30,6 +30,7 @@ typedef enum {
CABLE_PAIRING_UNSUPPORTED = 0,
CABLE_PAIRING_SIXAXIS,
CABLE_PAIRING_DS4,
+ CABLE_PAIRING_PS3_WIRELESS_KEYPAD
} CablePairingType;

static inline CablePairingType get_pairing_type(uint16_t vid,
@@ -78,6 +79,14 @@ static inline CablePairingType get_pairing_type(uint16_t vid,
.version = 0x0001,
.type = CABLE_PAIRING_DS4,
},
+ {
+ .name = "Wireless Keypad",
+ .source = 0x0002,
+ .vid = 0x054c,
+ .pid = 0x03a0,
+ .version = 0x0001,
+ .type = CABLE_PAIRING_PS3_WIRELESS_KEYPAD
+ },
};
guint i;

--
2.14.2


2017-10-18 01:58:12

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 08/11] plugins/sixaxis: Cancel cable pairing if unplugged

Cancel pending authorization requests when the device is unplugged
while a request is pending.
---
plugins/sixaxis.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 122 insertions(+), 15 deletions(-)

diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index a3e8749da..a05e95c1f 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -51,6 +51,8 @@
#include "profiles/input/sixaxis.h"

struct authentication_closure {
+ guint auth_id;
+ char *sysfs_path;
struct btd_adapter *adapter;
struct btd_device *device;
int fd;
@@ -58,9 +60,29 @@ struct authentication_closure {
CablePairingType type;
};

+struct authentication_destroy_closure {
+ struct authentication_closure *closure;
+ bool remove_device;
+};
+
static struct udev *ctx = NULL;
static struct udev_monitor *monitor = NULL;
static guint watch_id = 0;
+static GHashTable *pending_auths = NULL; /* key = sysfs_path (const str), value = auth_closure */
+
+/* Make sure to unset auth_id if already handled */
+static void auth_closure_destroy(struct authentication_closure *closure,
+ bool remove_device)
+{
+ if (closure->auth_id)
+ btd_cancel_authorization(closure->auth_id);
+
+ if (remove_device)
+ btd_adapter_remove_device(closure->adapter, closure->device);
+ close(closure->fd);
+ g_free(closure->sysfs_path);
+ g_free(closure);
+}

static int sixaxis_get_device_bdaddr(int fd, bdaddr_t *bdaddr)
{
@@ -214,31 +236,63 @@ static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr,
return -1;
}

+static bool is_auth_pending(struct authentication_closure *closure)
+{
+ GHashTableIter iter;
+ gpointer value;
+
+ g_hash_table_iter_init(&iter, pending_auths);
+ while (g_hash_table_iter_next(&iter, NULL, &value)) {
+ struct authentication_closure *c = value;
+ if (c == closure)
+ return true;
+ }
+ return false;
+}
+
+static gboolean auth_closure_destroy_idle(gpointer user_data)
+{
+ struct authentication_destroy_closure *destroy = user_data;
+
+ auth_closure_destroy(destroy->closure, destroy->remove_device);
+ g_free(destroy);
+
+ return false;
+}
+
static void agent_auth_cb(DBusError *derr,
void *user_data)
{
struct authentication_closure *closure = user_data;
+ struct authentication_destroy_closure *destroy;
char master_addr[18], adapter_addr[18], device_addr[18];
bdaddr_t master_bdaddr;
const bdaddr_t *adapter_bdaddr;
+ bool remove_device = true;
+
+ if (!is_auth_pending(closure))
+ return;
+
+ /* Don't try to remove this auth, we're handling it already */
+ closure->auth_id = 0;

if (derr != NULL) {
DBG("Agent replied negatively, removing temporary device");
- goto error;
+ goto out;
}

- btd_device_set_temporary(closure->device, false);
-
if (get_master_bdaddr(closure->fd, &master_bdaddr, closure->type) < 0)
- goto error;
+ goto out;

adapter_bdaddr = btd_adapter_get_address(closure->adapter);
if (bacmp(adapter_bdaddr, &master_bdaddr)) {
if (set_master_bdaddr(closure->fd, adapter_bdaddr, closure->type) < 0)
- goto error;
+ goto out;
}

+ remove_device = false;
btd_device_set_trusted(closure->device, true);
+ btd_device_set_temporary(closure->device, false);

ba2str(&closure->bdaddr, device_addr);
ba2str(&master_bdaddr, master_addr);
@@ -246,12 +300,21 @@ static void agent_auth_cb(DBusError *derr,
DBG("remote %s old_master %s new_master %s",
device_addr, master_addr, adapter_addr);

-error:
- close(closure->fd);
- g_free(closure);
+out:
+ g_hash_table_steal(pending_auths, closure->sysfs_path);
+
+ /* btd_adapter_remove_device() cannot be called in this
+ * callback or it would lead to a double-free in while
+ * trying to cancel the authentication that's being processed,
+ * so clean up in an idle */
+ destroy = g_new0(struct authentication_destroy_closure, 1);
+ destroy->closure = closure;
+ destroy->remove_device = remove_device;
+ g_idle_add(auth_closure_destroy_idle, destroy);
}

static bool setup_device(int fd,
+ const char *sysfs_path,
const char *name,
uint16_t source,
uint16_t vid,
@@ -298,12 +361,15 @@ static bool setup_device(int fd,
}
closure->adapter = adapter;
closure->device = device;
+ closure->sysfs_path = g_strdup(sysfs_path);
closure->fd = fd;
bacpy(&closure->bdaddr, &device_bdaddr);
closure->type = type;
adapter_bdaddr = btd_adapter_get_address(adapter);
- btd_request_authorization_cable_configured(adapter_bdaddr, &device_bdaddr,
- HID_UUID, agent_auth_cb, closure);
+ closure->auth_id = btd_request_authorization_cable_configured(adapter_bdaddr, &device_bdaddr,
+ HID_UUID, agent_auth_cb, closure);
+
+ g_hash_table_insert(pending_auths, closure->sysfs_path, closure);

return true;
}
@@ -312,12 +378,14 @@ static CablePairingType get_pairing_type_for_device(struct udev_device *udevice,
uint16_t *bus,
uint16_t *vid,
uint16_t *pid,
+ char **sysfs_path,
char **name,
uint16_t *source,
uint16_t *version)
{
struct udev_device *hid_parent;
const char *hid_id;
+ CablePairingType ret;

hid_parent = udev_device_get_parent_with_subsystem_devtype(udevice,
"hid", NULL);
@@ -329,14 +397,17 @@ static CablePairingType get_pairing_type_for_device(struct udev_device *udevice,
if (sscanf(hid_id, "%hx:%hx:%hx", bus, vid, pid) != 3)
return -1;

- return get_pairing_type(*vid, *pid, name, source, version);
+ ret = get_pairing_type(*vid, *pid, name, source, version);
+ *sysfs_path = g_strdup(udev_device_get_syspath(udevice));
+
+ return ret;
}

static void device_added(struct udev_device *udevice)
{
struct btd_adapter *adapter;
uint16_t bus, vid, pid, source, version;
- char *name = NULL;
+ char *name = NULL, *sysfs_path = NULL;
CablePairingType type;
int fd;

@@ -348,6 +419,7 @@ static void device_added(struct udev_device *udevice)
&bus,
&vid,
&pid,
+ &sysfs_path,
&name,
&source,
&version);
@@ -357,20 +429,39 @@ static void device_added(struct udev_device *udevice)
if (bus != BUS_USB)
return;

- info("sixaxis: compatible device connected: %s (%04X:%04X)",
- name, vid, pid);
+ info("sixaxis: compatible device connected: %s (%04X:%04X %s)",
+ name, vid, pid, sysfs_path);

fd = open(udev_device_get_devnode(udevice), O_RDWR);
if (fd < 0) {
g_free(name);
+ g_free(sysfs_path);
return;
}

/* Only close the fd if an authentication is not pending */
- if (!setup_device(fd, name, source, vid, pid, version, type, adapter))
+ if (!setup_device(fd, sysfs_path, name, source, vid, pid, version, type, adapter))
close(fd);

g_free(name);
+ g_free(sysfs_path);
+}
+
+static void device_removed(struct udev_device *udevice)
+{
+ struct authentication_closure *closure;
+ const char *sysfs_path;
+
+ sysfs_path = udev_device_get_syspath(udevice);
+ if (!sysfs_path)
+ return;
+
+ closure = g_hash_table_lookup(pending_auths, sysfs_path);
+ if (!closure)
+ return;
+
+ g_hash_table_steal(pending_auths, sysfs_path);
+ auth_closure_destroy(closure, true);
}

static gboolean monitor_watch(GIOChannel *source, GIOCondition condition,
@@ -384,6 +475,8 @@ static gboolean monitor_watch(GIOChannel *source, GIOCondition condition,

if (!g_strcmp0(udev_device_get_action(udevice), "add"))
device_added(udevice);
+ else if (!g_strcmp0(udev_device_get_action(udevice), "remove"))
+ device_removed(udevice);

udev_device_unref(udevice);

@@ -417,13 +510,27 @@ static int sixaxis_init(void)
watch_id = g_io_add_watch(channel, G_IO_IN, monitor_watch, NULL);
g_io_channel_unref(channel);

+ pending_auths = g_hash_table_new(g_str_hash,
+ g_str_equal);
+
return 0;
}

static void sixaxis_exit(void)
{
+ GHashTableIter iter;
+ gpointer value;
+
DBG("");

+ g_hash_table_iter_init(&iter, pending_auths);
+ while (g_hash_table_iter_next(&iter, NULL, &value)) {
+ struct authentication_closure *closure = value;
+ auth_closure_destroy(closure, true);
+ }
+ g_hash_table_destroy(pending_auths);
+ pending_auths = NULL;
+
g_source_remove(watch_id);
watch_id = 0;

--
2.14.2


2017-10-18 01:58:07

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 03/11] plugins/sixaxis: Move device discovery to shared header

Move the struct containing the Sixaxis-compatible devices to a
header shared with the input profiles code, so as to reduce device
declaration.

Adding support for new devices should be as easy as adding the device's
declaration in profiles/input/sixaxis.h
---
plugins/sixaxis.c | 82 +++++++++++++++++++++-------------------------
profiles/input/sixaxis.h | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 122 insertions(+), 45 deletions(-)
create mode 100644 profiles/input/sixaxis.h

diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index cee2263a1..1bc64e1c4 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -48,29 +48,7 @@
#include "src/plugin.h"
#include "src/log.h"
#include "src/shared/util.h"
-
-static const struct {
- const char *name;
- uint16_t source;
- uint16_t vid;
- uint16_t pid;
- uint16_t version;
-} devices[] = {
- {
- .name = "Sony PLAYSTATION(R)3 Controller",
- .source = 0x0002,
- .vid = 0x054c,
- .pid = 0x0268,
- .version = 0x0000,
- },
- {
- .name = "Navigation Controller",
- .source = 0x0002,
- .vid = 0x054c,
- .pid = 0x042f,
- .version = 0x0000,
- },
-};
+#include "profiles/input/sixaxis.h"

struct authentication_closure {
struct btd_adapter *adapter;
@@ -180,7 +158,13 @@ error:
g_free(closure);
}

-static bool setup_device(int fd, int index, struct btd_adapter *adapter)
+static bool setup_device(int fd,
+ const char *name,
+ uint16_t source,
+ uint16_t vid,
+ uint16_t pid,
+ uint16_t version,
+ struct btd_adapter *adapter)
{
bdaddr_t device_bdaddr;
const bdaddr_t *adapter_bdaddr;
@@ -209,9 +193,8 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter)

info("sixaxis: setting up new device");

- btd_device_device_set_name(device, devices[index].name);
- btd_device_set_pnpid(device, devices[index].source, devices[index].vid,
- devices[index].pid, devices[index].version);
+ btd_device_device_set_name(device, name);
+ btd_device_set_pnpid(device, source, vid, pid, version);
btd_device_set_temporary(device, true);

closure = g_new0(struct authentication_closure, 1);
@@ -230,12 +213,16 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter)
return true;
}

-static int get_supported_device(struct udev_device *udevice, uint16_t *bus)
+static CablePairingType get_pairing_type_for_device(struct udev_device *udevice,
+ uint16_t *bus,
+ uint16_t *vid,
+ uint16_t *pid,
+ char **name,
+ uint16_t *source,
+ uint16_t *version)
{
struct udev_device *hid_parent;
- uint16_t vid, pid;
const char *hid_id;
- guint i;

hid_parent = udev_device_get_parent_with_subsystem_devtype(udevice,
"hid", NULL);
@@ -244,45 +231,50 @@ static int get_supported_device(struct udev_device *udevice, uint16_t *bus)

hid_id = udev_device_get_property_value(hid_parent, "HID_ID");

- if (sscanf(hid_id, "%hx:%hx:%hx", bus, &vid, &pid) != 3)
+ if (sscanf(hid_id, "%hx:%hx:%hx", bus, vid, pid) != 3)
return -1;

- for (i = 0; i < G_N_ELEMENTS(devices); i++) {
- if (devices[i].vid == vid && devices[i].pid == pid)
- return i;
- }
-
- return -1;
+ return get_pairing_type(*vid, *pid, name, source, version);
}

static void device_added(struct udev_device *udevice)
{
struct btd_adapter *adapter;
- uint16_t bus;
- int index;
+ uint16_t bus, vid, pid, source, version;
+ char *name = NULL;
+ CablePairingType type;
int fd;

adapter = btd_adapter_get_default();
if (!adapter)
return;

- index = get_supported_device(udevice, &bus);
- if (index < 0)
+ type = get_pairing_type_for_device(udevice,
+ &bus,
+ &vid,
+ &pid,
+ &name,
+ &source,
+ &version);
+ if (type != CABLE_PAIRING_SIXAXIS)
return;
if (bus != BUS_USB)
return;

info("sixaxis: compatible device connected: %s (%04X:%04X)",
- devices[index].name, devices[index].vid,
- devices[index].pid);
+ name, vid, pid);

fd = open(udev_device_get_devnode(udevice), O_RDWR);
- if (fd < 0)
+ if (fd < 0) {
+ g_free(name);
return;
+ }

/* Only close the fd if an authentication is not pending */
- if (!setup_device(fd, index, adapter))
+ if (!setup_device(fd, name, source, vid, pid, version, adapter))
close(fd);
+
+ g_free(name);
}

static gboolean monitor_watch(GIOChannel *source, GIOCondition condition,
diff --git a/profiles/input/sixaxis.h b/profiles/input/sixaxis.h
new file mode 100644
index 000000000..0b3c4e397
--- /dev/null
+++ b/profiles/input/sixaxis.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009,2017 Bastien Nocera <[email protected]>
+ * Copyright (C) 2011 Antonio Ospite <[email protected]>
+ * Copyright (C) 2013 Szymon Janc <[email protected]>
+ *
+ *
+ * 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
+ *
+ */
+
+#ifndef _SIXAXIS_H_
+#define _SIXAXIS_H_
+
+typedef enum {
+ CABLE_PAIRING_UNSUPPORTED = 0,
+ CABLE_PAIRING_SIXAXIS,
+} CablePairingType;
+
+static inline CablePairingType get_pairing_type(uint16_t vid,
+ uint16_t pid,
+ char **name,
+ uint16_t *source,
+ uint16_t *version)
+{
+ static const struct {
+ const char *name;
+ uint16_t source;
+ uint16_t vid;
+ uint16_t pid;
+ uint16_t version;
+ CablePairingType type;
+ } devices[] = {
+ {
+ .name = "Sony PLAYSTATION(R)3 Controller",
+ .source = 0x0002,
+ .vid = 0x054c,
+ .pid = 0x0268,
+ .version = 0x0000,
+ .type = CABLE_PAIRING_SIXAXIS,
+ },
+ {
+ .name = "Navigation Controller",
+ .source = 0x0002,
+ .vid = 0x054c,
+ .pid = 0x042f,
+ .version = 0x0000,
+ .type = CABLE_PAIRING_SIXAXIS,
+ },
+ };
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(devices); i++) {
+ if (devices[i].vid != vid)
+ continue;
+ if (devices[i].pid != pid)
+ continue;
+
+ if (name)
+ *name = g_strdup(devices[i].name);
+ if (source)
+ *source = devices[i].source;
+ if (version)
+ *version = devices[i].version;
+ return devices[i].type;
+ }
+
+ return CABLE_PAIRING_UNSUPPORTED;
+}
+
+#endif /* _SIXAXIS_H_ */
--
2.14.2


2017-10-18 01:58:14

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 10/11] plugins/sixaxis: Add cable pairing for PS3 Keypads

As documented in qtsixa's sixpair_kbd.c, from unknown origin:
https://github.com/falkTX/qtsixa/blob/master/utils/sixpair_kbd.c
---
plugins/sixaxis.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)

diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index a05e95c1f..a2946f864 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -127,10 +127,33 @@ static int ds4_get_device_bdaddr(int fd, bdaddr_t *bdaddr)
return 0;
}

+static int ps3_keypad_get_device_bdaddr(int fd, bdaddr_t *bdaddr)
+{
+ uint8_t buf[16];
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = 0x4;
+
+ ret = ioctl(fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+ if (ret < 0) {
+ error("sixaxis: failed to read device address (%s)",
+ strerror(errno));
+ return ret;
+ }
+
+ baswap(bdaddr, (bdaddr_t *) (buf + 1));
+
+ return 0;
+}
+
static int get_device_bdaddr(int fd, bdaddr_t *bdaddr, CablePairingType type)
{
if (type == CABLE_PAIRING_SIXAXIS)
return sixaxis_get_device_bdaddr(fd, bdaddr);
+ else if (type == CABLE_PAIRING_PS3_WIRELESS_KEYPAD)
+ return ps3_keypad_get_device_bdaddr(fd, bdaddr);
else if (type == CABLE_PAIRING_DS4)
return ds4_get_device_bdaddr(fd, bdaddr);
return -1;
@@ -179,10 +202,33 @@ static int ds4_get_master_bdaddr(int fd, bdaddr_t *bdaddr)
return 0;
}

+static int ps3_keypad_get_master_bdaddr(int fd, bdaddr_t *bdaddr)
+{
+ uint8_t buf[16];
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = 0x4;
+
+ ret = ioctl(fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+ if (ret < 0) {
+ error("sixaxis: failed to read master address (%s)",
+ strerror(errno));
+ return ret;
+ }
+
+ bacpy(bdaddr, (bdaddr_t *) (buf + 10));
+
+ return 0;
+}
+
static int get_master_bdaddr(int fd, bdaddr_t *bdaddr, CablePairingType type)
{
if (type == CABLE_PAIRING_SIXAXIS)
return sixaxis_get_master_bdaddr(fd, bdaddr);
+ else if (type == CABLE_PAIRING_PS3_WIRELESS_KEYPAD)
+ return ps3_keypad_get_master_bdaddr(fd, bdaddr);
else if (type == CABLE_PAIRING_DS4)
return ds4_get_master_bdaddr(fd, bdaddr);
return -1;
@@ -226,11 +272,30 @@ static int ds4_set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
return ret;
}

+static int ps3_keypad_set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
+{
+ uint8_t buf[7];
+ int ret;
+
+ buf[0] = 0x05;
+
+ baswap((bdaddr_t*) (buf + 1), bdaddr);
+
+ ret = ioctl(fd, HIDIOCSFEATURE(sizeof(buf)), buf);
+ if (ret < 0)
+ error("sixaxis: failed to write PS3 Keypad master address (%s)",
+ strerror(errno));
+
+ return ret;
+}
+
static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr,
CablePairingType type)
{
if (type == CABLE_PAIRING_SIXAXIS)
return sixaxis_set_master_bdaddr(fd, bdaddr);
+ else if (type == CABLE_PAIRING_PS3_WIRELESS_KEYPAD)
+ return ps3_keypad_set_master_bdaddr(fd, bdaddr);
else if (type == CABLE_PAIRING_DS4)
return ds4_set_master_bdaddr(fd, bdaddr);
return -1;
@@ -424,7 +489,8 @@ static void device_added(struct udev_device *udevice)
&source,
&version);
if (type != CABLE_PAIRING_SIXAXIS &&
- type != CABLE_PAIRING_DS4)
+ type != CABLE_PAIRING_DS4 &&
+ type != CABLE_PAIRING_PS3_WIRELESS_KEYPAD)
return;
if (bus != BUS_USB)
return;
--
2.14.2


2017-10-18 01:58:15

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 11/11] plugins/autopair: Don't try to pair PS3 Keypad

The keypad doesn't use pairing. Don't type your passwords on this...
---
plugins/autopair.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/plugins/autopair.c b/plugins/autopair.c
index 6980b0a64..863b8d736 100644
--- a/plugins/autopair.c
+++ b/plugins/autopair.c
@@ -78,6 +78,10 @@ static ssize_t autopair_pincb(struct btd_adapter *adapter,
if (name != NULL && strstr(name, "iCade") != NULL)
return 0;

+ /* The PS3 Wireless Keypad doesn't need pairing */
+ if (name != NULL && g_str_equal(name, "Wireless Keypad"))
+ return 0;
+
/* This is a class-based pincode guesser. Ignore devices with an
* unknown class.
*/
--
2.14.2


2017-10-18 01:58:09

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 05/11] profiles/input: Add DS4 devices to the shared header

And simplify the detection code in server.c some more.
---
profiles/input/server.c | 7 ++-----
profiles/input/sixaxis.h | 17 +++++++++++++++++
2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/profiles/input/server.c b/profiles/input/server.c
index 121c334d3..ef428fefe 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -134,11 +134,8 @@ static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst)
pid = btd_device_get_product(device);

type = get_pairing_type(vid, pid, NULL, NULL, NULL);
- if (type == CABLE_PAIRING_SIXAXIS)
- return true;
-
- /* DualShock 4 */
- if (vid == 0x054c && pid == 0x05c4)
+ if (type == CABLE_PAIRING_SIXAXIS ||
+ type == CABLE_PAIRING_DS4)
return true;

return false;
diff --git a/profiles/input/sixaxis.h b/profiles/input/sixaxis.h
index 0b3c4e397..17a7dc3f7 100644
--- a/profiles/input/sixaxis.h
+++ b/profiles/input/sixaxis.h
@@ -29,6 +29,7 @@
typedef enum {
CABLE_PAIRING_UNSUPPORTED = 0,
CABLE_PAIRING_SIXAXIS,
+ CABLE_PAIRING_DS4,
} CablePairingType;

static inline CablePairingType get_pairing_type(uint16_t vid,
@@ -61,6 +62,22 @@ static inline CablePairingType get_pairing_type(uint16_t vid,
.version = 0x0000,
.type = CABLE_PAIRING_SIXAXIS,
},
+ {
+ .name = "Wireless Controller",
+ .source = 0x0002,
+ .vid = 0x054c,
+ .pid = 0x05c4,
+ .version = 0x0001,
+ .type = CABLE_PAIRING_DS4,
+ },
+ {
+ .name = "Wireless Controller",
+ .source = 0x0002,
+ .vid = 0x054c,
+ .pid = 0x09cc,
+ .version = 0x0001,
+ .type = CABLE_PAIRING_DS4,
+ },
};
guint i;

--
2.14.2


2017-10-18 01:58:11

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 07/11] plugins/sixaxis: Add support for DualShock 4/PS4 cable pairing

From: Juha Kuikka <[email protected]>

This patch adds support for "pairing" a Dualshock4 controller over USB
into the sixaxis plugin, similarly to what the Sixaxis/PS3 controller
supported.

Actual bonding happens on first connection, but the device will be
marked as trusted when the agent replies.

This patch is based on DS4 supprt for sixpair tool by t0xicCode:
https://github.com/t0xicCode/sixpair/commit/975c38cb6cd61a2f0be350714f0f64cef5f0432c
---
plugins/sixaxis.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)

diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index 69b1041e1..a3e8749da 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -83,10 +83,34 @@ static int sixaxis_get_device_bdaddr(int fd, bdaddr_t *bdaddr)
return 0;
}

+static int ds4_get_device_bdaddr(int fd, bdaddr_t *bdaddr)
+{
+ uint8_t buf[7];
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = 0x81;
+
+ ret = ioctl(fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+ if (ret < 0) {
+ error("sixaxis: failed to read DS4 device address (%s)",
+ strerror(errno));
+ return ret;
+ }
+
+ /* address is little-endian on DS4 */
+ bacpy(bdaddr, (bdaddr_t*) (buf + 1));
+
+ return 0;
+}
+
static int get_device_bdaddr(int fd, bdaddr_t *bdaddr, CablePairingType type)
{
if (type == CABLE_PAIRING_SIXAXIS)
return sixaxis_get_device_bdaddr(fd, bdaddr);
+ else if (type == CABLE_PAIRING_DS4)
+ return ds4_get_device_bdaddr(fd, bdaddr);
return -1;
}

@@ -111,10 +135,34 @@ static int sixaxis_get_master_bdaddr(int fd, bdaddr_t *bdaddr)
return 0;
}

+static int ds4_get_master_bdaddr(int fd, bdaddr_t *bdaddr)
+{
+ uint8_t buf[16];
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = 0x12;
+
+ ret = ioctl(fd, HIDIOCGFEATURE(sizeof(buf)), buf);
+ if (ret < 0) {
+ error("sixaxis: failed to read DS4 master address (%s)",
+ strerror(errno));
+ return ret;
+ }
+
+ /* address is little-endian on DS4 */
+ bacpy(bdaddr, (bdaddr_t*) (buf + 10));
+
+ return 0;
+}
+
static int get_master_bdaddr(int fd, bdaddr_t *bdaddr, CablePairingType type)
{
if (type == CABLE_PAIRING_SIXAXIS)
return sixaxis_get_master_bdaddr(fd, bdaddr);
+ else if (type == CABLE_PAIRING_DS4)
+ return ds4_get_master_bdaddr(fd, bdaddr);
return -1;
}

@@ -136,11 +184,33 @@ static int sixaxis_set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
return ret;
}

+static int ds4_set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
+{
+ uint8_t buf[23];
+ int ret;
+
+ buf[0] = 0x13;
+ bacpy((bdaddr_t*) (buf + 1), bdaddr);
+ /* TODO: we could put the key here but
+ there is no way to force a re-loading
+ of link keys to the kernel from here. */
+ memset(buf + 7, 0, 16);
+
+ ret = ioctl(fd, HIDIOCSFEATURE(sizeof(buf)), buf);
+ if (ret < 0)
+ error("sixaxis: failed to write DS4 master address (%s)",
+ strerror(errno));
+
+ return ret;
+}
+
static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr,
CablePairingType type)
{
if (type == CABLE_PAIRING_SIXAXIS)
return sixaxis_set_master_bdaddr(fd, bdaddr);
+ else if (type == CABLE_PAIRING_DS4)
+ return ds4_set_master_bdaddr(fd, bdaddr);
return -1;
}

@@ -281,7 +351,8 @@ static void device_added(struct udev_device *udevice)
&name,
&source,
&version);
- if (type != CABLE_PAIRING_SIXAXIS)
+ if (type != CABLE_PAIRING_SIXAXIS &&
+ type != CABLE_PAIRING_DS4)
return;
if (bus != BUS_USB)
return;
--
2.14.2


2017-10-18 01:58:06

by Bastien Nocera

[permalink] [raw]
Subject: [PATCH v2 02/11] sixaxis: Ask user whether cable configuration should be allowed

Previously, users doing cable configuration of Sixaxis PS3 controllers
would only get asked whether a device was allowed to connect to the
computer when switching it to Bluetooth mode: unplugging it, and
pressing the PS button.

Instead, we should ask the user straight away, through the agent,
whether the pad should be allowed to connect.

This makes it easier to setup those devices, while keeping security.
---
plugins/sixaxis.c | 89 +++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 67 insertions(+), 22 deletions(-)

diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c
index 7d3a8f3ac..cee2263a1 100644
--- a/plugins/sixaxis.c
+++ b/plugins/sixaxis.c
@@ -44,6 +44,7 @@

#include "src/adapter.h"
#include "src/device.h"
+#include "src/agent.h"
#include "src/plugin.h"
#include "src/log.h"
#include "src/shared/util.h"
@@ -71,6 +72,13 @@ static const struct {
},
};

+struct authentication_closure {
+ struct btd_adapter *adapter;
+ struct btd_device *device;
+ int fd;
+ bdaddr_t bdaddr; /* device bdaddr */
+};
+
static struct udev *ctx = NULL;
static struct udev_monitor *monitor = NULL;
static guint watch_id = 0;
@@ -135,19 +143,53 @@ static int set_master_bdaddr(int fd, const bdaddr_t *bdaddr)
return ret;
}

+static void agent_auth_cb(DBusError *derr,
+ void *user_data)
+{
+ struct authentication_closure *closure = user_data;
+ char master_addr[18], adapter_addr[18], device_addr[18];
+ bdaddr_t master_bdaddr;
+ const bdaddr_t *adapter_bdaddr;
+
+ if (derr != NULL) {
+ DBG("Agent replied negatively, removing temporary device");
+ goto error;
+ }
+
+ btd_device_set_temporary(closure->device, false);
+
+ if (get_master_bdaddr(closure->fd, &master_bdaddr) < 0)
+ goto error;
+
+ adapter_bdaddr = btd_adapter_get_address(closure->adapter);
+ if (bacmp(adapter_bdaddr, &master_bdaddr)) {
+ if (set_master_bdaddr(closure->fd, adapter_bdaddr) < 0)
+ goto error;
+ }
+
+ btd_device_set_trusted(closure->device, true);
+
+ ba2str(&closure->bdaddr, device_addr);
+ ba2str(&master_bdaddr, master_addr);
+ ba2str(adapter_bdaddr, adapter_addr);
+ DBG("remote %s old_master %s new_master %s",
+ device_addr, master_addr, adapter_addr);
+
+error:
+ close(closure->fd);
+ g_free(closure);
+}
+
static bool setup_device(int fd, int index, struct btd_adapter *adapter)
{
- char device_addr[18], master_addr[18], adapter_addr[18];
- bdaddr_t device_bdaddr, master_bdaddr;
+ bdaddr_t device_bdaddr;
const bdaddr_t *adapter_bdaddr;
struct btd_device *device;
+ struct authentication_closure *closure;

if (get_device_bdaddr(fd, &device_bdaddr) < 0)
return false;

- if (get_master_bdaddr(fd, &master_bdaddr) < 0)
- return false;
-
/* This can happen if controller was plugged while already connected
* eg. to charge up battery. */
device = btd_adapter_find_device(adapter, &device_bdaddr,
@@ -155,25 +197,14 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter)
if (device && btd_device_is_connected(device))
return false;

- adapter_bdaddr = btd_adapter_get_address(adapter);
-
- if (bacmp(adapter_bdaddr, &master_bdaddr)) {
- if (set_master_bdaddr(fd, adapter_bdaddr) < 0)
- return false;
- }
-
- ba2str(&device_bdaddr, device_addr);
- ba2str(&master_bdaddr, master_addr);
- ba2str(adapter_bdaddr, adapter_addr);
- DBG("remote %s old_master %s new_master %s",
- device_addr, master_addr, adapter_addr);
-
device = btd_adapter_get_device(adapter, &device_bdaddr, BDADDR_BREDR);

if (g_slist_find_custom(btd_device_get_uuids(device), HID_UUID,
(GCompareFunc)strcasecmp)) {
+ char device_addr[18];
+ ba2str(&device_bdaddr, device_addr);
DBG("device %s already known, skipping", device_addr);
- return true;
+ return false;
}

info("sixaxis: setting up new device");
@@ -181,7 +212,20 @@ static bool setup_device(int fd, int index, struct btd_adapter *adapter)
btd_device_device_set_name(device, devices[index].name);
btd_device_set_pnpid(device, devices[index].source, devices[index].vid,
devices[index].pid, devices[index].version);
- btd_device_set_temporary(device, false);
+ btd_device_set_temporary(device, true);
+
+ closure = g_new0(struct authentication_closure, 1);
+ if (!closure) {
+ btd_adapter_remove_device(adapter, device);
+ return false;
+ }
+ closure->adapter = adapter;
+ closure->device = device;
+ closure->fd = fd;
+ bacpy(&closure->bdaddr, &device_bdaddr);
+ adapter_bdaddr = btd_adapter_get_address(adapter);
+ btd_request_authorization_cable_configured(adapter_bdaddr, &device_bdaddr,
+ HID_UUID, agent_auth_cb, closure);

return true;
}
@@ -236,8 +280,9 @@ static void device_added(struct udev_device *udevice)
if (fd < 0)
return;

- setup_device(fd, index, adapter);
- close(fd);
+ /* Only close the fd if an authentication is not pending */
+ if (!setup_device(fd, index, adapter))
+ close(fd);
}

static gboolean monitor_watch(GIOChannel *source, GIOCondition condition,
--
2.14.2