diff mbox series

[v2,05/14] Bluetooth: Add get/set device flags mgmt op

Message ID 146480ca31b6e4caf5c2e4efde2485f63adc0433.1592404644.git.marcel@holtmann.org (mailing list archive)
State New, archived
Headers show
Series Combination of pending patches | expand

Commit Message

Marcel Holtmann June 17, 2020, 2:39 p.m. UTC
From: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>

Add the get device flags and set device flags mgmt ops and the device
flags changed event. Their behavior is described in detail in
mgmt-api.txt in bluez.

Sample btmon trace when a HID device is added (trimmed to 75 chars):

@ MGMT Command: Unknown (0x0050) plen 11        {0x0001} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00                 ...........
@ MGMT Event: Unknown (0x002a) plen 15          {0x0004} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
@ MGMT Event: Unknown (0x002a) plen 15          {0x0003} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
@ MGMT Event: Unknown (0x002a) plen 15          {0x0002} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
@ MGMT Event: Command Compl.. (0x0001) plen 10  {0x0001} [hci0] 18:06:14.98
      Unknown (0x0050) plen 7
        Status: Success (0x00)
        90 c5 13 cd f3 cd 02                             .......
@ MGMT Command: Add Device (0x0033) plen 8      {0x0001} [hci0] 18:06:14.98
        LE Address: CD:F3:CD:13:C5:90 (Static)
        Action: Auto-connect remote device (0x02)
@ MGMT Event: Device Added (0x001a) plen 8      {0x0004} [hci0] 18:06:14.98
        LE Address: CD:F3:CD:13:C5:90 (Static)
        Action: Auto-connect remote device (0x02)
@ MGMT Event: Device Added (0x001a) plen 8      {0x0003} [hci0] 18:06:14.98
        LE Address: CD:F3:CD:13:C5:90 (Static)
        Action: Auto-connect remote device (0x02)
@ MGMT Event: Device Added (0x001a) plen 8      {0x0002} [hci0] 18:06:14.98
        LE Address: CD:F3:CD:13:C5:90 (Static)
        Action: Auto-connect remote device (0x02)
@ MGMT Event: Unknown (0x002a) plen 15          {0x0004} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
@ MGMT Event: Unknown (0x002a) plen 15          {0x0003} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
@ MGMT Event: Unknown (0x002a) plen 15          {0x0002} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
@ MGMT Event: Unknown (0x002a) plen 15          {0x0001} [hci0] 18:06:14.98
        90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............

Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Reviewed-by: Alain Michaud <alainm@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 include/net/bluetooth/mgmt.h |  28 ++++++++
 net/bluetooth/mgmt.c         | 128 +++++++++++++++++++++++++++++++++++
 2 files changed, 156 insertions(+)

Comments

Abhishek Pandit-Subedi June 17, 2020, 6:03 p.m. UTC | #1
Hi Marcel,

This looks good to me. Thanks for removing
HCI_MGMT_DEVICE_FLAGS_EVENTS -- I misunderstood what it was for.

Abhishek

