2015-03-26 01:53:39

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 1/8] Bluetooth: Add macros for advertising instance flags

This patch adds macro definitions for possible advertising instance
flags that can be passed to the "Add Advertising" command.

Signed-off-by: Arman Uguray <[email protected]>
---
include/net/bluetooth/mgmt.h | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 68abd4b..b831242 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -554,6 +554,14 @@ struct mgmt_rp_add_advertising {
__u8 instance;
} __packed;

+#define MGMT_ADV_FLAG_CONNECTABLE BIT(0)
+#define MGMT_ADV_FLAG_DISCOV BIT(1)
+#define MGMT_ADV_FLAG_LIMITED_DISCOV BIT(2)
+#define MGMT_ADV_FLAG_MANAGED_FLAGS BIT(3)
+#define MGMT_ADV_FLAG_TX_POWER BIT(4)
+#define MGMT_ADV_FLAG_APPEARANCE BIT(5)
+#define MGMT_ADV_FLAG_LOCAL_NAME BIT(6)
+
#define MGMT_OP_REMOVE_ADVERTISING 0x003F
struct mgmt_cp_remove_advertising {
__u8 instance;
--
2.2.0.rc0.207.ga3a616c



2015-03-26 02:32:25

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] Bluetooth: Add macros for advertising instance flags

Hi Arman,

> This patch adds macro definitions for possible advertising instance
> flags that can be passed to the "Add Advertising" command.
>
> Signed-off-by: Arman Uguray <[email protected]>
> ---
> include/net/bluetooth/mgmt.h | 8 ++++++++
> 1 file changed, 8 insertions(+)

all 8 patches have been applied to bluetooth-next tree.

Regards

Marcel


2015-03-26 01:53:40

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 2/8] Bluetooth: Support the "connectable mode" adv flag

This patch adds support for the "connectable mode" flag of the
Add Advertising command.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 87 +++++++++++++++++++++++++++++++++-------------------
1 file changed, 56 insertions(+), 31 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 38b03bd..e6280dc 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1013,11 +1013,8 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static void update_adv_data(struct hci_request *req)
+static u8 get_current_adv_instance(struct hci_dev *hdev)
{
- struct hci_dev *hdev = req->hdev;
- u8 instance;
-
/* The "Set Advertising" setting supersedes the "Add Advertising"
* setting. Here we set the advertising data based on which
* setting was set. When neither apply, default to the global settings,
@@ -1025,9 +1022,54 @@ static void update_adv_data(struct hci_request *req)
*/
if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
!hci_dev_test_flag(hdev, HCI_ADVERTISING))
- instance = 0x01;
- else
- instance = 0x00;
+ return 0x01;
+
+ return 0x00;
+}
+
+static bool get_connectable(struct hci_dev *hdev)
+{
+ struct mgmt_pending_cmd *cmd;
+
+ /* If there's a pending mgmt command the flag will not yet have
+ * it's final value, so check for this first.
+ */
+ cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
+ if (cmd) {
+ struct mgmt_mode *cp = cmd->param;
+
+ return cp->val;
+ }
+
+ return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
+}
+
+static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
+{
+ u32 flags;
+
+ if (instance > 0x01)
+ return 0;
+
+ if (instance == 1)
+ return hdev->adv_instance.flags;
+
+ flags = 0;
+
+ /* For instance 0, assemble the flags from global settings */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) ||
+ get_connectable(hdev))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;
+
+ /* TODO: Add the rest of the flags */
+
+ return flags;
+}
+
+static void update_adv_data(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+ u8 instance = get_current_adv_instance(hdev);

update_adv_data_for_instance(req, instance);
}
@@ -1159,22 +1201,6 @@ static void update_class(struct hci_request *req)
hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
}

