2011-05-26 19:23:49

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 1/9] Bluetooth: Add advertising report meta event structs

From: Anderson Briglia <[email protected]>

This patch adds definitions and a new struct for Advertising Report
Event from LE and Dual Mode controllers.

Signed-off-by: Anderson Briglia <[email protected]>
---
include/net/bluetooth/hci.h | 19 +++++++++++++++++++
1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index e0a3cf1..ec0fb2d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1029,6 +1029,25 @@ struct hci_ev_le_conn_complete {
__u8 clk_accurancy;
} __packed;

+/* Advertising report event types */
+#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;
+
/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal {
--
1.7.4.1



2011-05-30 22:37:22

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v3 5/9] Bluetooth: Advertising entries lifetime

Hi Andre,

* Andre Guedes <[email protected]> [2011-05-26 16:23:53 -0300]:

> This patch adds a timer to clear 'adv_entries' 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 advertising cache.
>
> 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 | 14 ++++++++++++++
> net/bluetooth/hci_event.c | 6 +++++-
> 3 files changed, 21 insertions(+), 1 deletions(-)

Patches 1 to 5 have been applied. Thanks.

--
Gustavo F. Padovan
http://profusion.mobi

2011-05-30 22:30:27

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v3 6/9] Bluetooth: Add 'dst_type' field to struct hci_conn

Hi Andre,

* Andre Guedes <[email protected]> [2011-05-26 16:23:54 -0300]:

