2011-03-04 20:35:07

by Andre Guedes

[permalink] [raw]
Subject: [RFC 0/6] LE advertising cache

During a LE connection establishment, the host should be able to infer the
bdaddr type from a given bdaddr.

To achieve that, during the LE scanning, the host stores the bdaddr and the
bdaddr type gathered from advertising reports. The host keeps a list of
advertising entry (bdaddr and bdaddr_type) for later lookup. This list will
be called Advertising Cache.

Since the penality to connect to an unreachable device is relatively high,
we must keep only fresh advertising entries on the advertising cache. So,
before each LE scanning the advertising cache is cleared. Also, after the LE
scanning, a timer is set to clear the cache.

Next steps include removing all advertising cache from userspace and
implementing a mechanism to sync kernel and userspace advertising cache.

Patches are rebased using Vinicius SMP patches, repo:
git://git.infradead.org/users/vcgomes/linux-2.6.git for-next

Anderson Briglia (1):
Bluetooth: Implement advertising report meta event

Andre Guedes (5):
Bluetooth: LE advertising info caching
Bluetooth: Protect adv_entries with a RW semaphore
Bluetooth: Check advertising cache in hci_connect()
Bluetooth: Clear advertising cache before scanning
Bluetooth: Add a timer to clear the advertising cache

include/net/bluetooth/hci.h | 20 ++++++++
include/net/bluetooth/hci_core.h | 16 +++++++
net/bluetooth/hci_conn.c | 12 ++++-
net/bluetooth/hci_core.c | 92 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 48 ++++++++++++++++++++
5 files changed, 185 insertions(+), 3 deletions(-)



2011-03-11 13:27:21

by Andre Guedes

[permalink] [raw]
Subject: Re: [RFC 0/6] LE advertising cache

Hi Brian,

On Fri, Mar 4, 2011 at 5:49 PM, Brian Gix <[email protected]> wrote:
>
> On 11-03-04 12:35 PM, Andre Guedes wrote:
>>
>> During a LE connection establishment, the host should be able to infer the
>> bdaddr type from a given bdaddr.
>>
>> To achieve that, during the LE scanning, the host stores the bdaddr and the
>> bdaddr type gathered from advertising reports. The host keeps a list of
>> advertising entry (bdaddr and bdaddr_type) for later lookup. This list will
>> be called Advertising Cache.
>
> My biggest problem with this is testing purposes.
>
> While it is true that the bdaddr_type can be extracted from the LE Scan data, when you are at an event like UPF, there can be an awful lot of devices very close to you.
>
> It would be nice to be able to explicitly specify both the bdaddr and bdaddr_type during these things.

For testing purposes, hcitool lecc [--random] <bdaddr> command can be
used to?explicitly specify both the bdaddr and bdaddr_type.

For the L2CAP socket, we could have extended the "struct sockaddr_l2"
to add?the address type field, but we've decided to not add a new
field which is not applied to basic rate.

>
> But I agree that as a deployed device, caching from an LE scan makes the most sense.
>
> Will this also work for (future) private addressing, where the address being connected to may not be the one initially seen in the scan?

Yes. Advertising entries are cached during both active and passive
scanning. We need to define how to put all pieces together: whitelist,
active/passive scanning and address resolution in the kernel.

>>
>> Since the penality to connect to an unreachable device is relatively high,
>> we must keep only fresh advertising entries on the advertising cache. So,
>> before each LE scanning the advertising cache is cleared. Also, after the LE
>> scanning, a timer is set to clear the cache.
>>
>> Next steps include removing all advertising cache from userspace and
>> implementing a mechanism to sync kernel and userspace advertising cache.
>>
>> Patches are rebased using Vinicius SMP patches, repo:
>> git://git.infradead.org/users/vcgomes/linux-2.6.git for-next
>>
>> Anderson Briglia (1):
>> ? Bluetooth: Implement advertising report meta event
>>
>> Andre Guedes (5):
>> ? Bluetooth: LE advertising info caching
>> ? Bluetooth: Protect adv_entries with a RW semaphore
>> ? Bluetooth: Check advertising cache in hci_connect()
>> ? Bluetooth: Clear advertising cache before scanning
>> ? Bluetooth: Add a timer to clear the advertising cache
>>
>> ?include/net/bluetooth/hci.h ? ? ?| ? 20 ++++++++
>> ?include/net/bluetooth/hci_core.h | ? 16 +++++++
>> ?net/bluetooth/hci_conn.c ? ? ? ? | ? 12 ++++-
>> ?net/bluetooth/hci_core.c ? ? ? ? | ? 92 ++++++++++++++++++++++++++++++++++++++
>> ?net/bluetooth/hci_event.c ? ? ? ?| ? 48 ++++++++++++++++++++
>> ?5 files changed, 185 insertions(+), 3 deletions(-)
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
>
> --
> Brian Gix
> [email protected]
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