-static bool get_connectable(struct hci_dev *hdev)
-{
- struct mgmt_pending_cmd *cmd;
-
- /* If there's a pending mgmt command the flag will not yet have
- * it's final value, so check for this first.
- */
- cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
- if (cmd) {
- struct mgmt_mode *cp = cmd->param;
- return cp->val;
- }
-
- return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
-}
-
static void disable_advertising(struct hci_request *req)
{
u8 enable = 0x00;
@@ -1188,6 +1214,8 @@ static void enable_advertising(struct hci_request *req)
struct hci_cp_le_set_adv_param cp;
u8 own_addr_type, enable = 0x01;
bool connectable;
+ u8 instance;
+ u32 flags;

if (hci_conn_num(hdev, LE_LINK) > 0)
return;
@@ -1202,10 +1230,9 @@ static void enable_advertising(struct hci_request *req)
*/
hci_dev_clear_flag(hdev, HCI_LE_ADV);

- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
- connectable = true;
- else
- connectable = get_connectable(hdev);
+ instance = get_current_adv_instance(hdev);
+ flags = get_adv_instance_flags(hdev, instance);
+ connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE);

/* Set require_privacy to true only when non-connectable
* advertising is used. In that case it is fine to use a
@@ -6623,10 +6650,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);

- /* The current implementation only supports adding one instance and
- * doesn't support flags.
- */
- if (cp->instance != 0x01 || flags)
+ /* The current implementation only supports adding one instance */
+ if (cp->instance != 0x01)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

--
2.2.0.rc0.207.ga3a616c


2015-03-26 01:53:41

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 3/8] Bluetooth: Support the "discoverable" adv flag

This patch adds support for the "discoverable" flag of the
Add Advertising command.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 38 ++++++++++++++++++++++++++++++--------
1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e6280dc..03ddcfe 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -975,13 +975,28 @@ static u8 create_default_adv_data(struct hci_dev *hdev, u8 *ptr)

static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
{
- /* TODO: Set the appropriate entries based on advertising instance flags
- * here once flags other than 0 are supported.
- */
+ u8 ad_len = 0, flags = 0;
+
+ if (hdev->adv_instance.flags & MGMT_ADV_FLAG_DISCOV)
+ flags |= LE_AD_GENERAL;
+
+ if (flags) {
+ if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+ flags |= LE_AD_NO_BREDR;
+
+ ptr[0] = 0x02;
+ ptr[1] = EIR_FLAGS;
+ ptr[2] = flags;
+
+ ad_len += 3;
+ ptr += 3;
+ }
+
memcpy(ptr, hdev->adv_instance.adv_data,
hdev->adv_instance.adv_data_len);
+ ad_len += hdev->adv_instance.adv_data_len;

- return hdev->adv_instance.adv_data_len;
+ return ad_len;
}

static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
@@ -6556,12 +6571,16 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
}

static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
- u8 len)
+ u8 len, bool is_adv_data)
{
u8 max_len = HCI_MAX_AD_LENGTH;
int i, cur_len;
+ bool flags_managed = false;

- /* TODO: Correctly reduce len based on adv_flags. */
+ if (is_adv_data && (adv_flags & MGMT_ADV_FLAG_DISCOV)) {
+ flags_managed = true;
+ max_len -= 3;
+ }

if (len > max_len)
return false;
@@ -6570,6 +6589,9 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
cur_len = data[i];

+ if (flags_managed && data[i + 1] == EIR_FLAGS)
+ return false;
+
/* If the current field length would exceed the total data
* length, then it's invalid.
*/
@@ -6671,9 +6693,9 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}

- if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len) ||
+ if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
!tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
- cp->scan_rsp_len)) {
+ cp->scan_rsp_len, false)) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);
goto unlock;
--
2.2.0.rc0.207.ga3a616c


2015-03-26 01:53:43

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 5/8] Bluetooth: Support the "managed-flags" adv flag