> This patch adds a new field (dst_type) to the struct hci_conn which
> holds the type of the destination address (bdaddr_t dst). This
> approach is needed in order to use the struct hci_conn as an
> abstraction of LE connections in HCI Layer.
>
> This patch also adds a new parameter to hci_conn_add() since now the
> address type must be considered to create LE struct hci_conn objects.
> For non-LE that parameter is ignored.
>
> Signed-off-by: Andre Guedes <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 4 +++-
> net/bluetooth/hci_conn.c | 12 ++++++++----
> net/bluetooth/hci_event.c | 11 +++++++----
> 3 files changed, 18 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index af4b0ed..486224d 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -224,6 +224,7 @@ struct hci_conn {
> spinlock_t lock;
>
> bdaddr_t dst;
> + __u8 dst_type;
> __u16 handle;
> __u16 state;
> __u8 mode;
> @@ -424,7 +425,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle);
> void hci_setup_sync(struct hci_conn *conn, __u16 handle);
> void hci_sco_setup(struct hci_conn *conn, __u8 status);
>
> -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
> +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
> + __u8 dst_type);
> int hci_conn_del(struct hci_conn *conn);
> void hci_conn_hash_flush(struct hci_dev *hdev);
> void hci_conn_check_pending(struct hci_dev *hdev);
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 3163330..84ad32b 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -282,7 +282,8 @@ static void hci_conn_auto_accept(unsigned long arg)
> hci_dev_unlock(hdev);
> }
>
> -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
> +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
> + __u8 dst_type)
> {
> struct hci_conn *conn;
>
> @@ -319,6 +320,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
> case ESCO_LINK:
> conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
> break;
> + case LE_LINK:
> + conn->dst_type = dst_type;
> + break;
> }
>
> skb_queue_head_init(&conn->data_q);
> @@ -450,7 +454,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
> le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
> if (le)
> return ERR_PTR(-EBUSY);
> - le = hci_conn_add(hdev, LE_LINK, dst);
> + le = hci_conn_add(hdev, LE_LINK, dst, 0);
> if (!le)
> return ERR_PTR(-ENOMEM);
> if (le->state == BT_OPEN)
> @@ -463,7 +467,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
>
> acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
> if (!acl) {
> - acl = hci_conn_add(hdev, ACL_LINK, dst);
> + acl = hci_conn_add(hdev, ACL_LINK, dst, 0);
> if (!acl)
> return NULL;
> }
> @@ -482,7 +486,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
>
> sco = hci_conn_hash_lookup_ba(hdev, type, dst);
> if (!sco) {
> - sco = hci_conn_add(hdev, type, dst);
> + sco = hci_conn_add(hdev, type, dst, 0);
> if (!sco) {
> hci_conn_put(acl);
> return NULL;
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index df51f93..3fbc66c 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -910,7 +910,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
> }
> } else {
> if (!conn) {
> - conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
> + conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, 0);
> if (conn) {
> conn->out = 1;
> conn->link_mode |= HCI_LM_MASTER;
> @@ -1233,7 +1233,8 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
> }
> } else {
> if (!conn) {
> - conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
> + conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr,
> + cp->peer_addr_type);
> if (conn)
> conn->out = 1;

just set conn->dst_type here might be a better idea. Then we don't need to
modify hci_conn_add() parameters.


> else
> @@ -1397,7 +1398,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
>
> conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
> if (!conn) {
> - conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
> + conn = hci_conn_add(hdev, ev->link_type,
> + &ev->bdaddr, 0);
> if (!conn) {
> BT_ERR("No memory for new connection");
> hci_dev_unlock(hdev);
> @@ -2681,7 +2683,8 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
>
> conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
> if (!conn) {
> - conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
> + conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr,
> + ev->bdaddr_type);

same here.

--
Gustavo F. Padovan
http://profusion.mobi

2011-05-26 19:23:57

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 9/9] Bluetooth: Set 'peer_addr_type' in hci_le_connect()

Set the 'peer_addr_type' field of the LE Create Connection command
sent in hci_le_connect().

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

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 468d2aa..e58ef96 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -58,6 +58,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 = conn->dst_type;
cp.conn_interval_min = cpu_to_le16(0x0008);
cp.conn_interval_max = cpu_to_le16(0x0100);
cp.supervision_timeout = cpu_to_le16(0x0064);
--
1.7.4.1


2011-05-26 19:23:56

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 8/9] 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 address type of that device.

If its advertising entry is not found, the connection is not
established and hci_connect() returns error.

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

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b21cbb3..468d2aa 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -451,10 +451,17 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
BT_DBG("%s dst %s", hdev->name, batostr(dst));

if (type == LE_LINK) {
+ struct adv_entry *entry;
+
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (le)
return ERR_PTR(-EBUSY);
- le = hci_conn_add(hdev, LE_LINK, dst, 0);
+
+ entry = hci_find_adv_entry(hdev, dst);
+ if (!entry)
+ return ERR_PTR(-EHOSTUNREACH);
+
+ le = hci_conn_add(hdev, LE_LINK, dst, entry->bdaddr_type);
if (!le)
return ERR_PTR(-ENOMEM);

--
1.7.4.1


2011-05-26 19:23:55

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 7/9] Bluetooth: Remove useless check in hci_connect()

There is no need to check the connection's state since hci_conn_add()
has just created a new connection and its state has been set properly.

Signed-off-by: Andre Guedes <[email protected]>
Acked-by: Ville Tervo <[email protected]>
---
net/bluetooth/hci_conn.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 84ad32b..b21cbb3 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -457,8 +457,8 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
le = hci_conn_add(hdev, LE_LINK, dst, 0);
if (!le)
return ERR_PTR(-ENOMEM);
- if (le->state == BT_OPEN)
- hci_le_connect(le);
+
+ hci_le_connect(le);

hci_conn_hold(le);

--
1.7.4.1


2011-05-26 19:23:54

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 6/9] Bluetooth: Add 'dst_type' field to struct hci_conn

This patch adds a new field (dst_type) to the struct hci_conn which
holds the type of the destination address (bdaddr_t dst). This
approach is needed in order to use the struct hci_conn as an
abstraction of LE connections in HCI Layer.

This patch also adds a new parameter to hci_conn_add() since now the
address type must be considered to create LE struct hci_conn objects.
For non-LE that parameter is ignored.

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

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index af4b0ed..486224d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -224,6 +224,7 @@ struct hci_conn {
spinlock_t lock;

bdaddr_t dst;
+ __u8 dst_type;
__u16 handle;
__u16 state;
__u8 mode;
@@ -424,7 +425,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);

