@@ -608,10 +608,17 @@ 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_MIN 0x04
+#define MGMT_CAP_LE_TX_PWR_MAX 0x05
+
+#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
@@ -58,6 +58,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
@@ -1699,6 +1701,58 @@ 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 %u != %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_MIN:
+ if ((tag_len - sizeof(tag_type)) !=
+ sizeof(manager->min_tx_power)) {
+ error("TX power had unexpected length %d",
+ tag_len);
+ break;
+ }
+ memcpy(&manager->min_tx_power, &ptr[offset], tag_len);
+ break;
+ case MGMT_CAP_LE_TX_PWR_MAX:
+ if ((tag_len - sizeof(tag_type)) !=
+ sizeof(manager->min_tx_power)) {
+ error("TX power had unexpected length %d",
+ tag_len);
+ break;
+ }
+ memcpy(&manager->max_tx_power, &ptr[offset], tag_len);
+ break;
+ }
+
+ /* 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)
{
@@ -1738,6 +1792,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:
@@ -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");