diff options
author | Daniel Winkler <danielwinkler@google.com> | 2020-10-29 16:06:19 -0700 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2020-10-29 17:45:21 -0700 |
commit | f63c569f971ba9c6f028a9c8bf68be300efbba94 (patch) | |
tree | d5481d835847b8d65534d235e7f4fa10705e3c48 /src/advertising.c | |
parent | cf7795a6ad50ab379bb6a0dceff2b0dc99ed5456 (diff) | |
download | bluez-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.c | 56 |
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: |