This patch adds support for the "managed-flags" flag of the Add
Advertising command.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4cb02f3..0ce4bd6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -986,7 +986,13 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
if (hdev->adv_instance.flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
flags |= LE_AD_LIMITED;

- if (flags) {
+ if (flags || (hdev->adv_instance.flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
+ /* If a discovery flag wasn't provided, simply use the global
+ * settings.
+ */
+ if (!flags)
+ flags |= get_adv_discov_flags(hdev);
+
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
flags |= LE_AD_NO_BREDR;

@@ -6582,7 +6588,8 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
u8 max_len = HCI_MAX_AD_LENGTH;
int i, cur_len;
bool flags_managed = false;
- u32 flags_params = MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV;
+ u32 flags_params = MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
+ MGMT_ADV_FLAG_MANAGED_FLAGS;

if (is_adv_data && (adv_flags & flags_params)) {
flags_managed = true;
--
2.2.0.rc0.207.ga3a616c


2015-03-26 01:53:44

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 6/8] Bluetooth: Support the "tx-power" adv flag

This patch adds support for the "tx-power" flag of the Add
Advertising command.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0ce4bd6..fd41b20 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1004,6 +1004,16 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
ptr += 3;
}

+ if (hdev->adv_tx_power != HCI_TX_POWER_INVALID &&
+ (hdev->adv_instance.flags & MGMT_ADV_FLAG_TX_POWER)) {
+ ptr[0] = 0x02;
+ ptr[1] = EIR_TX_POWER;
+ ptr[2] = (u8)hdev->adv_tx_power;
+
+ ad_len += 3;
+ ptr += 3;
+ }
+
memcpy(ptr, hdev->adv_instance.adv_data,
hdev->adv_instance.adv_data_len);
ad_len += hdev->adv_instance.adv_data_len;
@@ -6588,6 +6598,7 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
u8 max_len = HCI_MAX_AD_LENGTH;
int i, cur_len;
bool flags_managed = false;
+ bool tx_power_managed = false;
u32 flags_params = MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV |
MGMT_ADV_FLAG_MANAGED_FLAGS;

@@ -6596,6 +6607,11 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
max_len -= 3;
}

+ if (is_adv_data && (adv_flags & MGMT_ADV_FLAG_TX_POWER)) {
+ tx_power_managed = true;
+ max_len -= 3;
+ }
+
if (len > max_len)
return false;

@@ -6606,6 +6622,9 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
if (flags_managed && data[i + 1] == EIR_FLAGS)
return false;

+ if (tx_power_managed && data[i + 1] == EIR_TX_POWER)
+ return false;
+
/* If the current field length would exceed the total data
* length, then it's invalid.
*/
--
2.2.0.rc0.207.ga3a616c


2015-03-26 01:53:46

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 8/8] Bluetooth: Unify advertising data code paths

This patch simplifies the code paths for assembling the advertising data
used by advertising instances 0 and 1.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 155 +++++++++++++++++++++------------------------------
1 file changed, 64 insertions(+), 91 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 71d4130..5fc1ebf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -941,52 +941,73 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev)
return 0;
}

-static u8 create_default_adv_data(struct hci_dev *hdev, u8 *ptr)
+static u8 get_current_adv_instance(struct hci_dev *hdev)
{
- u8 ad_len = 0, flags = 0;
-
- flags |= get_adv_discov_flags(hdev);
+ /* The "Set Advertising" setting supersedes the "Add Advertising"
+ * setting. Here we set the advertising data based on which
+ * setting was set. When neither apply, default to the global settings,
+ * represented by instance "0".
+ */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return 0x01;

- if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
- flags |= LE_AD_NO_BREDR;
+ return 0x00;
+}