On Wed, Jun 17, 2020 at 7:39 AM Marcel Holtmann <marcel@holtmann.org> wrote:
>
> From: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
>
> Add the get device flags and set device flags mgmt ops and the device
> flags changed event. Their behavior is described in detail in
> mgmt-api.txt in bluez.
>
> Sample btmon trace when a HID device is added (trimmed to 75 chars):
>
> @ MGMT Command: Unknown (0x0050) plen 11        {0x0001} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00                 ...........
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0004} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0003} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0002} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
> @ MGMT Event: Command Compl.. (0x0001) plen 10  {0x0001} [hci0] 18:06:14.98
>       Unknown (0x0050) plen 7
>         Status: Success (0x00)
>         90 c5 13 cd f3 cd 02                             .......
> @ MGMT Command: Add Device (0x0033) plen 8      {0x0001} [hci0] 18:06:14.98
>         LE Address: CD:F3:CD:13:C5:90 (Static)
>         Action: Auto-connect remote device (0x02)
> @ MGMT Event: Device Added (0x001a) plen 8      {0x0004} [hci0] 18:06:14.98
>         LE Address: CD:F3:CD:13:C5:90 (Static)
>         Action: Auto-connect remote device (0x02)
> @ MGMT Event: Device Added (0x001a) plen 8      {0x0003} [hci0] 18:06:14.98
>         LE Address: CD:F3:CD:13:C5:90 (Static)
>         Action: Auto-connect remote device (0x02)
> @ MGMT Event: Device Added (0x001a) plen 8      {0x0002} [hci0] 18:06:14.98
>         LE Address: CD:F3:CD:13:C5:90 (Static)
>         Action: Auto-connect remote device (0x02)
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0004} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0003} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0002} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
> @ MGMT Event: Unknown (0x002a) plen 15          {0x0001} [hci0] 18:06:14.98
>         90 c5 13 cd f3 cd 02 01 00 00 00 01 00 00 00     ...............
>
> Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
> Reviewed-by: Alain Michaud <alainm@chromium.org>
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
>  include/net/bluetooth/mgmt.h |  28 ++++++++
>  net/bluetooth/mgmt.c         | 128 +++++++++++++++++++++++++++++++++++
>  2 files changed, 156 insertions(+)
>
> diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> index e515288f328f..8e47b0c5fe52 100644
> --- a/include/net/bluetooth/mgmt.h
> +++ b/include/net/bluetooth/mgmt.h
> @@ -720,6 +720,27 @@ struct mgmt_rp_set_exp_feature {
>  #define MGMT_OP_SET_DEF_RUNTIME_CONFIG 0x004e
>  #define MGMT_SET_DEF_RUNTIME_CONFIG_SIZE       0
>
> +#define MGMT_OP_GET_DEVICE_FLAGS       0x004F
> +#define MGMT_GET_DEVICE_FLAGS_SIZE     7
> +struct mgmt_cp_get_device_flags {
> +       struct mgmt_addr_info addr;
> +} __packed;
> +struct mgmt_rp_get_device_flags {
> +       struct mgmt_addr_info addr;
> +       __le32 supported_flags;
> +       __le32 current_flags;
> +} __packed;
> +
> +#define MGMT_OP_SET_DEVICE_FLAGS       0x0050
> +#define MGMT_SET_DEVICE_FLAGS_SIZE     11
> +struct mgmt_cp_set_device_flags {
> +       struct mgmt_addr_info addr;
> +       __le32 current_flags;
> +} __packed;
> +struct mgmt_rp_set_device_flags {
> +       struct mgmt_addr_info addr;
> +} __packed;
> +
>  #define MGMT_EV_CMD_COMPLETE           0x0001
>  struct mgmt_ev_cmd_complete {
>         __le16  opcode;
> @@ -951,3 +972,10 @@ struct mgmt_ev_exp_feature_changed {
>         __u8    uuid[16];
>         __le32  flags;
>  } __packed;
> +
> +#define MGMT_EV_DEVICE_FLAGS_CHANGED           0x002a
> +struct mgmt_ev_device_flags_changed {
> +       struct mgmt_addr_info addr;
> +       __le32 supported_flags;
> +       __le32 current_flags;
> +} __packed;
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index d0d0fa832c8a..e409ff48e8e6 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -116,6 +116,8 @@ static const u16 mgmt_commands[] = {
>         MGMT_OP_SET_DEF_SYSTEM_CONFIG,
>         MGMT_OP_READ_DEF_RUNTIME_CONFIG,
>         MGMT_OP_SET_DEF_RUNTIME_CONFIG,
> +       MGMT_OP_GET_DEVICE_FLAGS,
> +       MGMT_OP_SET_DEVICE_FLAGS,
>  };
>
>  static const u16 mgmt_events[] = {
> @@ -156,6 +158,7 @@ static const u16 mgmt_events[] = {
>         MGMT_EV_EXT_INFO_CHANGED,
>         MGMT_EV_PHY_CONFIGURATION_CHANGED,
>         MGMT_EV_EXP_FEATURE_CHANGED,
> +       MGMT_EV_DEVICE_FLAGS_CHANGED,
>  };
>
>  static const u16 mgmt_untrusted_commands[] = {
> @@ -3856,6 +3859,120 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
>                                MGMT_STATUS_NOT_SUPPORTED);
>  }
>
> +#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
> +
> +static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
> +                           u16 data_len)
> +{
> +       struct mgmt_cp_get_device_flags *cp = data;
> +       struct mgmt_rp_get_device_flags rp;
> +       struct bdaddr_list_with_flags *br_params;
> +       struct hci_conn_params *params;
> +       u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
> +       u32 current_flags = 0;
> +       u8 status = MGMT_STATUS_INVALID_PARAMS;
> +
> +       bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
> +                  &cp->addr.bdaddr, cp->addr.type);
> +
> +       if (cp->addr.type == BDADDR_BREDR) {
> +               br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
> +                                                             &cp->addr.bdaddr,
> +                                                             cp->addr.type);
> +               if (!br_params)
> +                       goto done;
> +
> +               current_flags = br_params->current_flags;
> +       } else {
> +               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
> +                                               le_addr_type(cp->addr.type));
> +
> +               if (!params)
> +                       goto done;
> +
> +               current_flags = params->current_flags;
> +       }
> +
> +       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
> +       rp.addr.type = cp->addr.type;
> +       rp.supported_flags = cpu_to_le32(supported_flags);
> +       rp.current_flags = cpu_to_le32(current_flags);
> +
> +       status = MGMT_STATUS_SUCCESS;
> +
> +done:
> +       return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
> +                               &rp, sizeof(rp));
> +}
> +
> +static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
> +                                bdaddr_t *bdaddr, u8 bdaddr_type,
> +                                u32 supported_flags, u32 current_flags)
> +{
> +       struct mgmt_ev_device_flags_changed ev;
> +
> +       bacpy(&ev.addr.bdaddr, bdaddr);
> +       ev.addr.type = bdaddr_type;
> +       ev.supported_flags = cpu_to_le32(supported_flags);
> +       ev.current_flags = cpu_to_le32(current_flags);
> +
> +       mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
> +}
> +
> +static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
> +                           u16 len)
> +{
> +       struct mgmt_cp_set_device_flags *cp = data;
> +       struct bdaddr_list_with_flags *br_params;
> +       struct hci_conn_params *params;
> +       u8 status = MGMT_STATUS_INVALID_PARAMS;
> +       u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
> +       u32 current_flags = __le32_to_cpu(cp->current_flags);
> +
> +       bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
> +                  &cp->addr.bdaddr, cp->addr.type,
> +                  __le32_to_cpu(current_flags));
> +
> +       if ((supported_flags | current_flags) != supported_flags) {
> +               bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
> +                           current_flags, supported_flags);
> +               goto done;
> +       }
> +
> +       if (cp->addr.type == BDADDR_BREDR) {
> +               br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
> +                                                             &cp->addr.bdaddr,
> +                                                             cp->addr.type);
> +
> +               if (br_params) {
> +                       br_params->current_flags = current_flags;
> +                       status = MGMT_STATUS_SUCCESS;
> +               } else {
> +                       bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
> +                                   &cp->addr.bdaddr, cp->addr.type);
> +               }
> +       } else {
> +               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
> +                                               le_addr_type(cp->addr.type));
> +               if (params) {
> +                       params->current_flags = current_flags;
> +                       status = MGMT_STATUS_SUCCESS;
> +               } else {
> +                       bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
> +                                   &cp->addr.bdaddr,
> +                                   le_addr_type(cp->addr.type));
> +               }
> +       }
> +
> +done:
> +       if (status == MGMT_STATUS_SUCCESS)
> +               device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
> +                                    supported_flags, current_flags);
> +
> +       return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
> +                                &cp->addr, sizeof(cp->addr));
> +}
> +
>  static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
>                                          u16 opcode, struct sk_buff *skb)
>  {
> @@ -5973,7 +6090,9 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
>  {
>         struct mgmt_cp_add_device *cp = data;
>         u8 auto_conn, addr_type;
> +       struct hci_conn_params *params;
>         int err;
> +       u32 current_flags = 0;
>
>         bt_dev_dbg(hdev, "sock %p", sk);
>
> @@ -6041,12 +6160,19 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
>                                         MGMT_STATUS_FAILED, &cp->addr,
>                                         sizeof(cp->addr));
>                 goto unlock;
> +       } else {
> +               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
> +                                               addr_type);
> +               if (params)
> +                       current_flags = params->current_flags;
>         }
>
>         hci_update_background_scan(hdev);
>
>  added:
>         device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
> +       device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
> +                            SUPPORTED_DEVICE_FLAGS(), current_flags);
>
>         err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
>                                 MGMT_STATUS_SUCCESS, &cp->addr,
> @@ -7313,6 +7439,8 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
>                                                 HCI_MGMT_UNTRUSTED },
>         { set_def_runtime_config,  MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
>                                                 HCI_MGMT_VAR_LEN },
> +       { get_device_flags,        MGMT_GET_DEVICE_FLAGS_SIZE },
> +       { set_device_flags,        MGMT_SET_DEVICE_FLAGS_SIZE },
>  };
>
>  void mgmt_index_added(struct hci_dev *hdev)
> --
> 2.26.2
>
diff mbox series