Regards,

Andre Guedes.

2011-03-10 21:56:50

by Andre Guedes

[permalink] [raw]
Subject: Re: [RFC 1/6] Bluetooth: Implement advertising report meta event

Ok,

Please, do not consider this patch set, I will rebase and send a v2 soon.

Thanks,

Andre.

On Wed, Mar 9, 2011 at 10:58 AM, Anderson Briglia
<[email protected]> wrote:
>
> Hi,
>
> On Fri, Mar 4, 2011 at 4:35 PM, Andre Guedes <[email protected]> wrote:
> > From: Anderson Briglia <[email protected]>
> >
> > This patch implements new LE meta event in order to handle advertising
> > reports.
> >
> > Signed-off-by: Anderson Briglia <[email protected]>
> > ---
> > ?include/net/bluetooth/hci.h | ? 18 ++++++++++++++++++
> > ?net/bluetooth/hci_event.c ? | ? 22 ++++++++++++++++++++++
> > ?2 files changed, 40 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index d851f8b..fdcc494 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -1011,6 +1011,24 @@ struct hci_ev_le_conn_complete {
> > ? ? ? ?__u8 ? ? clk_accurancy;
> > ?} __packed;
> >
> > +#define ADV_IND ? ? ? ? ? ? ? ?0x00
> > +#define ADV_DIRECT_IND 0x01
> > +#define ADV_SCAN_IND ? 0x02
> > +#define ADV_NONCONN_IND ? ? ? ?0x03
> > +#define SCAN_RSP ? ? ? 0x04
> > +
> > +#define ADDR_DEV_PUBLIC ? ? ? ?0x00
> > +#define ADDR_DEV_RANDOM ? ? ? ?0x01
> > +
> > +#define HCI_EV_LE_ADVERTISING_REPORT ? 0x02
> > +struct hci_ev_le_advertising_info {
> > + ? ? ? __u8 ? ? evt_type;
> > + ? ? ? __u8 ? ? bdaddr_type;
> > + ? ? ? bdaddr_t bdaddr;
> > + ? ? ? __u8 ? ? length;
> > + ? ? ? __u8 ? ? data[0];
> > +} __packed;
> > +
> > ?#define HCI_EV_LE_LTK_REQ ? ? ? ? ? ? ?0x05
> > ?struct hci_ev_le_ltk_req {
> > ? ? ? ?__le16 ?handle;
> > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> > index 5a2ab2c..8acc4a5 100644
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -2556,6 +2556,24 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
> > ? ? ? ?hci_dev_unlock(hdev);
> > ?}
> >
> > +static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct sk_buff *skb)
> > +{
> > + ? ? ? struct hci_ev_le_advertising_info *ev;
> > + ? ? ? u8 num_reports, i;
> > +
> > + ? ? ? num_reports = skb->data[0];
> > +
> > + ? ? ? ev = (void *) &skb->data[1];
> > +
> > + ? ? ? BT_DBG("adv from: %s", batostr(&ev->bdaddr));
> > +
> > + ? ? ? for (i = 1; i < num_reports; i++) {
> > + ? ? ? ? ? ? ? ev = (void *) (ev->data + ev->length + 1);
> > + ? ? ? ? ? ? ? BT_DBG("adv from: %s", batostr(&ev->bdaddr));
> > + ? ? ? }
> > +}
> > +
> > ?static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > ?{
> > ? ? ? ?struct hci_ev_le_meta *le_ev = (void *) skb->data;
> > @@ -2571,6 +2589,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > ? ? ? ? ? ? ? ?hci_le_ltk_request_evt(hdev, skb);
> > ? ? ? ? ? ? ? ?break;
> >
> > + ? ? ? case HCI_EV_LE_ADVERTISING_REPORT:
> > + ? ? ? ? ? ? ? hci_le_adv_report_evt(hdev, skb);
> > + ? ? ? ? ? ? ? break;
> > +
> > ? ? ? ?default:
> > ? ? ? ? ? ? ? ?break;
> > ? ? ? ?}
> > --
> > 1.7.1
> >
> >
>
> Please, do not consider this patch. I have another one with some
> modifications proposed by padovan. Andre, rebase your git tree,
> please.
>
>
> --
> INdT - Instituto Nokia de tecnologia
> +55 2126 1122
> http://techblog.briglia.net

