We need to know if kernel supports the new MGMT interface. To do so, we call MGMT_OP_READ_COMMANDS when our manager is created and check if the new commands are available. This will then be used to route our requests for new advertisements. The change is tested by manually verifying that the correct MGMT commands are used when the feature is and is not available in kernel. Reviewed-by: Sonny Sasaka <sonnysasaka@xxxxxxxxxxxx> --- src/advertising.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/advertising.c b/src/advertising.c index e5f25948d..172a83907 100644 --- a/src/advertising.c +++ b/src/advertising.c @@ -57,6 +57,7 @@ struct btd_adv_manager { uint8_t max_ads; uint32_t supported_flags; unsigned int instance_bitmap; + bool extended_add_cmds; }; #define AD_TYPE_BROADCAST 0 @@ -1407,6 +1408,51 @@ static void read_adv_features_callback(uint8_t status, uint16_t length, remove_advertising(manager, 0); } +static void read_commands_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_commands *rp = param; + uint16_t num_commands, num_events; + size_t expected_len; + int i; + + if (status != MGMT_STATUS_SUCCESS) { + error("Failed to read supported commands: %s (0x%02x)", + mgmt_errstr(status), status); + return; + } + + if (length < sizeof(*rp)) { + error("Wrong size of read commands response"); + return; + } + + num_commands = btohs(rp->num_commands); + num_events = btohs(rp->num_events); + + expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) + + num_events * sizeof(uint16_t); + + if (length < expected_len) { + error("Too small reply for supported commands: (%u != %zu)", + length, expected_len); + return; + } + + for (i = 0; i < num_commands; i++) { + uint16_t op = get_le16(rp->opcodes + i); + + switch (op) { + case MGMT_OP_ADD_EXT_ADV_PARAMS: + manager->extended_add_cmds = true; + break; + default: + break; + } + } +} + static struct btd_adv_manager *manager_create(struct btd_adapter *adapter, struct mgmt *mgmt) { @@ -1426,6 +1472,7 @@ static struct btd_adv_manager *manager_create(struct btd_adapter *adapter, manager->mgmt_index = btd_adapter_get_index(adapter); manager->clients = queue_new(); manager->supported_flags = MGMT_ADV_FLAG_LOCAL_NAME; + manager->extended_add_cmds = false; if (!g_dbus_register_interface(btd_get_dbus_connection(), adapter_get_path(manager->adapter), @@ -1442,6 +1489,13 @@ static struct btd_adv_manager *manager_create(struct btd_adapter *adapter, goto fail; } + /* Determine if kernel supports extended advertising add command. We + * don't care if this request fails, as we will fall back to legacy + * add_advertising by default + */ + mgmt_send(manager->mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, + NULL, read_commands_complete, manager, NULL); + return manager; fail: -- 2.28.0.618.gf4bc123cb7-goog