2011-03-11 13:32:51

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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 | 47 +++++++++++++++++++
5 files changed, 184 insertions(+), 3 deletions(-)



2011-03-16 12:21:49

by Anderson Lizardo

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

Hi Ville,

On Wed, Mar 16, 2011 at 1:53 AM, Ville Tervo <[email protected]> wrote:
> On Tue, Mar 15, 2011 at 10:41:55AM -0400, ext Anderson Lizardo wrote:
>> IIRC the connection procedure defined on the spec requires this scan.
>> See for instance the general connection establishment procedure at
>> page 1715
>
> But it makes "Direct Connection Establishment" impossible.

I can only see on the spec "Direct Connection Establishment" allowed
to be used as sub-procedures for either General or Selective
connection establishment. Correct me if you find other references
outside these two procedures.

The problem is that, unlike BR/EDR where the address is enough, for LE
you need to know the address type as well before connecting and this
information can only be obtained by means of advertising reports (from
a scanning during discovery, or from previously bonded devices, for
which we need to have stored this information).

Also see this note regarding privacy-enabled peripherals (page 1704):
"A Central may connect to a Peripheral that supports the privacy
feature using only the general connection establishment procedure."
(I'm not sure I get this sentence right, as it uses the dubious "may
... only" sentence).

> Is it needed to pass PTS for example?

Note sure. Claudio may know more about PTS requirements on GAP part.

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-03-16 05:53:57

by Ville Tervo

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

On Tue, Mar 15, 2011 at 10:41:55AM -0400, ext Anderson Lizardo wrote:
> Hi Ville,
>
> On Tue, Mar 15, 2011 at 3:57 AM, Ville Tervo <[email protected]> wrote:
> > Hi,
> >
> > On Fri, Mar 11, 2011 at 10:32:51AM -0300, ext 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.
> >>
> >> 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.
> >
> > I tested these pathes with a device which had random address. Connection works
> > which is good.
> >
> > How ever I'm not yet sure if mandatory scanning before every connect is
> > acceptable.
>
> IIRC the connection procedure defined on the spec requires this scan.
> See for instance the general connection establishment procedure at
> page 1715

But it makes "Direct Connection Establishment" impossible.

Is it needed to pass PTS for example?

>
> >
> > I have been playing with idea to derive address type from msb bits of the
> > address. Any ideaѕ what would lose in that way?
>
> How can you differ public address type from a random one in this case?
> I think the MSB bit checking is only for detecting the type of random
> address (static, non-resolvable private, resolvable private)

That's true. Address type needs to be known.


--
Ville

2011-03-15 14:41:55

by Anderson Lizardo

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

Hi Ville,

On Tue, Mar 15, 2011 at 3:57 AM, Ville Tervo <[email protected]> wrote:
> Hi,
>
> On Fri, Mar 11, 2011 at 10:32:51AM -0300, ext 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.
>>
>> 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.
>
> I tested these pathes with a device which had random address. Connection works
> which is good.
>
> How ever I'm not yet sure if mandatory scanning before every connect is
> acceptable.

IIRC the connection procedure defined on the spec requires this scan.
See for instance the general connection establishment procedure at
page 1715

>
> I have been playing with idea to derive address type from msb bits of the
> address. Any ideaѕ what would lose in that way?

How can you differ public address type from a random one in this case?
I think the MSB bit checking is only for detecting the type of random
address (static, non-resolvable private, resolvable private)

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-03-15 07:57:42

by Ville Tervo

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

Hi,

On Fri, Mar 11, 2011 at 10:32:51AM -0300, ext 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.
>
> 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.

I tested these pathes with a device which had random address. Connection works
which is good.

How ever I'm not yet sure if mandatory scanning before every connect is
acceptable.

I have been playing with idea to derive address type from msb bits of the
address. Any ideaѕ what would lose in that way?


--
Ville

2011-03-11 13:32:57

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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 fa1b43b..03b41a0 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-11 13:32:56

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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 de27caa..a936592 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 5019b76..fa1b43b 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-11 13:32:55

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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-11 13:32:54

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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-11 13:32:53

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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 55502ac..5019b76 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2564,12 +2564,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);

while (--num_reports) {
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-11 13:32:52

by Andre Guedes

[permalink] [raw]
Subject: [RFC v2 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 | 21 +++++++++++++++++++++
2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index d851f8b..de27caa 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 ADV_SCAN_RSP 0x04
+
+#define ADDR_LE_DEV_PUBLIC 0x00
+#define ADDR_LE_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..55502ac 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2556,6 +2556,23 @@ 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;
+
+ num_reports = skb->data[0];
+ ev = (void *) &skb->data[1];
+
+ BT_DBG("adv from: %s", batostr(&ev->bdaddr));
+
+ while (--num_reports) {
+ 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 +2588,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