2011-03-09 13:58:16

by Anderson Briglia

[permalink] [raw]
Subject: Re: [RFC 1/6] Bluetooth: Implement advertising report meta event

Hi,

On Fri, Mar 4, 2011 at 4:35 PM, Andre Guedes <[email protected]> wrote:
> From: Anderson Briglia <[email protected]>
>
> This patch implements new LE meta event in order to handle advertising
> reports.
>
> Signed-off-by: Anderson Briglia <[email protected]>
> ---
> ?include/net/bluetooth/hci.h | ? 18 ++++++++++++++++++
> ?net/bluetooth/hci_event.c ? | ? 22 ++++++++++++++++++++++
> ?2 files changed, 40 insertions(+), 0 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index d851f8b..fdcc494 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1011,6 +1011,24 @@ struct hci_ev_le_conn_complete {
> ? ? ? ?__u8 ? ? clk_accurancy;
> ?} __packed;
>
> +#define ADV_IND ? ? ? ? ? ? ? ?0x00
> +#define ADV_DIRECT_IND 0x01
> +#define ADV_SCAN_IND ? 0x02
> +#define ADV_NONCONN_IND ? ? ? ?0x03
> +#define SCAN_RSP ? ? ? 0x04
> +
> +#define ADDR_DEV_PUBLIC ? ? ? ?0x00
> +#define ADDR_DEV_RANDOM ? ? ? ?0x01
> +
> +#define HCI_EV_LE_ADVERTISING_REPORT ? 0x02
> +struct hci_ev_le_advertising_info {
> + ? ? ? __u8 ? ? evt_type;
> + ? ? ? __u8 ? ? bdaddr_type;
> + ? ? ? bdaddr_t bdaddr;
> + ? ? ? __u8 ? ? length;
> + ? ? ? __u8 ? ? data[0];
> +} __packed;
> +
> ?#define HCI_EV_LE_LTK_REQ ? ? ? ? ? ? ?0x05
> ?struct hci_ev_le_ltk_req {
> ? ? ? ?__le16 ?handle;
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 5a2ab2c..8acc4a5 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2556,6 +2556,24 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
> ? ? ? ?hci_dev_unlock(hdev);
> ?}
>
> +static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct sk_buff *skb)
> +{
> + ? ? ? struct hci_ev_le_advertising_info *ev;
> + ? ? ? u8 num_reports, i;
> +
> + ? ? ? num_reports = skb->data[0];
> +
> + ? ? ? ev = (void *) &skb->data[1];
> +
> + ? ? ? BT_DBG("adv from: %s", batostr(&ev->bdaddr));
> +
> + ? ? ? for (i = 1; i < num_reports; i++) {
> + ? ? ? ? ? ? ? ev = (void *) (ev->data + ev->length + 1);
> + ? ? ? ? ? ? ? BT_DBG("adv from: %s", batostr(&ev->bdaddr));
> + ? ? ? }
> +}
> +
> ?static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
> ?{
> ? ? ? ?struct hci_ev_le_meta *le_ev = (void *) skb->data;
> @@ -2571,6 +2589,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
> ? ? ? ? ? ? ? ?hci_le_ltk_request_evt(hdev, skb);
> ? ? ? ? ? ? ? ?break;
>
> + ? ? ? case HCI_EV_LE_ADVERTISING_REPORT:
> + ? ? ? ? ? ? ? hci_le_adv_report_evt(hdev, skb);
> + ? ? ? ? ? ? ? break;
> +
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
> --
> 1.7.1
>
>

Please, do not consider this patch. I have another one with some
modifications proposed by padovan. Andre, rebase your git tree,
please.


--
INdT - Instituto Nokia de tecnologia
+55 2126 1122
http://techblog.briglia.net

2011-03-04 20:49:38

by Brian Gix

[permalink] [raw]
Subject: Re: [RFC 0/6] LE advertising cache

On 11-03-04 12:35 PM, Andre Guedes wrote:
> During a LE connection establishment, the host should be able to infer the
> bdaddr type from a given bdaddr.
>
> To achieve that, during the LE scanning, the host stores the bdaddr and the
> bdaddr type gathered from advertising reports. The host keeps a list of
> advertising entry (bdaddr and bdaddr_type) for later lookup. This list will
> be called Advertising Cache.

My biggest problem with this is testing purposes.

While it is true that the bdaddr_type can be extracted from the LE Scan
data, when you are at an event like UPF, there can be an awful lot of
devices very close to you.

It would be nice to be able to explicitly specify both the bdaddr and
bdaddr_type during these things.

But I agree that as a deployed device, caching from an LE scan makes the
most sense.

Will this also work for (future) private addressing, where the address
being connected to may not be the one initially seen in the scan?


>
> Since the penality to connect to an unreachable device is relatively high,
> we must keep only fresh advertising entries on the advertising cache. So,
> before each LE scanning the advertising cache is cleared. Also, after the LE
> scanning, a timer is set to clear the cache.
>
> Next steps include removing all advertising cache from userspace and
> implementing a mechanism to sync kernel and userspace advertising cache.
>
> Patches are rebased using Vinicius SMP patches, repo:
> git://git.infradead.org/users/vcgomes/linux-2.6.git for-next
>
> Anderson Briglia (1):
> Bluetooth: Implement advertising report meta event
>
> Andre Guedes (5):
> Bluetooth: LE advertising info caching
> Bluetooth: Protect adv_entries with a RW semaphore
> Bluetooth: Check advertising cache in hci_connect()
> Bluetooth: Clear advertising cache before scanning
> Bluetooth: Add a timer to clear the advertising cache
>
> include/net/bluetooth/hci.h | 20 ++++++++
> include/net/bluetooth/hci_core.h | 16 +++++++
> net/bluetooth/hci_conn.c | 12 ++++-
> net/bluetooth/hci_core.c | 92 ++++++++++++++++++++++++++++++++++++++
> net/bluetooth/hci_event.c | 48 ++++++++++++++++++++
> 5 files changed, 185 insertions(+), 3 deletions(-)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


--
Brian Gix
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

2011-03-04 20:35:13

by Andre Guedes

[permalink] [raw]
Subject: [RFC 6/6] Bluetooth: Add a timer to clear the advertising cache

This patch adds a timer to clear adv_entries list after three minutes.

After some amount of time, the advertising entries cached during the
last LE scan should be considered expired and they should be removed
from the adv_entries list.

It was chosen a three minutes timeout as an initial attempt. This value
might change in future.

Signed-off-by: Andre Guedes <[email protected]>
---
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_core.c | 9 +++++++++
net/bluetooth/hci_event.c | 6 +++++-
3 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 3ead365..790f839 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -179,6 +179,7 @@ struct hci_dev {

struct list_head adv_entries;
struct rw_semaphore adv_entries_rwsem;
+ struct timer_list adv_timer;

struct hci_dev_stats stat;

@@ -517,6 +518,7 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);

+#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */
int hci_adv_entries_clear(struct hci_dev *hdev);
struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_add_adv_entry(struct hci_dev *hdev,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 8f9b3a5..ea8b0c2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1081,6 +1081,13 @@ static void hci_cmd_timer(unsigned long arg)
tasklet_schedule(&hdev->cmd_task);
}

+static void hci_adv_clear(unsigned long arg)
+{
+ struct hci_dev *hdev = (void *) arg;
+
+ hci_adv_entries_clear(hdev);
+}
+
int hci_adv_entries_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;
@@ -1233,6 +1240,7 @@ int hci_register_dev(struct hci_dev *hdev)

INIT_LIST_HEAD(&hdev->adv_entries);
init_rwsem(&hdev->adv_entries_rwsem);
+ setup_timer(&hdev->adv_timer, hci_adv_clear, (unsigned long) hdev);

INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
@@ -1314,6 +1322,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_unregister_sysfs(hdev);

hci_del_off_timer(hdev);
+ del_timer(&hdev->adv_timer);

destroy_workqueue(hdev->workqueue);

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a07ed86..a1fe9cc 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -858,8 +858,12 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
return;

param_scan_enable = *((__u8 *) sent);
- if (param_scan_enable == 0x01)
+ if (param_scan_enable == 0x01) {
+ del_timer(&hdev->adv_timer);
hci_adv_entries_clear(hdev);
+ } else if (param_scan_enable == 0x00) {
+ mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
+ }
}