Patch

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index e515288f328f..8e47b0c5fe52 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -720,6 +720,27 @@  struct mgmt_rp_set_exp_feature {
 #define MGMT_OP_SET_DEF_RUNTIME_CONFIG	0x004e
 #define MGMT_SET_DEF_RUNTIME_CONFIG_SIZE	0
 
+#define MGMT_OP_GET_DEVICE_FLAGS	0x004F
+#define MGMT_GET_DEVICE_FLAGS_SIZE	7
+struct mgmt_cp_get_device_flags {
+	struct mgmt_addr_info addr;
+} __packed;
+struct mgmt_rp_get_device_flags {
+	struct mgmt_addr_info addr;
+	__le32 supported_flags;
+	__le32 current_flags;
+} __packed;
+
+#define MGMT_OP_SET_DEVICE_FLAGS	0x0050
+#define MGMT_SET_DEVICE_FLAGS_SIZE	11
+struct mgmt_cp_set_device_flags {
+	struct mgmt_addr_info addr;
+	__le32 current_flags;
+} __packed;
+struct mgmt_rp_set_device_flags {
+	struct mgmt_addr_info addr;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16	opcode;
@@ -951,3 +972,10 @@  struct mgmt_ev_exp_feature_changed {
 	__u8	uuid[16];
 	__le32	flags;
 } __packed;
+
+#define MGMT_EV_DEVICE_FLAGS_CHANGED		0x002a
+struct mgmt_ev_device_flags_changed {
+	struct mgmt_addr_info addr;
+	__le32 supported_flags;
+	__le32 current_flags;
+} __packed;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d0d0fa832c8a..e409ff48e8e6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -116,6 +116,8 @@  static const u16 mgmt_commands[] = {
 	MGMT_OP_SET_DEF_SYSTEM_CONFIG,
 	MGMT_OP_READ_DEF_RUNTIME_CONFIG,
 	MGMT_OP_SET_DEF_RUNTIME_CONFIG,
+	MGMT_OP_GET_DEVICE_FLAGS,
+	MGMT_OP_SET_DEVICE_FLAGS,
 };
 
 static const u16 mgmt_events[] = {
@@ -156,6 +158,7 @@  static const u16 mgmt_events[] = {
 	MGMT_EV_EXT_INFO_CHANGED,
 	MGMT_EV_PHY_CONFIGURATION_CHANGED,
 	MGMT_EV_EXP_FEATURE_CHANGED,
+	MGMT_EV_DEVICE_FLAGS_CHANGED,
 };
 
 static const u16 mgmt_untrusted_commands[] = {
@@ -3856,6 +3859,120 @@  static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
 			       MGMT_STATUS_NOT_SUPPORTED);
 }
 
+#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
+
+static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
+			    u16 data_len)
+{
+	struct mgmt_cp_get_device_flags *cp = data;
+	struct mgmt_rp_get_device_flags rp;
+	struct bdaddr_list_with_flags *br_params;
+	struct hci_conn_params *params;
+	u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
+	u32 current_flags = 0;
+	u8 status = MGMT_STATUS_INVALID_PARAMS;
+
+	bt_dev_dbg(hdev, "Get device flags %pMR (type 0x%x)\n",
+		   &cp->addr.bdaddr, cp->addr.type);
+
+	if (cp->addr.type == BDADDR_BREDR) {
+		br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
+							      &cp->addr.bdaddr,
+							      cp->addr.type);
+		if (!br_params)
+			goto done;
+
+		current_flags = br_params->current_flags;
+	} else {
+		params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
+						le_addr_type(cp->addr.type));
+
+		if (!params)
+			goto done;
+
+		current_flags = params->current_flags;
+	}
+
+	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+	rp.addr.type = cp->addr.type;
+	rp.supported_flags = cpu_to_le32(supported_flags);
+	rp.current_flags = cpu_to_le32(current_flags);
+
+	status = MGMT_STATUS_SUCCESS;
+
+done:
+	return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_DEVICE_FLAGS, status,
+				&rp, sizeof(rp));
+}
+
+static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
+				 bdaddr_t *bdaddr, u8 bdaddr_type,
+				 u32 supported_flags, u32 current_flags)
+{
+	struct mgmt_ev_device_flags_changed ev;
+
+	bacpy(&ev.addr.bdaddr, bdaddr);
+	ev.addr.type = bdaddr_type;
+	ev.supported_flags = cpu_to_le32(supported_flags);
+	ev.current_flags = cpu_to_le32(current_flags);
+
+	mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
+}
+
+static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
+			    u16 len)
+{
+	struct mgmt_cp_set_device_flags *cp = data;
+	struct bdaddr_list_with_flags *br_params;
+	struct hci_conn_params *params;
+	u8 status = MGMT_STATUS_INVALID_PARAMS;
+	u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
+	u32 current_flags = __le32_to_cpu(cp->current_flags);
+
+	bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
+		   &cp->addr.bdaddr, cp->addr.type,
+		   __le32_to_cpu(current_flags));
+
+	if ((supported_flags | current_flags) != supported_flags) {
+		bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
+			    current_flags, supported_flags);
+		goto done;
+	}
+
+	if (cp->addr.type == BDADDR_BREDR) {
+		br_params = hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
+							      &cp->addr.bdaddr,
+							      cp->addr.type);
+
+		if (br_params) {
+			br_params->current_flags = current_flags;
+			status = MGMT_STATUS_SUCCESS;
+		} else {
+			bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
+				    &cp->addr.bdaddr, cp->addr.type);
+		}
+	} else {
+		params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
+						le_addr_type(cp->addr.type));
+		if (params) {
+			params->current_flags = current_flags;
+			status = MGMT_STATUS_SUCCESS;
+		} else {
+			bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
+				    &cp->addr.bdaddr,
+				    le_addr_type(cp->addr.type));
+		}
+	}
+
+done:
+	if (status == MGMT_STATUS_SUCCESS)
+		device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+				     supported_flags, current_flags);
+
+	return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_FLAGS, status,
+				 &cp->addr, sizeof(cp->addr));
+}
+
 static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
 				         u16 opcode, struct sk_buff *skb)
 {
@@ -5973,7 +6090,9 @@  static int add_device(struct sock *sk, struct hci_dev *hdev,
 {
 	struct mgmt_cp_add_device *cp = data;
 	u8 auto_conn, addr_type;
+	struct hci_conn_params *params;
 	int err;
+	u32 current_flags = 0;
 
 	bt_dev_dbg(hdev, "sock %p", sk);
 
@@ -6041,12 +6160,19 @@  static int add_device(struct sock *sk, struct hci_dev *hdev,
 					MGMT_STATUS_FAILED, &cp->addr,
 					sizeof(cp->addr));
 		goto unlock;
+	} else {
+		params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
+						addr_type);
+		if (params)
+			current_flags = params->current_flags;
 	}
 
 	hci_update_background_scan(hdev);
 
 added:
 	device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
+	device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
+			     SUPPORTED_DEVICE_FLAGS(), current_flags);
 
 	err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
 				MGMT_STATUS_SUCCESS, &cp->addr,
@@ -7313,6 +7439,8 @@  static const struct hci_mgmt_handler mgmt_handlers[] = {
 						HCI_MGMT_UNTRUSTED },
 	{ set_def_runtime_config,  MGMT_SET_DEF_RUNTIME_CONFIG_SIZE,
 						HCI_MGMT_VAR_LEN },
+	{ get_device_flags,        MGMT_GET_DEVICE_FLAGS_SIZE },
+	{ set_device_flags,        MGMT_SET_DEVICE_FLAGS_SIZE },
 };
 
 void mgmt_index_added(struct hci_dev *hdev)