- if (flags) {
- BT_DBG("adv flags 0x%02x", flags);
+static bool get_connectable(struct hci_dev *hdev)
+{
+ struct mgmt_pending_cmd *cmd;

- ptr[0] = 2;
- ptr[1] = EIR_FLAGS;
- ptr[2] = flags;
+ /* If there's a pending mgmt command the flag will not yet have
+ * it's final value, so check for this first.
+ */
+ cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
+ if (cmd) {
+ struct mgmt_mode *cp = cmd->param;

- ad_len += 3;
- ptr += 3;
+ return cp->val;
}

- if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
- ptr[0] = 2;
- ptr[1] = EIR_TX_POWER;
- ptr[2] = (u8) hdev->adv_tx_power;
+ return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
+}

- ad_len += 3;
- ptr += 3;
- }
+static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
+{
+ u32 flags;

- return ad_len;
+ if (instance > 0x01)
+ return 0;
+
+ if (instance == 0x01)
+ return hdev->adv_instance.flags;
+
+ /* Instance 0 always manages the "Tx Power" and "Flags" fields */
+ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS;
+
+ /* For instance 0, assemble the flags from global settings */
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) ||
+ get_connectable(hdev))
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;
+
+ return flags;
}

-static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
+static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
u8 ad_len = 0, flags = 0;
+ u32 instance_flags = get_adv_instance_flags(hdev, instance);

/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
*/
- if (hdev->adv_instance.flags & MGMT_ADV_FLAG_DISCOV)
+ if (instance_flags & MGMT_ADV_FLAG_DISCOV)
flags |= LE_AD_GENERAL;

- if (hdev->adv_instance.flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
+ if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
flags |= LE_AD_LIMITED;

- if (flags || (hdev->adv_instance.flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
+ if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
/* If a discovery flag wasn't provided, simply use the global
* settings.
*/
@@ -996,16 +1017,22 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
flags |= LE_AD_NO_BREDR;

- ptr[0] = 0x02;
- ptr[1] = EIR_FLAGS;
- ptr[2] = flags;
+ /* If flags would still be empty, then there is no need to
+ * include the "Flags" AD field".
+ */
+ if (flags) {
+ ptr[0] = 0x02;
+ ptr[1] = EIR_FLAGS;
+ ptr[2] = flags;

- ad_len += 3;
- ptr += 3;
+ ad_len += 3;
+ ptr += 3;
+ }
}

+ /* Provide Tx Power only if we can provide a valid value for it */
if (hdev->adv_tx_power != HCI_TX_POWER_INVALID &&
- (hdev->adv_instance.flags & MGMT_ADV_FLAG_TX_POWER)) {
+ (instance_flags & MGMT_ADV_FLAG_TX_POWER)) {
ptr[0] = 0x02;
ptr[1] = EIR_TX_POWER;
ptr[2] = (u8)hdev->adv_tx_power;
@@ -1014,9 +1041,11 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
ptr += 3;
}

- memcpy(ptr, hdev->adv_instance.adv_data,
- hdev->adv_instance.adv_data_len);
- ad_len += hdev->adv_instance.adv_data_len;
+ if (instance) {
+ memcpy(ptr, hdev->adv_instance.adv_data,
+ hdev->adv_instance.adv_data_len);
+ ad_len += hdev->adv_instance.adv_data_len;
+ }

return ad_len;
}
@@ -1032,10 +1061,7 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)

memset(&cp, 0, sizeof(cp));

- if (instance)
- len = create_instance_adv_data(hdev, cp.data);
- else
- len = create_default_adv_data(hdev, cp.data);
+ len = create_instance_adv_data(hdev, instance, cp.data);

/* There's nothing to do if the data hasn't changed */
if (hdev->adv_data_len == len &&
@@ -1050,59 +1076,6 @@ static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}

-static u8 get_current_adv_instance(struct hci_dev *hdev)
-{
- /* The "Set Advertising" setting supersedes the "Add Advertising"
- * setting. Here we set the advertising data based on which
- * setting was set. When neither apply, default to the global settings,
- * represented by instance "0".
- */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
- !hci_dev_test_flag(hdev, HCI_ADVERTISING))
- return 0x01;
-
- return 0x00;
-}
-
-static bool get_connectable(struct hci_dev *hdev)
-{
- struct mgmt_pending_cmd *cmd;
-
- /* If there's a pending mgmt command the flag will not yet have
- * it's final value, so check for this first.
- */
- cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
- if (cmd) {
- struct mgmt_mode *cp = cmd->param;
-
- return cp->val;
- }
-
- return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
-}
-
-static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance)
-{
- u32 flags;
-
- if (instance > 0x01)
- return 0;
-
- if (instance == 1)
- return hdev->adv_instance.flags;
-
- flags = 0;
-
- /* For instance 0, assemble the flags from global settings */
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) ||
- get_connectable(hdev))
- flags |= MGMT_ADV_FLAG_CONNECTABLE;
-
- /* TODO: Add the rest of the flags */
-
- return flags;
-}
-
static void update_adv_data(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
--
2.2.0.rc0.207.ga3a616c


2015-03-26 01:53:45

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 7/8] Bluetooth: Update supported_flags for AD features

