Skip to content

Commit

Permalink
Bluetooth: Add support for Get Advertising Size Information command
Browse files Browse the repository at this point in the history
The Get Advertising Size Information command allows to retrieve size
information for advertising data and scan response data fields depending
on the selected flags. This is useful if applications want to know the
available size ahead of time.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
  • Loading branch information
Marcel Holtmann authored and Johan Hedberg committed Nov 22, 2015
1 parent 31a3248 commit 40b25fe
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
13 changes: 13 additions & 0 deletions include/net/bluetooth/mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,19 @@ struct mgmt_rp_remove_advertising {
__u8 instance;
} __packed;

#define MGMT_OP_GET_ADV_SIZE_INFO 0x0040
struct mgmt_cp_get_adv_size_info {
__u8 instance;
__le32 flags;
} __packed;
#define MGMT_GET_ADV_SIZE_INFO_SIZE 5
struct mgmt_rp_get_adv_size_info {
__u8 instance;
__le32 flags;
__u8 max_adv_data_len;
__u8 max_scan_rsp_len;
} __packed;

#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
Expand Down
58 changes: 58 additions & 0 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_READ_ADV_FEATURES,
MGMT_OP_ADD_ADVERTISING,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_OP_GET_ADV_SIZE_INFO,
};

static const u16 mgmt_events[] = {
Expand Down Expand Up @@ -7059,6 +7060,62 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
return err;
}

static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
{
u8 max_len = HCI_MAX_AD_LENGTH;

if (is_adv_data) {
if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
MGMT_ADV_FLAG_LIMITED_DISCOV |
MGMT_ADV_FLAG_MANAGED_FLAGS))
max_len -= 3;

if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
max_len -= 3;
}

return max_len;
}

static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
struct mgmt_cp_get_adv_size_info *cp = data;
struct mgmt_rp_get_adv_size_info rp;
u32 flags, supported_flags;
int err;

BT_DBG("%s", hdev->name);

if (!lmp_le_capable(hdev))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_STATUS_REJECTED);

if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_STATUS_INVALID_PARAMS);

flags = __le32_to_cpu(cp->flags);

/* The current implementation only supports a subset of the specified
* flags.
*/
supported_flags = get_supported_adv_flags(hdev);
if (flags & ~supported_flags)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_STATUS_INVALID_PARAMS);

rp.instance = cp->instance;
rp.flags = cp->flags;
rp.max_adv_data_len = tlv_data_max_len(flags, true);
rp.max_scan_rsp_len = tlv_data_max_len(flags, false);

err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));

return err;
}

static const struct hci_mgmt_handler mgmt_handlers[] = {
{ NULL }, /* 0x0000 (no command) */
{ read_version, MGMT_READ_VERSION_SIZE,
Expand Down Expand Up @@ -7146,6 +7203,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ add_advertising, MGMT_ADD_ADVERTISING_SIZE,
HCI_MGMT_VAR_LEN },
{ remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
{ get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
};

void mgmt_index_added(struct hci_dev *hdev)
Expand Down

0 comments on commit 40b25fe

Please sign in to comment.