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 <vibhavp@xxxxxxxxx> --- 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