diff mbox series

[Bluez,v4,07/10] advertising: Query LE TX range at manager initialization

Message ID 20201001155738.Bluez.v4.7.I187f71748b9bd93f6bf97ec4a195216109c3ea06@changeid (mailing list archive)
State New, archived
Headers show
Series Bluetooth: Add new MGMT interface for advertising add | expand

Commit Message

Daniel Winkler Oct. 1, 2020, 11:01 p.m. UTC
This patch calls the new MGMT command to get controller capabilities,
and parses the min and max LE tx power range when the manager is
initialized. This will be used to populate a client-facing dbus entry so
that the client will know the advertising capabilities of the controller
before registering an advertisement.

This patch is tested by manually verifying the data is parsed correctly
from the MGMT response.

Reviewed-by: Sonny Sasaka <sonnysasaka@chromium.org>
Reviewed-by: Alain Michaud <alainm@chromium.org>
---

Changes in v4:
- Move tx power range into single capability field

Changes in v3: None
Changes in v2: None

 lib/mgmt.h        | 14 ++++++++----
 src/advertising.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/btmgmt.c    | 12 +++++------
 3 files changed, 70 insertions(+), 10 deletions(-)

Comments

Luiz Augusto von Dentz Oct. 27, 2020, 10:08 p.m. UTC | #1
Hi Daniel,

