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@xxxxxxxxxxxx> wrote: > > From: Abhishek Pandit-Subedi <abhishekpandit@xxxxxxxxxxxx> > > 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@xxxxxxxxxxxx> > Reviewed-by: Alain Michaud <alainm@xxxxxxxxxxxx> > Signed-off-by: Marcel Holtmann <marcel@xxxxxxxxxxxx> > --- > 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 >