2024-02-10 22:22:44

by Vibhav Pant

[permalink] [raw]
Subject: [PATCH 0/1] Bluetooth: mgmt: Add command for getting device IO capabilities.

The following patch adds a new command to the bluetooth management interface,
GET_DEVICE_IO_CAPABILITY. The command allows userspace to get the IO capability,
and the authentication methods supported by a connected device. The command is
necessary in order to implement parts of the Win32 Bluetooth API in the Wine,
specifically the following two structs:

* BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS, which provides IO and auth capabilities
info for an incoming authentication request from a device.

* BTH_DEVICE_INFO, which contains flags indicating whether the device supports
Simple Secure Pairing and MITM protection. The former is supported through BlueZ's
"LegacyPairing" property.

Because the Wine API are implemented on top of BlueZ, I'll also be providing a
corresponding patch that uses the newly added management command to expose the
capabilities through new properties in the org.bluez.Device1 interface.

Thanks,
Vibhav

Vibhav Pant (1):
Bluetooth: mgmt: Add command for getting device IO capabilities.

include/net/bluetooth/mgmt.h | 19 ++++++++
net/bluetooth/mgmt.c | 89 ++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)

--
2.43.0



2024-02-10 22:23:01

by Vibhav Pant

[permalink] [raw]
Subject: [PATCH 1/1] Bluetooth: mgmt: Add command for getting device IO capabilities.

get_device_io_capability allows to get a connected device's IO
capabilities, including the authentication method (and MITM support)
requested, stored in the hci_conn for the device.

Signed-off-by: Vibhav Pant <[email protected]>
---
include/net/bluetooth/mgmt.h | 19 ++++++++
net/bluetooth/mgmt.c | 89 ++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index d382679efd2b..dba431baaef8 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -878,6 +878,25 @@ struct mgmt_cp_mesh_send_cancel {
} __packed;
#define MGMT_MESH_SEND_CANCEL_SIZE 1

+#define MGMT_OP_GET_DEVICE_IO_CAPABILITY 0x005B
+struct mgmt_cp_get_device_io_capability {
+ struct mgmt_addr_info addr;
+} __packed;
+#define MGMT_GET_DEVICE_IO_CAPABILITY_SIZE MGMT_ADDR_INFO_SIZE
+struct mgmt_rp_get_device_io_capability {
+ struct mgmt_addr_info addr;
+ __u8 flags;
+} __packed;
+
+#define MGMT_DEVICE_IO_CAP_FLAG_IO_DISPLAY_ONLY BIT(0)
+#define MGMT_DEVICE_IO_CAP_FLAG_IO_DISPLAY_YESNO BIT(1)
+#define MGMT_DEVICE_IO_CAP_FLAG_IO_KEYBOARD_ONLY BIT(2)
+#define MGMT_DEVICE_IO_CAP_FLAG_IO_NO_INPUT_OUTPUT BIT(3)
+#define MGMT_DEVICE_IO_CAP_FLAG_AT_NO_BONDING BIT(4)
+#define MGMT_DEVICE_IO_CAP_FLAG_AT_DEDICATED_BONDING BIT(5)
+#define MGMT_DEVICE_IO_CAP_FLAG_AT_GENERAL_BONDING BIT(6)
+#define MGMT_DEVICE_IO_CAP_FLAG_AT_MITM BIT(7)
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 78ab562807d0..92b4317e60a1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -28,6 +28,7 @@
#include <asm/unaligned.h>

#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/l2cap.h>
@@ -67,6 +68,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_PIN_CODE_REPLY,
MGMT_OP_PIN_CODE_NEG_REPLY,
MGMT_OP_SET_IO_CAPABILITY,
+ MGMT_OP_GET_DEVICE_IO_CAPABILITY,
MGMT_OP_PAIR_DEVICE,
MGMT_OP_CANCEL_PAIR_DEVICE,
MGMT_OP_UNPAIR_DEVICE,
@@ -3303,6 +3305,92 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
NULL, 0);
}

+static int get_device_io_capability(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_get_device_io_capability *cp = data;
+ struct mgmt_rp_get_device_io_capability rp;
+ struct hci_conn *conn;
+ int err = 0;
+
+ bt_dev_dbg(hdev, "sock %p", sk);
+
+ memset(&rp, 0, sizeof(rp));
+ bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+ rp.addr.type = cp->addr.type;
+
+ if (!bdaddr_type_is_valid(cp->addr.type))
+ return mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_GET_DEVICE_IO_CAPABILITY,
+ MGMT_STATUS_INVALID_PARAMS, &rp,
+ sizeof(rp));
+ hci_dev_lock(hdev);
+
+ if (!hdev_is_powered(hdev)) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_GET_DEVICE_IO_CAPABILITY,
+ MGMT_STATUS_NOT_POWERED, &rp,
+ sizeof(rp));
+ goto unlock;
+ }
+
+ if (cp->addr.type == BDADDR_BREDR)
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+ &cp->addr.bdaddr);
+ else
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
+
+ if (!conn) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_GET_DEVICE_IO_CAPABILITY,
+ MGMT_STATUS_NOT_CONNECTED, &rp,
+ sizeof(rp));
+ goto unlock;
+ }
+
+ switch (conn->remote_cap) {
+ case HCI_IO_DISPLAY_ONLY:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_IO_DISPLAY_ONLY;
+ break;
+ case HCI_IO_DISPLAY_YESNO:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_IO_DISPLAY_YESNO;
+ break;
+ case HCI_IO_KEYBOARD_ONLY:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_IO_KEYBOARD_ONLY;
+ break;
+ case HCI_IO_NO_INPUT_OUTPUT:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_IO_NO_INPUT_OUTPUT;
+ break;
+ }
+
+ switch (conn->remote_auth) {
+ case HCI_AT_NO_BONDING_MITM:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_AT_MITM;
+ fallthrough;
+ case HCI_AT_NO_BONDING:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_AT_NO_BONDING;
+ break;
+ case HCI_AT_DEDICATED_BONDING_MITM:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_AT_MITM;
+ fallthrough;
+ case HCI_AT_DEDICATED_BONDING:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_AT_DEDICATED_BONDING;
+ break;
+ case HCI_AT_GENERAL_BONDING_MITM:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_AT_MITM;
+ fallthrough;
+ case HCI_AT_GENERAL_BONDING:
+ rp.flags |= MGMT_DEVICE_IO_CAP_FLAG_AT_GENERAL_BONDING;
+ break;
+ }
+
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_IO_CAPABILITY,
+ MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
+unlock:
+ hci_dev_unlock(hdev);
+ return err;
+}
+
static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@@ -9217,6 +9305,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
{ pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
{ set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
+ { get_device_io_capability,MGMT_GET_DEVICE_IO_CAPABILITY_SIZE },
{ pair_device, MGMT_PAIR_DEVICE_SIZE },
{ cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
{ unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
--
2.43.0