On Thu, Oct 1, 2020 at 4:05 PM Daniel Winkler <danielwinkler@google.com> wrote:
>
> This patch calls the new MGMT command to get controller capabilities,
> and parses the min and max LE tx power range when the manager is
> initialized. This will be used to populate a client-facing dbus entry so
> that the client will know the advertising capabilities of the controller
> before registering an advertisement.
>
> This patch is tested by manually verifying the data is parsed correctly
> from the MGMT response.
>
> Reviewed-by: Sonny Sasaka <sonnysasaka@chromium.org>
> Reviewed-by: Alain Michaud <alainm@chromium.org>
> ---
>
> Changes in v4:
> - Move tx power range into single capability field
>
> Changes in v3: None
> Changes in v2: None
>
>  lib/mgmt.h        | 14 ++++++++----
>  src/advertising.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
>  tools/btmgmt.c    | 12 +++++------
>  3 files changed, 70 insertions(+), 10 deletions(-)
>
> diff --git a/lib/mgmt.h b/lib/mgmt.h
> index 7ab4fb797..f37f7e654 100644
> --- a/lib/mgmt.h
> +++ b/lib/mgmt.h
> @@ -599,10 +599,16 @@ struct mgmt_cp_set_blocked_keys {
>         struct mgmt_blocked_key_info keys[0];
>  } __packed;
>
> -#define MGMT_OP_READ_SECURITY_INFO     0x0048
> -struct mgmt_rp_read_security_info {
> -       uint16_t sec_len;
> -       uint8_t  sec[0];
> +#define MGMT_CAP_SEC_FLAGS             0x01
> +#define MGMT_CAP_MAX_ENC_KEY_SIZE      0x02
> +#define MGMT_CAP_SMP_MAX_ENC_KEY_SIZE  0x03
> +#define MGMT_CAP_LE_TX_PWR             0x04
> +
> +#define MGMT_OP_READ_CONTROLLER_CAP    0x0048
> +#define MGMT_READ_CONTROLLER_CAP_SIZE  0
> +struct mgmt_rp_read_controller_cap {
> +       uint16_t cap_len;
> +       uint8_t cap[0];
>  } __packed;
>
>  #define MGMT_OP_READ_EXP_FEATURES_INFO 0x0049
> diff --git a/src/advertising.c b/src/advertising.c
> index 052964d42..41d0658c8 100644
> --- a/src/advertising.c
> +++ b/src/advertising.c
> @@ -49,6 +49,8 @@ struct btd_adv_manager {
>         uint32_t supported_flags;
>         unsigned int instance_bitmap;
>         bool extended_add_cmds;
> +       int8_t min_tx_power;
> +       int8_t max_tx_power;
>  };
>
>  #define AD_TYPE_BROADCAST 0
> @@ -1679,6 +1681,49 @@ static void read_adv_features_callback(uint8_t status, uint16_t length,
>                 remove_advertising(manager, 0);
>  }
>
> +static void read_controller_cap_complete(uint8_t status, uint16_t length,
> +                                       const void *param, void *user_data)
> +{
> +       struct btd_adv_manager *manager = user_data;
> +       const struct mgmt_rp_read_controller_cap *rp = param;
> +       const uint8_t *ptr = rp->cap;
> +       size_t offset = 0;
> +       uint8_t tag_len;
> +       uint8_t tag_type;
> +
> +       if (status || !param) {
> +               error("Failed to read advertising features: %s (0x%02x)",
> +                                               mgmt_errstr(status), status);
> +               return;
> +       }
> +
> +       if (sizeof(rp->cap_len) + rp->cap_len != length) {
> +               error("Controller capabilities malformed, size %lu != %u",
> +                               sizeof(rp->cap_len) + rp->cap_len, length);
> +               return;
> +       }
> +
> +       while (offset < rp->cap_len) {
> +               tag_len = ptr[offset++];
> +               tag_type = ptr[offset++];
> +
> +               switch (tag_type) {
> +               case MGMT_CAP_LE_TX_PWR:
> +                       if ((tag_len - sizeof(tag_type)) !=
> +                                       2*sizeof(manager->min_tx_power)) {
> +                               error("TX power had unexpected length %d",
> +                                       tag_len);
> +                               break;
> +                       }
> +                       memcpy(&manager->min_tx_power, &ptr[offset], tag_len);
> +                       memcpy(&manager->max_tx_power, &ptr[offset+1], tag_len);
> +               }
> +
> +               /* Step to the next entry */
> +               offset += (tag_len - sizeof(tag_type));
> +       }
> +}
> +
>  static struct btd_adv_manager *manager_create(struct btd_adapter *adapter,
>                                                 struct mgmt *mgmt)
>  {
> @@ -1700,6 +1745,8 @@ static struct btd_adv_manager *manager_create(struct btd_adapter *adapter,
>         manager->supported_flags = MGMT_ADV_FLAG_LOCAL_NAME;
>         manager->extended_add_cmds =
>                         btd_has_kernel_features(KERNEL_HAS_EXT_ADV_ADD_CMDS);
> +       manager->min_tx_power = ADV_TX_POWER_NO_PREFERENCE;
> +       manager->max_tx_power = ADV_TX_POWER_NO_PREFERENCE;
>
>         if (!g_dbus_register_interface(btd_get_dbus_connection(),
>                                         adapter_get_path(manager->adapter),
> @@ -1716,6 +1763,13 @@ static struct btd_adv_manager *manager_create(struct btd_adapter *adapter,
>                 goto fail;
>         }
>
> +       /* Query controller capabilities. This will be used to display valid
> +        * advertising tx power range to the client.
> +        */
> +       mgmt_send(manager->mgmt, MGMT_OP_READ_CONTROLLER_CAP,
> +               manager->mgmt_index, 0, NULL,
> +               read_controller_cap_complete, manager, NULL);

I'd make this conditional to experimental for now, also don't we need
to check the kernel has support for it?

>         return manager;
>
>  fail:
> diff --git a/tools/btmgmt.c b/tools/btmgmt.c
> index 48c9e5887..8b1cc4df5 100644
> --- a/tools/btmgmt.c
> +++ b/tools/btmgmt.c
> @@ -1531,7 +1531,7 @@ static void cmd_extinfo(int argc, char **argv)
>  static void sec_info_rsp(uint8_t status, uint16_t len, const void *param,
>                                                         void *user_data)
>  {
> -       const struct mgmt_rp_read_security_info *rp = param;
> +       const struct mgmt_rp_read_controller_cap *rp = param;
>         uint16_t index = PTR_TO_UINT(user_data);
>
>         if (status != 0) {
> @@ -1546,7 +1546,7 @@ static void sec_info_rsp(uint8_t status, uint16_t len, const void *param,
>         }
>
>         print("Primary controller (hci%u)", index);
> -       print("\tSecurity info length: %u", le16_to_cpu(rp->sec_len));
> +       print("\tSecurity info length: %u", le16_to_cpu(rp->cap_len));
>
>  done:
>         pending_index--;
> @@ -1589,11 +1589,11 @@ static void sec_index_rsp(uint8_t status, uint16_t len, const void *param,
>                 if (rp->entry[i].type != 0x00)
>                         continue;
>
> -               if (!mgmt_send(mgmt, MGMT_OP_READ_SECURITY_INFO,
> +               if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP,
>                                                 index, 0, NULL, sec_info_rsp,
>                                                 UINT_TO_PTR(index), NULL)) {
> -                               error("Unable to send read_security_info cmd");
> -                               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +                       error("Unable to send read_security_info cmd");
> +                       return bt_shell_noninteractive_quit(EXIT_FAILURE);
>                 }
>                 pending_index++;
>         }
> @@ -1615,7 +1615,7 @@ static void cmd_secinfo(int argc, char **argv)
>                 return;
>         }
>
> -       if (!mgmt_send(mgmt, MGMT_OP_READ_SECURITY_INFO, mgmt_index, 0, NULL,
> +       if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, mgmt_index, 0, NULL,
>                                         sec_info_rsp,
>                                         UINT_TO_PTR(mgmt_index), NULL)) {
>                 error("Unable to send read_security_info cmd");
> --
> 2.28.0.709.gb0816b6eb0-goog
>
diff mbox series

Patch

diff --git a/lib/mgmt.h b/lib/mgmt.h
index 7ab4fb797..f37f7e654 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -599,10 +599,16 @@  struct mgmt_cp_set_blocked_keys {
 	struct mgmt_blocked_key_info keys[0];
 } __packed;
 
-#define MGMT_OP_READ_SECURITY_INFO	0x0048
-struct mgmt_rp_read_security_info {
-	uint16_t sec_len;
-	uint8_t  sec[0];
+#define MGMT_CAP_SEC_FLAGS		0x01
+#define MGMT_CAP_MAX_ENC_KEY_SIZE	0x02
+#define MGMT_CAP_SMP_MAX_ENC_KEY_SIZE	0x03
+#define MGMT_CAP_LE_TX_PWR		0x04
+
+#define MGMT_OP_READ_CONTROLLER_CAP	0x0048
+#define MGMT_READ_CONTROLLER_CAP_SIZE	0
+struct mgmt_rp_read_controller_cap {
+	uint16_t cap_len;
+	uint8_t cap[0];
 } __packed;
 
 #define MGMT_OP_READ_EXP_FEATURES_INFO	0x0049
diff --git a/src/advertising.c b/src/advertising.c
index 052964d42..41d0658c8 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -49,6 +49,8 @@  struct btd_adv_manager {
 	uint32_t supported_flags;
 	unsigned int instance_bitmap;
 	bool extended_add_cmds;
+	int8_t min_tx_power;
+	int8_t max_tx_power;
 };
 
 #define AD_TYPE_BROADCAST 0
@@ -1679,6 +1681,49 @@  static void read_adv_features_callback(uint8_t status, uint16_t length,
 		remove_advertising(manager, 0);
 }
 
+static void read_controller_cap_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct btd_adv_manager *manager = user_data;
+	const struct mgmt_rp_read_controller_cap *rp = param;
+	const uint8_t *ptr = rp->cap;
+	size_t offset = 0;
+	uint8_t tag_len;
+	uint8_t tag_type;
+
+	if (status || !param) {
+		error("Failed to read advertising features: %s (0x%02x)",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	if (sizeof(rp->cap_len) + rp->cap_len != length) {
+		error("Controller capabilities malformed, size %lu != %u",
+				sizeof(rp->cap_len) + rp->cap_len, length);
+		return;
+	}
+
+	while (offset < rp->cap_len) {
+		tag_len = ptr[offset++];
+		tag_type = ptr[offset++];
+
+		switch (tag_type) {
+		case MGMT_CAP_LE_TX_PWR:
+			if ((tag_len - sizeof(tag_type)) !=
+					2*sizeof(manager->min_tx_power)) {
+				error("TX power had unexpected length %d",
+					tag_len);
+				break;
+			}
+			memcpy(&manager->min_tx_power, &ptr[offset], tag_len);
+			memcpy(&manager->max_tx_power, &ptr[offset+1], tag_len);
+		}
+
+		/* Step to the next entry */
+		offset += (tag_len - sizeof(tag_type));
+	}
+}
+
 static struct btd_adv_manager *manager_create(struct btd_adapter *adapter,
 						struct mgmt *mgmt)
 {
@@ -1700,6 +1745,8 @@  static struct btd_adv_manager *manager_create(struct btd_adapter *adapter,
 	manager->supported_flags = MGMT_ADV_FLAG_LOCAL_NAME;
 	manager->extended_add_cmds =
 			btd_has_kernel_features(KERNEL_HAS_EXT_ADV_ADD_CMDS);
+	manager->min_tx_power = ADV_TX_POWER_NO_PREFERENCE;
+	manager->max_tx_power = ADV_TX_POWER_NO_PREFERENCE;
 
 	if (!g_dbus_register_interface(btd_get_dbus_connection(),
 					adapter_get_path(manager->adapter),
@@ -1716,6 +1763,13 @@  static struct btd_adv_manager *manager_create(struct btd_adapter *adapter,
 		goto fail;
 	}
 
+	/* Query controller capabilities. This will be used to display valid
+	 * advertising tx power range to the client.
+	 */
+	mgmt_send(manager->mgmt, MGMT_OP_READ_CONTROLLER_CAP,
+		manager->mgmt_index, 0, NULL,
+		read_controller_cap_complete, manager, NULL);
+
 	return manager;
 
 fail:
diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 48c9e5887..8b1cc4df5 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -1531,7 +1531,7 @@  static void cmd_extinfo(int argc, char **argv)
 static void sec_info_rsp(uint8_t status, uint16_t len, const void *param,
 							void *user_data)
 {
-	const struct mgmt_rp_read_security_info *rp = param;
+	const struct mgmt_rp_read_controller_cap *rp = param;
 	uint16_t index = PTR_TO_UINT(user_data);
 
 	if (status != 0) {
@@ -1546,7 +1546,7 @@  static void sec_info_rsp(uint8_t status, uint16_t len, const void *param,
 	}
 
 	print("Primary controller (hci%u)", index);
-	print("\tSecurity info length: %u", le16_to_cpu(rp->sec_len));
+	print("\tSecurity info length: %u", le16_to_cpu(rp->cap_len));
 
 done:
 	pending_index--;
@@ -1589,11 +1589,11 @@  static void sec_index_rsp(uint8_t status, uint16_t len, const void *param,
 		if (rp->entry[i].type != 0x00)
 			continue;
 
-		if (!mgmt_send(mgmt, MGMT_OP_READ_SECURITY_INFO,
+		if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP,
 						index, 0, NULL, sec_info_rsp,
 						UINT_TO_PTR(index), NULL)) {
-				error("Unable to send read_security_info cmd");
-				return bt_shell_noninteractive_quit(EXIT_FAILURE);
+			error("Unable to send read_security_info cmd");
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 		pending_index++;
 	}
@@ -1615,7 +1615,7 @@  static void cmd_secinfo(int argc, char **argv)
 		return;
 	}
 
-	if (!mgmt_send(mgmt, MGMT_OP_READ_SECURITY_INFO, mgmt_index, 0, NULL,
+	if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, mgmt_index, 0, NULL,
 					sec_info_rsp,
 					UINT_TO_PTR(mgmt_index), NULL)) {
 		error("Unable to send read_security_info cmd");