summaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2015-11-19 10:16:43 -0500
committerJohan Hedberg <johan.hedberg@intel.com>2015-11-22 09:26:05 -0500
commit40b25fe5dc57a6557b96241b75ae63dce716a487 (patch)
tree04ea7578edcbccf324e75d6ed2b5d23d9b759017 /net/bluetooth
parent31a3248dd97be9268859abed9a30c1040b2f4090 (diff)
Bluetooth: Add support for Get Advertising Size Information command
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/mgmt.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 05370e76feb0..dc8e428050d9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -102,6 +102,7 @@ static const u16 mgmt_commands[] = {
102 MGMT_OP_READ_ADV_FEATURES, 102 MGMT_OP_READ_ADV_FEATURES,
103 MGMT_OP_ADD_ADVERTISING, 103 MGMT_OP_ADD_ADVERTISING,
104 MGMT_OP_REMOVE_ADVERTISING, 104 MGMT_OP_REMOVE_ADVERTISING,
105 MGMT_OP_GET_ADV_SIZE_INFO,
105}; 106};
106 107
107static const u16 mgmt_events[] = { 108static const u16 mgmt_events[] = {
@@ -7059,6 +7060,62 @@ unlock:
7059 return err; 7060 return err;
7060} 7061}
7061 7062
7063static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
7064{
7065 u8 max_len = HCI_MAX_AD_LENGTH;
7066
7067 if (is_adv_data) {
7068 if (adv_flags & (MGMT_ADV_FLAG_DISCOV |
7069 MGMT_ADV_FLAG_LIMITED_DISCOV |
7070 MGMT_ADV_FLAG_MANAGED_FLAGS))
7071 max_len -= 3;
7072
7073 if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
7074 max_len -= 3;
7075 }
7076
7077 return max_len;
7078}
7079
7080static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
7081 void *data, u16 data_len)
7082{
7083 struct mgmt_cp_get_adv_size_info *cp = data;
7084 struct mgmt_rp_get_adv_size_info rp;
7085 u32 flags, supported_flags;
7086 int err;
7087
7088 BT_DBG("%s", hdev->name);
7089
7090 if (!lmp_le_capable(hdev))
7091 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7092 MGMT_STATUS_REJECTED);
7093
7094 if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
7095 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7096 MGMT_STATUS_INVALID_PARAMS);
7097
7098 flags = __le32_to_cpu(cp->flags);
7099
7100 /* The current implementation only supports a subset of the specified
7101 * flags.
7102 */
7103 supported_flags = get_supported_adv_flags(hdev);
7104 if (flags & ~supported_flags)
7105 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7106 MGMT_STATUS_INVALID_PARAMS);
7107
7108 rp.instance = cp->instance;
7109 rp.flags = cp->flags;
7110 rp.max_adv_data_len = tlv_data_max_len(flags, true);
7111 rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
7112
7113 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
7114 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
7115
7116 return err;
7117}
7118
7062static const struct hci_mgmt_handler mgmt_handlers[] = { 7119static const struct hci_mgmt_handler mgmt_handlers[] = {
7063 { NULL }, /* 0x0000 (no command) */ 7120 { NULL }, /* 0x0000 (no command) */
7064 { read_version, MGMT_READ_VERSION_SIZE, 7121 { read_version, MGMT_READ_VERSION_SIZE,
@@ -7146,6 +7203,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
7146 { add_advertising, MGMT_ADD_ADVERTISING_SIZE, 7203 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
7147 HCI_MGMT_VAR_LEN }, 7204 HCI_MGMT_VAR_LEN },
7148 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE }, 7205 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
7206 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
7149}; 7207};
7150 7208
7151void mgmt_index_added(struct hci_dev *hdev) 7209void mgmt_index_added(struct hci_dev *hdev)