summaryrefslogtreecommitdiff
path: root/src/advertising.c
diff options
context:
space:
mode:
authorDaniel Winkler <danielwinkler@google.com>2020-10-29 16:06:19 -0700
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2020-10-29 17:45:21 -0700
commitf63c569f971ba9c6f028a9c8bf68be300efbba94 (patch)
treed5481d835847b8d65534d235e7f4fa10705e3c48 /src/advertising.c
parentcf7795a6ad50ab379bb6a0dceff2b0dc99ed5456 (diff)
downloadbluez-f63c569f971ba9c6f028a9c8bf68be300efbba94.tar.gz
advertising: Query LE TX range at manager initialization
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.
Diffstat (limited to 'src/advertising.c')
-rw-r--r--src/advertising.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/advertising.c b/src/advertising.c
index 538c788a5..f12534776 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
@@ -1700,6 +1702,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)
{
@@ -1721,6 +1766,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),
@@ -1737,6 +1784,15 @@ 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.
+ */
+ if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL &&
+ btd_has_kernel_features(KERNEL_HAS_CONTROLLER_CAP_CMD))
+ mgmt_send(manager->mgmt, MGMT_OP_READ_CONTROLLER_CAP,
+ manager->mgmt_index, 0, NULL,
+ read_controller_cap_complete, manager, NULL);
+
return manager;
fail: