From de66aa63054a6fe348869722221d5cd3463d74a0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:27 +0200 Subject: Bluetooth: Store UUIDs in the same order that they were added We should be encoding UUIDs to the EIR data in the same order that they were added to the kernel, i.e. each UUID should be added to the end of the UUIDs list. This patch fixes the issue by using list_add_tail instead of list_add for storing the UUIDs. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- 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 e7f944f52ff2..4fd45a3271e0 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) -- cgit v1.2.3 From 4821002ce2baa130666c2d777e0ed30bee6c7702 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:28 +0200 Subject: Bluetooth: Simplify UUIDs clearing code The code for clearing the UUIDs list can be simplified by using list_for_each_entry_safe instead of list_for_each_safe. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d13ce99b410a..22e77a786545 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1183,14 +1183,10 @@ static void hci_discov_off(struct work_struct *work) int hci_uuids_clear(struct hci_dev *hdev) { - struct list_head *p, *n; - - list_for_each_safe(p, n, &hdev->uuids) { - struct bt_uuid *uuid; + struct bt_uuid *uuid, *tmp; - uuid = list_entry(p, struct bt_uuid, list); - - list_del(p); + list_for_each_entry_safe(uuid, tmp, &hdev->uuids, list) { + list_del(&uuid->list); kfree(uuid); } -- cgit v1.2.3 From 83be8eca2e67faaec45280224b798828bbfa69aa Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:29 +0200 Subject: Bluetooth: Keep track of UUID type upon addition The primary purpose of the UUIDs is to enable generation of EIR and AD data. In these data formats the UUIDs are split into separate fields based on whether they're 16, 32 or 128 bit UUIDs. To make the generation of these data fields simpler this patch adds a type member to the bt_uuid struct and assigns a value to it as soon as the UUID is added to the kernel. This way the type doesn't need to be calculated each time the UUID list is later iterated. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 48 +++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bcf8ffe2a843..90cf75afcb02 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -86,6 +86,7 @@ struct bdaddr_list { struct bt_uuid { struct list_head list; u8 uuid[16]; + u8 size; u8 svc_hint; }; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4fd45a3271e0..8de6d576dc70 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -435,28 +435,6 @@ static u32 get_current_settings(struct hci_dev *hdev) #define PNP_INFO_SVCLASS_ID 0x1200 -static u8 bluetooth_base_uuid[] = { - 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static u16 get_uuid16(u8 *uuid128) -{ - u32 val; - int i; - - for (i = 0; i < 12; i++) { - if (bluetooth_base_uuid[i] != uuid128[i]) - return 0; - } - - val = get_unaligned_le32(&uuid128[12]); - if (val > 0xffff) - return 0; - - return (u16) val; -} - static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -513,10 +491,10 @@ static void create_eir(struct hci_dev *hdev, u8 *data) list_for_each_entry(uuid, &hdev->uuids, list) { u16 uuid16; - uuid16 = get_uuid16(uuid->uuid); - if (uuid16 == 0) - return; + if (uuid->size != 16) + continue; + uuid16 = get_unaligned_le16(&uuid->uuid[12]); if (uuid16 < 0x1100) continue; @@ -1304,6 +1282,25 @@ unlock: return err; } +static const u8 bluetooth_base_uuid[] = { + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u8 get_uuid_size(const u8 *uuid) +{ + u32 val; + + if (memcmp(uuid, bluetooth_base_uuid, 12)) + return 128; + + val = get_unaligned_le32(&uuid[12]); + if (val > 0xffff) + return 32; + + return 16; +} + static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -1329,6 +1326,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; + uuid->size = get_uuid_size(cp->uuid); list_add_tail(&uuid->list, &hdev->uuids); -- cgit v1.2.3 From 056341c8cb677356eb2c20a82e788ccb51c6a37b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:30 +0200 Subject: Bluetooth: Simplify UUID removal code The UUID removal code can be simplified by using list_for_each_entry_safe instead of list_for_each_safe. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8de6d576dc70..1e906d8d86ac 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1372,7 +1372,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_remove_uuid *cp = data; struct pending_cmd *cmd; - struct list_head *p, *n; + struct bt_uuid *match, *tmp; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int err, found; @@ -1400,9 +1400,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, found = 0; - list_for_each_safe(p, n, &hdev->uuids) { - struct bt_uuid *match = list_entry(p, struct bt_uuid, list); - + list_for_each_entry_safe(match, tmp, &hdev->uuids, list) { if (memcmp(match->uuid, cp->uuid, 16) != 0) continue; -- cgit v1.2.3 From a10f27cf4272033d148d91ff12bb8f4b67dfaca4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:31 +0200 Subject: Bluetooth: Simplify UUID16 list generation for EIR There's no need to use two separate loops to generate a UUID list for the EIR data. This patch merges the two loops previously used for the 16-bit UUID list generation into a single loop, thus simplifying the code a great deal. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1e906d8d86ac..02827af1aef0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -438,9 +438,8 @@ static u32 get_current_settings(struct hci_dev *hdev) static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; + u8 *uuids_start; u16 eir_len = 0; - u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; - int i, truncated = 0; struct bt_uuid *uuid; size_t name_len; @@ -485,7 +484,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += 10; } - memset(uuid16_list, 0, sizeof(uuid16_list)); + uuids_start = NULL; /* Group all UUID16 types */ list_for_each_entry(uuid, &hdev->uuids, list) { @@ -501,39 +500,24 @@ static void create_eir(struct hci_dev *hdev, u8 *data) if (uuid16 == PNP_INFO_SVCLASS_ID) continue; + if (!uuids_start) { + uuids_start = ptr; + uuids_start[0] = 1; + uuids_start[1] = EIR_UUID16_ALL; + ptr += 2; + eir_len += 2; + } + /* Stop if not enough space to put next UUID */ if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { - truncated = 1; + uuids_start[1] = EIR_UUID16_SOME; break; } - /* Check for duplicates */ - for (i = 0; uuid16_list[i] != 0; i++) - if (uuid16_list[i] == uuid16) - break; - - if (uuid16_list[i] == 0) { - uuid16_list[i] = uuid16; - eir_len += sizeof(u16); - } - } - - if (uuid16_list[0] != 0) { - u8 *length = ptr; - - /* EIR Data type */ - ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; - - ptr += 2; - 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; + *ptr++ = (uuid16 & 0x00ff); + *ptr++ = (uuid16 & 0xff00) >> 8; + eir_len += sizeof(uuid16); + uuids_start[0] += sizeof(uuid16); } } -- cgit v1.2.3 From 892bbc5794daac57bff09c584821ed271fa18046 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:32 +0200 Subject: Bluetooth: Remove useless eir_len variable from EIR creation The amount of data encoded so far in the create_eir() function can be calculated simply through the difference between the data and ptr pointer variables. The eir_len variable then becomes essentially useless. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 02827af1aef0..5e18d5a451f4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -439,7 +439,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; u8 *uuids_start; - u16 eir_len = 0; struct bt_uuid *uuid; size_t name_len; @@ -458,7 +457,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data) memcpy(ptr + 2, hdev->dev_name, name_len); - eir_len += (name_len + 2); ptr += (name_len + 2); } @@ -467,7 +465,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr[1] = EIR_TX_POWER; ptr[2] = (u8) hdev->inq_tx_power; - eir_len += 3; ptr += 3; } @@ -480,7 +477,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data) put_unaligned_le16(hdev->devid_product, ptr + 6); put_unaligned_le16(hdev->devid_version, ptr + 8); - eir_len += 10; ptr += 10; } @@ -505,18 +501,16 @@ static void create_eir(struct hci_dev *hdev, u8 *data) uuids_start[0] = 1; uuids_start[1] = EIR_UUID16_ALL; ptr += 2; - eir_len += 2; } /* Stop if not enough space to put next UUID */ - if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { + if ((ptr - data) + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { uuids_start[1] = EIR_UUID16_SOME; break; } *ptr++ = (uuid16 & 0x00ff); *ptr++ = (uuid16 & 0xff00) >> 8; - eir_len += sizeof(uuid16); uuids_start[0] += sizeof(uuid16); } } -- cgit v1.2.3 From 213202edc9b5ae60eef2a915b83b4aa19b1c3617 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:33 +0200 Subject: Bluetooth: Refactor UUID-16 list generation into its own function We will need to create three separate UUID lists in the EIR data (for 16, 32 and 128 bit UUIDs) so the code is easier to follow if each list is generated in their own function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 78 +++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5e18d5a451f4..497928d2b257 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -435,11 +435,51 @@ static u32 get_current_settings(struct hci_dev *hdev) #define PNP_INFO_SVCLASS_ID 0x1200 +static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) +{ + u8 *ptr = data, *uuids_start = NULL; + struct bt_uuid *uuid; + + if (len < 4) + return ptr; + + list_for_each_entry(uuid, &hdev->uuids, list) { + u16 uuid16; + + if (uuid->size != 16) + continue; + + uuid16 = get_unaligned_le16(&uuid->uuid[12]); + if (uuid16 < 0x1100) + continue; + + if (uuid16 == PNP_INFO_SVCLASS_ID) + continue; + + if (!uuids_start) { + uuids_start = ptr; + uuids_start[0] = 1; + uuids_start[1] = EIR_UUID16_ALL; + ptr += 2; + } + + /* Stop if not enough space to put next UUID */ + if ((ptr - data) + sizeof(u16) > len) { + uuids_start[1] = EIR_UUID16_SOME; + break; + } + + *ptr++ = (uuid16 & 0x00ff); + *ptr++ = (uuid16 & 0xff00) >> 8; + uuids_start[0] += sizeof(uuid16); + } + + return ptr; +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; - u8 *uuids_start; - struct bt_uuid *uuid; size_t name_len; name_len = strlen(hdev->dev_name); @@ -480,39 +520,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += 10; } - uuids_start = NULL; - - /* Group all UUID16 types */ - list_for_each_entry(uuid, &hdev->uuids, list) { - u16 uuid16; - - if (uuid->size != 16) - continue; - - uuid16 = get_unaligned_le16(&uuid->uuid[12]); - if (uuid16 < 0x1100) - continue; - - if (uuid16 == PNP_INFO_SVCLASS_ID) - continue; - - if (!uuids_start) { - uuids_start = ptr; - uuids_start[0] = 1; - uuids_start[1] = EIR_UUID16_ALL; - ptr += 2; - } - - /* Stop if not enough space to put next UUID */ - if ((ptr - data) + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { - uuids_start[1] = EIR_UUID16_SOME; - break; - } - - *ptr++ = (uuid16 & 0x00ff); - *ptr++ = (uuid16 & 0xff00) >> 8; - uuids_start[0] += sizeof(uuid16); - } + ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); } static int update_eir(struct hci_dev *hdev) -- cgit v1.2.3 From cdf1963f7ba075772b4b5f91f395ed8fb84d0e70 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:34 +0200 Subject: Bluetooth: Add support for 32-bit UUIDs in EIR data This patch adds the necessary code for inserting a list of 32-bit UUIDs into the EIR data. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 497928d2b257..0110a75661ef 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -477,6 +477,39 @@ static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) return ptr; } +static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) +{ + u8 *ptr = data, *uuids_start = NULL; + struct bt_uuid *uuid; + + if (len < 6) + return ptr; + + list_for_each_entry(uuid, &hdev->uuids, list) { + if (uuid->size != 32) + continue; + + if (!uuids_start) { + uuids_start = ptr; + uuids_start[0] = 1; + uuids_start[1] = EIR_UUID32_ALL; + ptr += 2; + } + + /* Stop if not enough space to put next UUID */ + if ((ptr - data) + sizeof(u32) > len) { + uuids_start[1] = EIR_UUID32_SOME; + break; + } + + memcpy(ptr, &uuid->uuid[12], sizeof(u32)); + ptr += sizeof(u32); + uuids_start[0] += sizeof(u32); + } + + return ptr; +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -521,6 +554,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) } ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); + ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); } static int update_eir(struct hci_dev *hdev) -- cgit v1.2.3 From c00d575bd550d3d57aeec2522defa0cea589560c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 00:31:35 +0200 Subject: Bluetooth: Add support for 128-bit UUIDs in EIR data This patch adds the necessary code for encoding a list of 128-bit UUIDs into the EIR data. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0110a75661ef..fbc8edf7dc1f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -510,6 +510,39 @@ static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) return ptr; } +static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) +{ + u8 *ptr = data, *uuids_start = NULL; + struct bt_uuid *uuid; + + if (len < 18) + return ptr; + + list_for_each_entry(uuid, &hdev->uuids, list) { + if (uuid->size != 128) + continue; + + if (!uuids_start) { + uuids_start = ptr; + uuids_start[0] = 1; + uuids_start[1] = EIR_UUID128_ALL; + ptr += 2; + } + + /* Stop if not enough space to put next UUID */ + if ((ptr - data) + 16 > len) { + uuids_start[1] = EIR_UUID128_SOME; + break; + } + + memcpy(ptr, uuid->uuid, 16); + ptr += 16; + uuids_start[0] += 16; + } + + return ptr; +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -555,6 +588,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); + ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); } static int update_eir(struct hci_dev *hdev) -- cgit v1.2.3 From f0ff92fbfa14c1cf8c0346f1dde9c3eda26d5abf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 08:32:00 -0600 Subject: Bluetooth: Fix link security setting when powering on If a controller is powered on while the HCI_AUTO_OFF flag is set the link security setting (HCI_LINK_SECURITY) might not be in sync with the actual state of the controller (HCI_AUTH). This patch fixes the issue by checking for inequality between the intended and actual settings and sends a HCI_Write_Auth_Enable command if necessary. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fbc8edf7dc1f..ae7585de9c08 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3073,6 +3073,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); if (powered) { + u8 link_sec; + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && !lmp_host_ssp_capable(hdev)) { u8 ssp = 1; @@ -3096,6 +3098,11 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) sizeof(cp), &cp); } + link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags); + if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) + hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, + sizeof(link_sec), &link_sec); + if (lmp_bredr_capable(hdev)) { set_bredr_scan(hdev); update_class(hdev); -- cgit v1.2.3 From 3810285cf8cef5c3f9c4334a317b71b876125269 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 27 Jan 2013 08:32:01 -0600 Subject: Bluetooth: Increment Management interface revision This patch increments the management interface revision due to the various fixes, improvements and other changes that have gone in lately. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- 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 ae7585de9c08..3bd4c41c6a1b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,7 +35,7 @@ bool enable_hs; #define MGMT_VERSION 1 -#define MGMT_REVISION 2 +#define MGMT_REVISION 3 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, -- cgit v1.2.3 From 405280887f8fb4e168a1bbc865917bb2b881db95 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 29 Jan 2013 19:59:56 -0300 Subject: Bluetooth: Reduce critical section in sco_conn_ready This patch reduces the critical section protected by sco_conn_lock in sco_conn_ready function. The lock is acquired only when it is really needed. This patch fixes the following lockdep warning which is generated when the host terminates a SCO connection. Today, this warning is a false positive. There is no way those two threads reported by lockdep are running at the same time since hdev->workqueue (where rx_work is queued) is single-thread. However, if somehow this behavior is changed in future, we will have a potential deadlock. ====================================================== [ INFO: possible circular locking dependency detected ] 3.8.0-rc1+ #7 Not tainted ------------------------------------------------------- kworker/u:1H/1018 is trying to acquire lock: (&(&conn->lock)->rlock){+.+...}, at: [] sco_chan_del+0x66/0x190 [bluetooth] but task is already holding lock: (slock-AF_BLUETOOTH-BTPROTO_SCO){+.+...}, at: [] sco_conn_del+0x8a/0xe0 [bluetooth] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (slock-AF_BLUETOOTH-BTPROTO_SCO){+.+...}: [] lock_acquire+0xb1/0xe0 [] _raw_spin_lock+0x41/0x80 [] sco_connect_cfm+0xbe/0x350 [bluetooth] [] hci_event_packet+0xd3c/0x29b0 [bluetooth] [] hci_rx_work+0x133/0x870 [bluetooth] [] process_one_work+0x2bf/0x4f0 [] worker_thread+0x2b2/0x3e0 [] kthread+0xd1/0xe0 [] ret_from_fork+0x7c/0xb0 -> #0 (&(&conn->lock)->rlock){+.+...}: [] __lock_acquire+0x1465/0x1c70 [] lock_acquire+0xb1/0xe0 [] _raw_spin_lock+0x41/0x80 [] sco_chan_del+0x66/0x190 [bluetooth] [] sco_conn_del+0x9d/0xe0 [bluetooth] [] sco_disconn_cfm+0x53/0x60 [bluetooth] [] hci_disconn_complete_evt.isra.54+0x363/0x3c0 [bluetooth] [] hci_event_packet+0xc7/0x29b0 [bluetooth] [] hci_rx_work+0x133/0x870 [bluetooth] [] process_one_work+0x2bf/0x4f0 [] worker_thread+0x2b2/0x3e0 [] kthread+0xd1/0xe0 [] ret_from_fork+0x7c/0xb0 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(slock-AF_BLUETOOTH-BTPROTO_SCO); lock(&(&conn->lock)->rlock); lock(slock-AF_BLUETOOTH-BTPROTO_SCO); lock(&(&conn->lock)->rlock); *** DEADLOCK *** 4 locks held by kworker/u:1H/1018: #0: (hdev->name#2){.+.+.+}, at: [] process_one_work+0x258/0x4f0 #1: ((&hdev->rx_work)){+.+.+.}, at: [] process_one_work+0x258/0x4f0 #2: (&hdev->lock){+.+.+.}, at: [] hci_disconn_complete_evt.isra.54+0x59/0x3c0 [bluetooth] #3: (slock-AF_BLUETOOTH-BTPROTO_SCO){+.+...}, at: [] sco_conn_del+0x8a/0xe0 [bluetooth] stack backtrace: Pid: 1018, comm: kworker/u:1H Not tainted 3.8.0-rc1+ #7 Call Trace: [] print_circular_bug+0x1fb/0x20c [] __lock_acquire+0x1465/0x1c70 [] lock_acquire+0xb1/0xe0 [] ? sco_chan_del+0x66/0x190 [bluetooth] [] _raw_spin_lock+0x41/0x80 [] ? sco_chan_del+0x66/0x190 [bluetooth] [] sco_chan_del+0x66/0x190 [bluetooth] [] sco_conn_del+0x9d/0xe0 [bluetooth] [] sco_disconn_cfm+0x53/0x60 [bluetooth] [] hci_disconn_complete_evt.isra.54+0x363/0x3c0 [bluetooth] [] ? hci_disconn_complete_evt.isra.54+0x40/0x3c0 [bluetooth] [] hci_event_packet+0xc7/0x29b0 [bluetooth] [] ? __dynamic_pr_debug+0x80/0x90 [] ? kfree_skb+0x2d/0x40 [] ? hci_send_to_monitor+0x1a4/0x1c0 [bluetooth] [] hci_rx_work+0x133/0x870 [bluetooth] [] ? process_one_work+0x258/0x4f0 [] process_one_work+0x2bf/0x4f0 [] ? process_one_work+0x258/0x4f0 [] ? worker_thread+0x51/0x3e0 [] ? hci_tx_work+0x800/0x800 [bluetooth] [] worker_thread+0x2b2/0x3e0 [] ? busy_worker_rebind_fn+0x100/0x100 [] kthread+0xd1/0xe0 [] ? flush_kthread_worker+0xc0/0xc0 [] ret_from_fork+0x7c/0xb0 [] ? flush_kthread_worker+0xc0/0xc0 Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 57f250c20e39..b5178d62064e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -900,8 +900,6 @@ static void sco_conn_ready(struct sco_conn *conn) BT_DBG("conn %p", conn); - sco_conn_lock(conn); - if (sk) { sco_sock_clear_timer(sk); bh_lock_sock(sk); @@ -909,9 +907,13 @@ static void sco_conn_ready(struct sco_conn *conn) sk->sk_state_change(sk); bh_unlock_sock(sk); } else { + sco_conn_lock(conn); + parent = sco_get_sock_listen(conn->src); - if (!parent) - goto done; + if (!parent) { + sco_conn_unlock(conn); + return; + } bh_lock_sock(parent); @@ -919,7 +921,8 @@ static void sco_conn_ready(struct sco_conn *conn) BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); - goto done; + sco_conn_unlock(conn); + return; } sco_sock_init(sk, parent); @@ -939,10 +942,9 @@ static void sco_conn_ready(struct sco_conn *conn) parent->sk_data_ready(parent, 1); bh_unlock_sock(parent); - } -done: - sco_conn_unlock(conn); + sco_conn_unlock(conn); + } } /* ----- SCO interface with lower layer (HCI) ----- */ -- cgit v1.2.3 From 2b8a9a2e6a2143928819f2fb948d3904746e1582 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 31 Jan 2013 20:12:10 -0300 Subject: Bluetooth: Remove unneeded locking This patch removes unneeded locking in hci_le_adv_report_evt. There is no need to lock hdev before calling mgmt_device_found. Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_event.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0a4fd642d4b9..477726a63512 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3988,8 +3988,6 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) void *ptr = &skb->data[1]; s8 rssi; - hci_dev_lock(hdev); - while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; @@ -3999,8 +3997,6 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) ptr += sizeof(*ev) + ev->length + 1; } - - hci_dev_unlock(hdev); } static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From a3d09356491d637548dbe815ddb966f52ec9e53a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 1 Feb 2013 11:21:30 -0300 Subject: Bluetooth: Refactor mgmt_pending_foreach This patch does a trivial refactor in mgmt_pending_foreach function. It replaces list_for_each_safe by list_for_each_entry_safe, simplifying the function. Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3bd4c41c6a1b..39395c7144aa 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -760,13 +760,9 @@ static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, void *data), void *data) { - struct list_head *p, *n; - - list_for_each_safe(p, n, &hdev->mgmt_pending) { - struct pending_cmd *cmd; - - cmd = list_entry(p, struct pending_cmd, list); + struct pending_cmd *cmd, *tmp; + list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { if (opcode > 0 && cmd->opcode != opcode) continue; -- cgit v1.2.3