static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
--
1.7.1


2011-03-04 20:35:12

by Andre Guedes

[permalink] [raw]
Subject: [RFC 5/6] Bluetooth: Clear advertising cache before scanning

The LE advertising list should be cleared when a LE scanning is
performed. This will force the list to contain only fresh advertising
entries.

In order to achieve that, it was added a handler to the Command
Complete Event generated by the LE Set Scan Enable Command.

Signed-off-by: Andre Guedes <[email protected]>
---
include/net/bluetooth/hci.h | 2 ++
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 2 +-
net/bluetooth/hci_event.c | 23 +++++++++++++++++++++++
4 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fdcc494..1786794 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -670,6 +670,8 @@ struct hci_rp_le_read_buffer_size {
__u8 le_max_pkt;
} __packed;

+#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
+
#define HCI_OP_LE_CREATE_CONN 0x200d
struct hci_cp_le_create_conn {
__le16 scan_interval;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index bf7b5df..3ead365 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -517,6 +517,7 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);

+int hci_adv_entries_clear(struct hci_dev *hdev);
struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_add_adv_entry(struct hci_dev *hdev,
struct hci_ev_le_advertising_info *ev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 71f8788..8f9b3a5 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1081,7 +1081,7 @@ static void hci_cmd_timer(unsigned long arg)
tasklet_schedule(&hdev->cmd_task);
}