-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
+ __u8 dst_type);
int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 3163330..84ad32b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -282,7 +282,8 @@ static void hci_conn_auto_accept(unsigned long arg)
hci_dev_unlock(hdev);
}

-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
+ __u8 dst_type)
{
struct hci_conn *conn;

@@ -319,6 +320,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
case ESCO_LINK:
conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
break;
+ case LE_LINK:
+ conn->dst_type = dst_type;
+ break;
}

skb_queue_head_init(&conn->data_q);
@@ -450,7 +454,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (le)
return ERR_PTR(-EBUSY);
- le = hci_conn_add(hdev, LE_LINK, dst);
+ le = hci_conn_add(hdev, LE_LINK, dst, 0);
if (!le)
return ERR_PTR(-ENOMEM);
if (le->state == BT_OPEN)
@@ -463,7 +467,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8

acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (!acl) {
- acl = hci_conn_add(hdev, ACL_LINK, dst);
+ acl = hci_conn_add(hdev, ACL_LINK, dst, 0);
if (!acl)
return NULL;
}
@@ -482,7 +486,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8

sco = hci_conn_hash_lookup_ba(hdev, type, dst);
if (!sco) {
- sco = hci_conn_add(hdev, type, dst);
+ sco = hci_conn_add(hdev, type, dst, 0);
if (!sco) {
hci_conn_put(acl);
return NULL;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index df51f93..3fbc66c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -910,7 +910,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
}
} else {
if (!conn) {
- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
+ conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, 0);
if (conn) {
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
@@ -1233,7 +1233,8 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
}
} else {
if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
+ conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr,
+ cp->peer_addr_type);
if (conn)
conn->out = 1;
else
@@ -1397,7 +1398,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk

conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
- conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
+ conn = hci_conn_add(hdev, ev->link_type,
+ &ev->bdaddr, 0);
if (!conn) {
BT_ERR("No memory for new connection");
hci_dev_unlock(hdev);
@@ -2681,7 +2683,8 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff

conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
+ conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr,
+ ev->bdaddr_type);
if (!conn) {
BT_ERR("No memory for new connection");
hci_dev_unlock(hdev);
--
1.7.4.1


2011-05-26 19:23:53

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 5/9] Bluetooth: Advertising entries lifetime

This patch adds a timer to clear 'adv_entries' 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 advertising cache.

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 | 14 ++++++++++++++
net/bluetooth/hci_event.c | 6 +++++-
3 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 10dfb85..af4b0ed 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -188,6 +188,7 @@ struct hci_dev {
struct list_head remote_oob_data;

struct list_head adv_entries;
+ struct timer_list adv_timer;

struct hci_dev_stats stat;

@@ -535,6 +536,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(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 dd27f97..5040c3f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1204,6 +1204,17 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
return 0;
}

+static void hci_clear_adv_cache(unsigned long arg)
+{
+ struct hci_dev *hdev = (void *) arg;
+
+ hci_dev_lock(hdev);
+
+ hci_adv_entries_clear(hdev);
+
+ hci_dev_unlock(hdev);
+}
+
int hci_adv_entries_clear(struct hci_dev *hdev)
{
struct adv_entry *entry, *tmp;
@@ -1332,6 +1343,8 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->remote_oob_data);

INIT_LIST_HEAD(&hdev->adv_entries);
+ setup_timer(&hdev->adv_timer, hci_clear_adv_cache,
+ (unsigned long) hdev);

INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
@@ -1405,6 +1418,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 556c38a..df51f93 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -856,8 +856,12 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,

hci_dev_lock(hdev);

- if (cp->enable == 0x01)
+ if (cp->enable == 0x01) {
+ del_timer(&hdev->adv_timer);
hci_adv_entries_clear(hdev);
+ } else if (cp->enable == 0x00) {
+ mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
+ }

hci_dev_unlock(hdev);
}
--
1.7.4.1


2011-05-26 19:23:52

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 4/9] Bluetooth: Clear advertising cache before scanning

The LE advertising cache should be cleared before performing a LE
scanning. This will force the cache to contain only fresh advertising
entries.

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

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ec0fb2d..ed1a0d1 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -710,6 +710,12 @@ struct hci_rp_le_read_buffer_size {
__u8 le_max_pkt;
} __packed;