This patch updates the "supported_flags" parameter returned from the
"Read Advertising Features" command. Add Advertising will now return
an error if an unsupported flag is provided.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index fd41b20..71d4130 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6540,6 +6540,21 @@ done:
return err;
}

+static u32 get_supported_adv_flags(struct hci_dev *hdev)
+{
+ u32 flags = 0;
+
+ flags |= MGMT_ADV_FLAG_CONNECTABLE;
+ flags |= MGMT_ADV_FLAG_DISCOV;
+ flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
+ flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
+
+ if (hdev->adv_tx_power != HCI_TX_POWER_INVALID)
+ flags |= MGMT_ADV_FLAG_TX_POWER;
+
+ return flags;
+}
+
static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
@@ -6547,9 +6562,14 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
size_t rp_len;
int err;
bool instance;
+ u32 supported_flags;

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

+ if (!lmp_le_capable(hdev))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
+ MGMT_STATUS_REJECTED);
+
hci_dev_lock(hdev);

rp_len = sizeof(*rp);
@@ -6567,7 +6587,9 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
return -ENOMEM;
}

- rp->supported_flags = cpu_to_le32(0);
+ supported_flags = get_supported_adv_flags(hdev);
+
+ rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = 1;
@@ -6689,6 +6711,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
struct mgmt_cp_add_advertising *cp = data;
struct mgmt_rp_add_advertising rp;
u32 flags;
+ u32 supported_flags;
u8 status;
u16 timeout;
int err;
@@ -6705,8 +6728,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
flags = __le32_to_cpu(cp->flags);
timeout = __le16_to_cpu(cp->timeout);

- /* The current implementation only supports adding one instance */
- if (cp->instance != 0x01)
+ /* The current implementation only supports adding one instance and only
+ * a subset of the specified flags.
+ */
+ supported_flags = get_supported_adv_flags(hdev);
+ if (cp->instance != 0x01 || (flags & ~supported_flags))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);

--
2.2.0.rc0.207.ga3a616c


2015-03-26 01:53:42

by Arman Uguray

[permalink] [raw]
Subject: [PATCH v2 4/8] Bluetooth: Support the "limited-discoverable" adv flag

This patch adds support for the "limited-discoverable" flag of the
Add Advertising command.

Signed-off-by: Arman Uguray <[email protected]>
---
net/bluetooth/mgmt.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 03ddcfe..4cb02f3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -977,9 +977,15 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0, flags = 0;

+ /* The Add Advertising command allows userspace to set both the general
+ * and limited discoverable flags.
+ */
if (hdev->adv_instance.flags & MGMT_ADV_FLAG_DISCOV)
flags |= LE_AD_GENERAL;

+ if (hdev->adv_instance.flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
+ flags |= LE_AD_LIMITED;
+
if (flags) {
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
flags |= LE_AD_NO_BREDR;
@@ -6576,8 +6582,9 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
u8 max_len = HCI_MAX_AD_LENGTH;
int i, cur_len;
bool flags_managed = false;
+ u32 flags_params = MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV;

- if (is_adv_data && (adv_flags & MGMT_ADV_FLAG_DISCOV)) {
+ if (is_adv_data && (adv_flags & flags_params)) {
flags_managed = true;
max_len -= 3;
}
--
2.2.0.rc0.207.ga3a616c