-static int hci_adv_entries_clear(struct hci_dev *hdev)
+int hci_adv_entries_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 825de59..a07ed86 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -843,6 +843,25 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
}

+static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ void *sent;
+ __u8 param_scan_enable;
+ __u8 status = *((__u8 *) skb->data);
+
+ if (status)
+ return;
+
+ sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
+ if (!sent)
+ return;
+
+ param_scan_enable = *((__u8 *) sent);
+ if (param_scan_enable == 0x01)
+ hci_adv_entries_clear(hdev);
+}
+
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1799,6 +1818,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_le_ltk_neg_reply(hdev, skb);
break;

+ case HCI_OP_LE_SET_SCAN_ENABLE:
+ hci_cc_le_set_scan_enable(hdev, skb);
+ break;
+
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
--
1.7.1


2011-03-04 20:35:11

by Andre Guedes

[permalink] [raw]
Subject: [RFC 4/6] Bluetooth: Check advertising cache in hci_connect()

When connecting to a LE device, we need to check the advertising cache
in order to know the bdaddr_type of that device. Additionally,
hci_le_connect() was changed to handle the bdaddr_type info.

Signed-off-by: Andre Guedes <[email protected]>
---
net/bluetooth/hci_conn.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 9a4a769..2d3197a 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -45,7 +45,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

-static void hci_le_connect(struct hci_conn *conn)
+static void hci_le_connect(struct hci_conn *conn, u8 bdaddr_type)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_create_conn cp;
@@ -59,6 +59,7 @@ static void hci_le_connect(struct hci_conn *conn)
cp.scan_interval = cpu_to_le16(0x0004);
cp.scan_window = cpu_to_le16(0x0004);
bacpy(&cp.peer_addr, &conn->dst);
+ cp.peer_addr_type = bdaddr_type;
cp.conn_interval_min = cpu_to_le16(0x0008);
cp.conn_interval_max = cpu_to_le16(0x0100);
cp.supervision_timeout = cpu_to_le16(0x0064);
@@ -482,8 +483,13 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
le = hci_conn_add(hdev, LE_LINK, dst);
if (!le)
return ERR_PTR(-ENOMEM);
- if (le->state == BT_OPEN)
- hci_le_connect(le);
+ if (le->state == BT_OPEN) {
+ struct adv_entry *entry = hci_find_adv_entry(hdev, dst);
+ if (!entry)
+ return ERR_PTR(-EHOSTUNREACH);
+
+ hci_le_connect(le, entry->bdaddr_type);
+ }

hci_conn_hold(le);

--
1.7.1


2011-03-04 20:35:10

by Andre Guedes

[permalink] [raw]
Subject: [RFC 3/6] Bluetooth: Protect adv_entries with a RW semaphore

This patch adds a RW semaphore to protect concurrent operations on
adv_entries list.