+#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
+struct hci_cp_le_set_scan_enable {
+ __u8 enable;
+ __u8 filter_dup;
+} __packed;
+
#define HCI_OP_LE_CREATE_CONN 0x200d
struct hci_cp_le_create_conn {
__le16 scan_interval;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 458caac..556c38a 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -839,6 +839,29 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
rp->randomizer, rp->status);
}

+static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_cp_le_set_scan_enable *cp;
+ __u8 status = *((__u8 *) skb->data);
+
+ BT_DBG("%s status 0x%x", hdev->name, status);
+
+ if (status)
+ return;
+
+ cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
+ if (!cp)
+ return;
+
+ hci_dev_lock(hdev);
+
+ if (cp->enable == 0x01)
+ hci_adv_entries_clear(hdev);
+
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1814,6 +1837,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_user_confirm_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.4.1


2011-05-26 19:23:51

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 3/9] Bluetooth: Add Advertising Report Meta Event handler

This patch adds a function to handle LE Advertising Report Meta
Events.

Signed-off-by: Andre Guedes <[email protected]>
Signed-off-by: Anderson Briglia <[email protected]>
---
net/bluetooth/hci_event.c | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f13ddbf..458caac 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2680,6 +2680,28 @@ unlock:
hci_dev_unlock(hdev);
}

+static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ const u8 RSSI_SIZE = 1;
+ struct hci_ev_le_advertising_info *ev;
+ u8 num_reports;
+
+ num_reports = skb->data[0];
+ ev = (void *) &skb->data[1];
+
+ hci_dev_lock(hdev);
+
+ hci_add_adv_entry(hdev, ev);
+
+ while (--num_reports) {
+ ev = (void *) (ev->data + ev->length + RSSI_SIZE);
+ hci_add_adv_entry(hdev, ev);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
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;
@@ -2691,6 +2713,10 @@ static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_conn_complete_evt(hdev, skb);
break;

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


2011-05-26 19:23:50

by Andre Guedes

[permalink] [raw]
Subject: [PATCH v3 2/9] Bluetooth: LE advertising cache

This patch implements the LE advertising cache. It stores sensitive
information (bdaddr and bdaddr_type so far) gathered from LE
advertising report events.

Only advertising entries from connectables devices are added to the
cache.

Signed-off-by: Andre Guedes <[email protected]>
---
include/net/bluetooth/hci_core.h | 13 ++++++++
net/bluetooth/hci_core.c | 64 ++++++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6c994c0..10dfb85 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -89,6 +89,12 @@ struct oob_data {
u8 randomizer[16];
};

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

struct list_head remote_oob_data;

+ struct list_head adv_entries;
+
struct hci_dev_stats stat;

struct sk_buff_head driver_init;
@@ -527,6 +535,11 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(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);
+
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 b6bda3f..dd27f97 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1204,6 +1204,67 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
return 0;
}

+int hci_adv_entries_clear(struct hci_dev *hdev)
+{
+ struct adv_entry *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+
+ BT_DBG("%s adv cache cleared", hdev->name);
+
+ return 0;
+}
+
+struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct adv_entry *entry;
+
+ list_for_each_entry(entry, &hdev->adv_entries, 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;
+
+ /* Only new entries should be added to adv_entries. So, if
+ * bdaddr was found, don't add it. */
+ if (hci_find_adv_entry(hdev, &ev->bdaddr))
+ 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);
+
+ BT_DBG("%s adv entry added: address %s type %u", hdev->name,
+ batostr(&entry->bdaddr), entry->bdaddr_type);
+
+ return 0;
+}
+
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1270,6 +1331,8 @@ int hci_register_dev(struct hci_dev *hdev)

INIT_LIST_HEAD(&hdev->remote_oob_data);

+ 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);
@@ -1350,6 +1413,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_adv_entries_clear(hdev);
hci_dev_unlock_bh(hdev);

__hci_dev_put(hdev);
--
1.7.4.1