This patch enhances the existing code and add support for the
EIR updation for UUID-32 & UUID-128.
Patch 1: changes the order of the parsing inorder to avoid uuid's getting
overwritten in extreem cases. Since we are reversing the order the
mgmt-tester testcase for "UUID-16 multiple 1" will fail. I'll send the
updated fix for the mgmt-tester with UUID128 testcase.
Since I do not have a setup to test these changes using mgmt-tester,
Chen-yeol Park has help me a lot and tested the changes locally and
it is reported working fine. Thanks Johan for the guidence.
Syam Sidhardhan (6):
Bluetooth: Update the uuid list in reverse order
Bluetooth: Add helper function to get the uuid type
Bluetooth: Add helper function to prepare the EIR packet from list
Bluetooth: Add EIR UUID-16 bit parsing for EIR
Bluetooth: Add support for UUID-32 bit parsing for EIR
Bluetooth: Add support for UUID-128 bit parsing for EIR
net/bluetooth/mgmt.c | 352 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 314 insertions(+), 38 deletions(-)
--
1.7.9.5
This patch add the support for UUID 32-bit parsing for EIR.
Signed-off-by: Syam Sidhardhan <[email protected]>
Tested-by: Chan-yeol Park <[email protected]>
---
net/bluetooth/mgmt.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 446e4d3..e1fbf95 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -483,6 +483,18 @@ static u16 get_uuid16(u8 *uuid128)
return (u16) val;
}
+static u32 get_uuid32(u8 *uuid128)
+{
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (bluetooth_base_uuid[i] != uuid128[i])
+ return 0;
+ }
+
+ return get_unaligned_le32(&uuid128[12]);
+}
+
static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool updated_128, u16 eir_len, bool *truncated)
{
int i;
@@ -533,6 +545,47 @@ static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool up
return eir_len;
}
+static u16 update_eir_uuid32_list(u8 *list32, u8 *uuid, bool updated_16, bool updated_128, u16 eir_len, bool *truncated)
+{
+ int i;
+ u32 uuid32;
+ u32 *uuid32_list = (u32 *) list32;
+
+ /* Group all UUID32 types */
+ uuid32 = get_uuid32(uuid);
+
+ /* Stop if not enough space to put next UUID32 */
+ if (eir_len + 2 + sizeof(u32) > HCI_MAX_EIR_LENGTH) {
+ *truncated = true;
+ return 1;
+ }
+
+ /* Check for duplicates */
+ for (i = 0; uuid32_list[i] != 0; i++)
+ if (uuid32_list[i] == uuid32)
+ break;
+
+ if (uuid32_list[i] == 0) {
+
+ /* if any other uuid types has been already added into the
+ * corresponding list, then consider it's header length(2 bytes)
+ * in eir_len calculation.
+ */
+ if (uuid32_list[0] == 0) {
+ if (updated_16)
+ eir_len += 2;
+
+ if (updated_128 == true)
+ eir_len += 2;
+ }
+
+ uuid32_list[i] = uuid32;
+ eir_len += sizeof(u32);
+ }
+
+ return eir_len;
+}
+
static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
{
int i;
@@ -615,7 +668,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
struct bt_uuid *uuid;
size_t name_len;
- bool truncated_16 = false;
+ bool truncated_16 = false, truncated_32 = false;
bool updated_128 = false;
name_len = strlen(hdev->dev_name);
@@ -682,6 +735,17 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
break;
eir_len = ret;
+ } else if (uuid_type == EIR_TYPE_UUID32) {
+ ret = update_eir_uuid32_list((u8 *) uuid32_list,
+ uuid->uuid,
+ uuid16_list[0] ? 1 : 0,
+ updated_128, eir_len,
+ &truncated_32);
+ /* Truncated */
+ if (ret == 1)
+ break;
+
+ eir_len = ret;
}
} /* list_for_each_entry end */
@@ -690,6 +754,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
EIR_TYPE_UUID16, truncated_16);
eir_len += 2;
}
+
+ if (uuid32_list[0]) {
+ ptr = prepare_eir_from_list((u8 *) uuid32_list, ptr,
+ EIR_TYPE_UUID32, truncated_32);
+ eir_len += 2;
+ }
}
static int update_eir(struct hci_dev *hdev)
--
1.7.9.5
Here we are enhancing the existing code to support 16bit UUID's along
with other types. Also it fixes one issue related to EIR 16 bit UUID
updation. Earlier UUID 16bit updation fails further when any other
non 16 bit UUID types are trying to get registed.
Signed-off-by: Syam Sidhardhan <[email protected]>
Tested-by: Chan-yeol Park <[email protected]>
---
net/bluetooth/mgmt.c | 117 ++++++++++++++++++++++++++++++++------------------
1 file changed, 75 insertions(+), 42 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d2569f8..446e4d3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -483,6 +483,56 @@ static u16 get_uuid16(u8 *uuid128)
return (u16) val;
}
+static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool updated_128, u16 eir_len, bool *truncated)
+{
+ int i;
+ u16 uuid16;
+ u16 *uuid16_list = (u16 *) list16;
+
+ /* Group all UUID16 types */
+ uuid16 = get_uuid16(uuid);
+ if (uuid16 == 0)
+ return 0;
+
+ if (uuid16 < 0x1100)
+ return 0;
+
+ if (uuid16 == PNP_INFO_SVCLASS_ID)
+ return 0;
+
+ /* Stop if not enough space to put next UUID16 */
+ if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
+ *truncated = true;
+ return 1;
+ }
+
+ /* Check for duplicates */
+ for (i = 0; uuid16_list[i] != 0; i++)
+ if (uuid16_list[i] == uuid16)
+ return 0;
+
+ if (uuid16_list[i] == 0) {
+
+ /* if any other uuid types has been already added into the
+ * corresponding list, then consider it's header length(2 bytes)
+ * in eir_len calculation.
+ */
+ if (uuid16_list[0] == 0) {
+
+ if (updated_32)
+ eir_len += 2;
+
+ if (updated_128 == true)
+ eir_len += 2;
+ }
+
+ uuid16_list[i] = uuid16;
+ eir_len += sizeof(u16);
+ }
+
+ return eir_len;
+}
+
static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
{
int i;
@@ -562,9 +612,11 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u8 *ptr = data;
u16 eir_len = 0;
u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
- int i, truncated = 0;
+ u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
struct bt_uuid *uuid;
size_t name_len;
+ bool truncated_16 = false;
+ bool updated_128 = false;
name_len = strlen(hdev->dev_name);
@@ -608,54 +660,35 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
}
memset(uuid16_list, 0, sizeof(uuid16_list));
+ memset(uuid32_list, 0, sizeof(uuid32_list));
- /* Group all UUID16 types */
list_for_each_entry(uuid, &hdev->uuids, list) {
- u16 uuid16;
-
- uuid16 = get_uuid16(uuid->uuid);
- if (uuid16 == 0)
- return;
-
- if (uuid16 < 0x1100)
- continue;
-
- if (uuid16 == PNP_INFO_SVCLASS_ID)
- continue;
-
- /* Stop if not enough space to put next UUID */
- if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
- truncated = 1;
- break;
- }
-
- /* Check for duplicates */
- for (i = 0; uuid16_list[i] != 0; i++)
- if (uuid16_list[i] == uuid16)
+ u16 uuid_type;
+ u16 ret;
+
+ uuid_type = get_uuid_type(uuid->uuid);
+
+ if (uuid_type == EIR_TYPE_UUID16) {
+ ret = update_eir_uuid16_list((u8 *) uuid16_list,
+ uuid->uuid,
+ uuid32_list[0] ? 1 : 0,
+ updated_128, eir_len,
+ &truncated_16);
+ if (ret == 0)
+ continue;
+
+ /* Truncated */
+ if (ret == 1)
break;
- if (uuid16_list[i] == 0) {
- uuid16_list[i] = uuid16;
- eir_len += sizeof(u16);
+ eir_len = ret;
}
- }
+ } /* list_for_each_entry end */
- if (uuid16_list[0] != 0) {
- u8 *length = ptr;
-
- /* EIR Data type */
- ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
-
- ptr += 2;
+ if (uuid16_list[0]) {
+ ptr = prepare_eir_from_list((u8 *) uuid16_list, ptr,
+ EIR_TYPE_UUID16, truncated_16);
eir_len += 2;
-
- for (i = 0; uuid16_list[i] != 0; i++) {
- *ptr++ = (uuid16_list[i] & 0x00ff);
- *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
- }
-
- /* EIR Data length */
- *length = (i * sizeof(u16)) + 1;
}
}
--
1.7.9.5
This patch add the support for UUID-128 bit parsing for the EIR.
Signed-off-by: Syam Sidhardhan <[email protected]>
Tested-by: Chan-yeol Park <[email protected]>
---
net/bluetooth/mgmt.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e1fbf95..52cce2f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -586,6 +586,52 @@ static u16 update_eir_uuid32_list(u8 *list32, u8 *uuid, bool updated_16, bool up
return eir_len;
}
+static u16 update_eir_uuid128_list(u8 *list128, u8 *uuid, bool updated_16, bool updated_32, u16 eir_len, bool *truncated)
+{
+ int i;
+ u128 *uuid128_list = (u128 *) list128;
+ u128 u;
+
+ memset(u.data, 0, sizeof(u128));
+
+ /* Stop if not enough space to put next UUID128 */
+ if (eir_len + 2 + sizeof(u128) > HCI_MAX_EIR_LENGTH) {
+ *truncated = true;
+ return 1;
+ }
+
+ i = 0;
+
+ /* Comparing uuid128_list[i] with 0*/
+ while (memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+ if (!memcmp(uuid128_list[i].data, uuid, sizeof(u128)))
+ break;
+
+ ++i;
+ }
+
+ if (!memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+
+ /* if any other uuid types has been already added into the
+ * corresponding list, then consider it's header length(2 bytes)
+ * in eir_len calculation.
+ */
+ if (!memcmp(uuid128_list[0].data, u.data, sizeof(u128))) {
+ if (updated_16)
+ eir_len += 2;
+
+ if (updated_32)
+ eir_len += 2;
+
+ }
+
+ memcpy(uuid128_list[i].data, uuid, sizeof(u128));
+ eir_len += sizeof(u128);
+ }
+
+ return eir_len;
+}
+
static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
{
int i;
@@ -666,10 +712,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u16 eir_len = 0;
u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
+ u128 uuid128_list[HCI_MAX_EIR_LENGTH / sizeof(u128)];
struct bt_uuid *uuid;
size_t name_len;
- bool truncated_16 = false, truncated_32 = false;
+ bool truncated_16 = false, truncated_32 = false, truncated_128 = false;
bool updated_128 = false;
+ u128 u;
name_len = strlen(hdev->dev_name);
@@ -714,6 +762,8 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
memset(uuid16_list, 0, sizeof(uuid16_list));
memset(uuid32_list, 0, sizeof(uuid32_list));
+ memset(uuid128_list, 0, sizeof(uuid128_list));
+ memset(u.data, 0, sizeof(u128));
list_for_each_entry(uuid, &hdev->uuids, list) {
u16 uuid_type;
@@ -746,6 +796,23 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
break;
eir_len = ret;
+ } else {
+ ret = update_eir_uuid128_list((u8 *) uuid128_list,
+ uuid->uuid,
+ uuid16_list[0] ? 1 : 0,
+ uuid32_list[0] ? 1 : 0,
+ eir_len,
+ &truncated_128);
+ /* Truncated */
+ if (ret == 1)
+ break;
+
+ /* In other cases we will directly check uuid*_list[0].
+ * Here we use a flag updated_128 to avoid memcmp().
+ */
+ updated_128 = true;
+
+ eir_len = ret;
}
} /* list_for_each_entry end */
@@ -760,6 +827,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
EIR_TYPE_UUID32, truncated_32);
eir_len += 2;
}
+
+ if (memcmp(uuid128_list[0].data, u.data, sizeof(u128)) != 0) {
+ ptr = prepare_eir_from_list((u8 *) uuid128_list, ptr,
+ EIR_TYPE_UUID128, truncated_128);
+ eir_len += 2;
+ }
}
static int update_eir(struct hci_dev *hdev)
--
1.7.9.5
This function is used to prepare the final eir data from the
various list. It returns the updated pointer to the buffer.
Signed-off-by: Syam Sidhardhan <[email protected]>
Tested-by: Chan-yeol Park <[email protected]>
---
net/bluetooth/mgmt.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0f32986..d2569f8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -41,6 +41,11 @@ bool enable_hs;
#define EIR_TYPE_UUID32 2
#define EIR_TYPE_UUID128 3
+/* UUID128 type */
+typedef struct {
+ u8 data[16];
+} u128;
+
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
MGMT_OP_READ_INFO,
@@ -478,6 +483,80 @@ static u16 get_uuid16(u8 *uuid128)
return (u16) val;
}
+static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
+{
+ int i;
+ if (type == EIR_TYPE_UUID16) {
+ u8 *length = ptr;
+ u16 *uuid16_list = (u16 *) list;
+
+ /* EIR Data type */
+ ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
+
+ ptr += 2;
+ for (i = 0; uuid16_list[i] != 0; i++) {
+ *ptr++ = (uuid16_list[i] & 0x00ff);
+ *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
+ }
+
+ /* EIR Data length */
+ *length = (i * sizeof(u16)) + 1;
+ return ptr;
+ }
+
+ if (type == EIR_TYPE_UUID32) {
+ u8 *length = ptr;
+ u32 *uuid32_list = (u32 *) list;
+
+ /* EIR Data type */
+ ptr[1] = truncated ? EIR_UUID32_SOME : EIR_UUID32_ALL;
+
+ ptr += 2;
+
+ for (i = 0; uuid32_list[i] != 0; i++) {
+ *ptr++ = (uuid32_list[i] & 0x000000ff);
+ *ptr++ = (uuid32_list[i] & 0x0000ff00) >> 8;
+ *ptr++ = (uuid32_list[i] & 0x00ff0000) >> 16;
+ *ptr++ = (uuid32_list[i] & 0xff000000) >> 24;
+ }
+
+ /* EIR Data length */
+ *length = (i * sizeof(u32)) + 1;
+
+ return ptr;
+ }
+
+ if (type == EIR_TYPE_UUID128) {
+
+ u8 *length = ptr;
+ u128 *uuid128_list = (u128 *) list;
+ u128 u;
+
+ memset(u.data, 0, sizeof(u128));
+ /* EIR Data type */
+ ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
+
+ ptr += 2;
+
+ i = 0;
+ while (memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+
+ memcpy(ptr, uuid128_list[i].data, sizeof(u128));
+
+ ptr += sizeof(u128);
+ i++;
+ }
+
+ /* EIR Data length */
+ *length = (i * sizeof(u128)) + 1;
+
+ return ptr;
+
+ }
+
+ return ptr;
+}
+
static void create_eir(struct hci_dev *hdev, u8 *data)
{
u8 *ptr = data;
--
1.7.9.5
This function will return the particular uuid type
Signed-off-by: Syam Sidhardhan <[email protected]>
Tested-by: Chan-yeol Park <[email protected]>
---
net/bluetooth/mgmt.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4fd45a3..0f32986 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -37,6 +37,10 @@ bool enable_hs;
#define MGMT_VERSION 1
#define MGMT_REVISION 2
+#define EIR_TYPE_UUID16 1
+#define EIR_TYPE_UUID32 2
+#define EIR_TYPE_UUID128 3
+
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
MGMT_OP_READ_INFO,
@@ -440,6 +444,23 @@ static u8 bluetooth_base_uuid[] = {
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
+static int get_uuid_type(u8 *uuid128)
+{
+ u32 val;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (bluetooth_base_uuid[i] != uuid128[i])
+ return EIR_TYPE_UUID128;
+ }
+
+ val = get_unaligned_le32(&uuid128[12]);
+ if (val > 0xffff)
+ return EIR_TYPE_UUID32;
+ else
+ return EIR_TYPE_UUID16;
+}
+
static u16 get_uuid16(u8 *uuid128)
{
u32 val;
--
1.7.9.5
If we add uuid in the list head, then initially added uuid's might
get lost because of the possibility of Max limit 240 reaches before
reaching the end of the list parsing.
Signed-off-by: Syam Sidhardhan <[email protected]>
Tested-by: Chan-yeol Park <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e7f944f..4fd45a3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1330,7 +1330,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
memcpy(uuid->uuid, cp->uuid, 16);
uuid->svc_hint = cp->svc_hint;
- list_add(&uuid->list, &hdev->uuids);
+ list_add_tail(&uuid->list, &hdev->uuids);
err = update_class(hdev);
if (err < 0)
--
1.7.9.5