Signed-off-by: Andre Guedes <[email protected]>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 22 ++++++++++++++++++----
2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 970711d..bf7b5df 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -178,6 +178,7 @@ struct hci_dev {
struct list_head link_keys;

struct list_head adv_entries;
+ struct rw_semaphore adv_entries_rwsem;

struct hci_dev_stats stat;

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index cbff329..71f8788 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -44,6 +44,7 @@
#include <linux/timer.h>
#include <linux/crypto.h>
#include <net/sock.h>
+#include <linux/rwsem.h>

#include <asm/system.h>
#include <linux/uaccess.h>
@@ -1084,6 +1085,8 @@ static int hci_adv_entries_clear(struct hci_dev *hdev)
{
struct list_head *p, *n;

+ down_write(&hdev->adv_entries_rwsem);
+
list_for_each_safe(p, n, &hdev->adv_entries) {
struct adv_entry *entry;

@@ -1093,23 +1096,31 @@ static int hci_adv_entries_clear(struct hci_dev *hdev)
kfree(entry);
}

+ up_write(&hdev->adv_entries_rwsem);
+
return 0;
}

struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct list_head *p;
+ struct adv_entry *res = NULL;
+
+ down_read(&hdev->adv_entries_rwsem);

list_for_each(p, &hdev->adv_entries) {
struct adv_entry *entry;

entry = list_entry(p, struct adv_entry, list);

- if (bacmp(bdaddr, &entry->bdaddr) == 0)
- return entry;
+ if (bacmp(bdaddr, &entry->bdaddr) == 0) {
+ res = entry;
+ goto out;
+ }
}
-
- return NULL;
+out:
+ up_read(&hdev->adv_entries_rwsem);
+ return res;
}

static inline int is_connectable_adv(u8 evt_type)
@@ -1141,7 +1152,9 @@ int hci_add_adv_entry(struct hci_dev *hdev,
bacpy(&entry->bdaddr, &ev->bdaddr);
entry->bdaddr_type = ev->bdaddr_type;

+ down_write(&hdev->adv_entries_rwsem);
list_add(&entry->list, &hdev->adv_entries);
+ up_write(&hdev->adv_entries_rwsem);

return 0;
}
@@ -1219,6 +1232,7 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->link_keys);

INIT_LIST_HEAD(&hdev->adv_entries);
+ init_rwsem(&hdev->adv_entries_rwsem);

INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
--
1.7.1


2011-03-04 20:35:09

by Andre Guedes

[permalink] [raw]
Subject: [RFC 2/6] Bluetooth: LE advertising info caching

This patch adds a list of 'advertising entry' to the struct hci_dev.

The advertising entry (struct adv_entry) stores sensitive information
(bdaddr and bdaddr_type so far) gathered from LE advertising report
events.

A double-linked list (list_head adv_entries) is used to store those
advertising entries. Only advertising entries from connectables devices
are inserted into the list.

Signed-off-by: Andre Guedes <[email protected]>
---
include/net/bluetooth/hci_core.h | 12 ++++++
net/bluetooth/hci_core.c | 69 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 5 +--
3 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c59e857..970711d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -82,6 +82,12 @@ struct link_key {
u8 pin_len;
};

+struct adv_entry {
+ struct list_head list;
+ bdaddr_t bdaddr;
+ u8 bdaddr_type;
+};
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -171,6 +177,8 @@ struct hci_dev {

struct list_head link_keys;

+ struct list_head adv_entries;
+
struct hci_dev_stats stat;

struct sk_buff_head driver_init;
@@ -508,6 +516,10 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);

+struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_add_adv_entry(struct hci_dev *hdev,
+ struct hci_ev_le_advertising_info *ev);
+
void hci_del_off_timer(struct hci_dev *hdev);

void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ff67843..cbff329 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1080,6 +1080,72 @@ static void hci_cmd_timer(unsigned long arg)
tasklet_schedule(&hdev->cmd_task);
}

+static int hci_adv_entries_clear(struct hci_dev *hdev)
+{
+ struct list_head *p, *n;
+
+ list_for_each_safe(p, n, &hdev->adv_entries) {
+ struct adv_entry *entry;
+
+ entry = list_entry(p, struct adv_entry, list);
+
+ list_del(p);
+ kfree(entry);
+ }
+
+ return 0;
+}
+
+struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct list_head *p;
+
+ list_for_each(p, &hdev->adv_entries) {
+ struct adv_entry *entry;
+
+ entry = list_entry(p, struct adv_entry, list);
+
+ if (bacmp(bdaddr, &entry->bdaddr) == 0)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static inline int is_connectable_adv(u8 evt_type)
+{
+ if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
+ return 1;
+
+ return 0;
+}
+
+int hci_add_adv_entry(struct hci_dev *hdev,
+ struct hci_ev_le_advertising_info *ev)
+{
+ struct adv_entry *entry;
+
+ if (!is_connectable_adv(ev->evt_type))
+ return -EINVAL;
+
+ entry = hci_find_adv_entry(hdev, &ev->bdaddr);
+ /* Only new entries should be added to adv_entries. So, if
+ * bdaddr was found, don't add it. */
+ if (entry)
+ return 0;
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return -ENOMEM;
+
+ bacpy(&entry->bdaddr, &ev->bdaddr);
+ entry->bdaddr_type = ev->bdaddr_type;
+
+ list_add(&entry->list, &hdev->adv_entries);
+
+ return 0;
+}
+
static struct crypto_blkcipher *alloc_cypher(void)
{
if (enable_smp)
@@ -1152,6 +1218,8 @@ int hci_register_dev(struct hci_dev *hdev)

INIT_LIST_HEAD(&hdev->link_keys);

+ INIT_LIST_HEAD(&hdev->adv_entries);
+
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1239,6 +1307,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev);
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
+ hci_adv_entries_clear(hdev);
hci_dev_unlock_bh(hdev);

__hci_dev_put(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8acc4a5..825de59 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2565,12 +2565,11 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
num_reports = skb->data[0];

ev = (void *) &skb->data[1];
-
- BT_DBG("adv from: %s", batostr(&ev->bdaddr));
+ hci_add_adv_entry(hdev, ev);

for (i = 1; i < num_reports; i++) {
ev = (void *) (ev->data + ev->length + 1);
- BT_DBG("adv from: %s", batostr(&ev->bdaddr));
+ hci_add_adv_entry(hdev, ev);
}
}

--
1.7.1


2011-03-04 20:35:08

by Andre Guedes

[permalink] [raw]
Subject: [RFC 1/6] Bluetooth: Implement advertising report meta event

From: Anderson Briglia <[email protected]>

This patch implements new LE meta event in order to handle advertising
reports.

Signed-off-by: Anderson Briglia <[email protected]>
---
include/net/bluetooth/hci.h | 18 ++++++++++++++++++
net/bluetooth/hci_event.c | 22 ++++++++++++++++++++++
2 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index d851f8b..fdcc494 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1011,6 +1011,24 @@ struct hci_ev_le_conn_complete {
__u8 clk_accurancy;
} __packed;

+#define ADV_IND 0x00
+#define ADV_DIRECT_IND 0x01
+#define ADV_SCAN_IND 0x02
+#define ADV_NONCONN_IND 0x03
+#define SCAN_RSP 0x04
+
+#define ADDR_DEV_PUBLIC 0x00
+#define ADDR_DEV_RANDOM 0x01
+
+#define HCI_EV_LE_ADVERTISING_REPORT 0x02
+struct hci_ev_le_advertising_info {
+ __u8 evt_type;
+ __u8 bdaddr_type;
+ bdaddr_t bdaddr;
+ __u8 length;
+ __u8 data[0];
+} __packed;
+
#define HCI_EV_LE_LTK_REQ 0x05
struct hci_ev_le_ltk_req {
__le16 handle;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5a2ab2c..8acc4a5 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2556,6 +2556,24 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}

+static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_le_advertising_info *ev;
+ u8 num_reports, i;
+
+ num_reports = skb->data[0];
+
+ ev = (void *) &skb->data[1];
+
+ BT_DBG("adv from: %s", batostr(&ev->bdaddr));
+
+ for (i = 1; i < num_reports; i++) {
+ ev = (void *) (ev->data + ev->length + 1);
+ BT_DBG("adv from: %s", batostr(&ev->bdaddr));
+ }
+}
+
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_meta *le_ev = (void *) skb->data;
@@ -2571,6 +2589,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_ltk_request_evt(hdev, skb);
break;

+ case HCI_EV_LE_ADVERTISING_REPORT:
+ hci_le_adv_report_evt(hdev, skb);
+ break;
+
default:
break;
}
--
1.7.1