Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 290832
b: refs/heads/master
c: 561aafb
h: refs/heads/master
v: v3
  • Loading branch information
Johan Hedberg committed Feb 13, 2012
1 parent 2f764f8 commit 7e2d909
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 32748db00228b67a5315a91e1a6dd2c54864d87b
refs/heads/master: 561aafbcb2e3f8fee11d3781f866c7b4c4f93a28
29 changes: 22 additions & 7 deletions trunk/include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,23 @@ struct inquiry_data {
};

struct inquiry_entry {
struct list_head list;
struct list_head all; /* inq_cache.all */
struct list_head list; /* unknown or resolve */
enum {
NAME_NOT_KNOWN,
NAME_NEEDED,
NAME_PENDING,
NAME_KNOWN,
} name_state;
__u32 timestamp;
struct inquiry_data data;
};

struct inquiry_cache {
struct list_head list;
__u32 timestamp;
struct list_head all; /* All devices found during inquiry */
struct list_head unknown; /* Name state not known */
struct list_head resolve; /* Name needs to be resolved */
__u32 timestamp;
};

struct hci_conn_hash {
Expand Down Expand Up @@ -350,12 +359,14 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);

static inline void inquiry_cache_init(struct hci_dev *hdev)
{
INIT_LIST_HEAD(&hdev->inq_cache.list);
INIT_LIST_HEAD(&hdev->inq_cache.all);
INIT_LIST_HEAD(&hdev->inq_cache.unknown);
INIT_LIST_HEAD(&hdev->inq_cache.resolve);
}

static inline int inquiry_cache_empty(struct hci_dev *hdev)
{
return list_empty(&hdev->inq_cache.list);
return list_empty(&hdev->inq_cache.all);
}

static inline long inquiry_cache_age(struct hci_dev *hdev)
Expand All @@ -371,7 +382,10 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)

struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
bdaddr_t *bdaddr);
void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
bdaddr_t *bdaddr);
void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
bool name_known);

/* ----- HCI Connections ----- */
enum {
Expand Down Expand Up @@ -913,7 +927,8 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
u8 *randomizer, u8 status);
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
u8 addr_type, u8 *dev_class, s8 rssi,
u8 cfm_name, u8 *eir);
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status);
Expand Down
58 changes: 47 additions & 11 deletions trunk/net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,16 @@ struct hci_dev *hci_dev_get(int index)
/* ---- Inquiry support ---- */
static void inquiry_cache_flush(struct hci_dev *hdev)
{
struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *p, *n;

list_for_each_entry_safe(p, n, &hdev->inq_cache.list, list) {
list_del(&p->list);
list_for_each_entry_safe(p, n, &cache->all, all) {
list_del(&p->all);
kfree(p);
}

INIT_LIST_HEAD(&cache->unknown);
INIT_LIST_HEAD(&cache->resolve);
}

struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
Expand All @@ -372,29 +376,61 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b

BT_DBG("cache %p, %s", cache, batostr(bdaddr));

list_for_each_entry(e, &cache->list, list) {
list_for_each_entry(e, &cache->all, all) {
if (!bacmp(&e->data.bdaddr, bdaddr))
return e;
}

return NULL;
}

void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data)
struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
bdaddr_t *bdaddr)
{
struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *e;

BT_DBG("cache %p, %s", cache, batostr(bdaddr));

list_for_each_entry(e, &cache->unknown, list) {
if (!bacmp(&e->data.bdaddr, bdaddr))
return e;
}

return NULL;
}

void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
bool name_known)
{
struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *ie;

BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));

ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
if (!ie) {
/* Entry not in the cache. Add new one. */
ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
if (!ie)
return;
if (ie)
goto update;

/* Entry not in the cache. Add new one. */
ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
if (!ie)
return;

list_add(&ie->all, &cache->all);

if (name_known) {
ie->name_state = NAME_KNOWN;
} else {
ie->name_state = NAME_NOT_KNOWN;
list_add(&ie->list, &cache->unknown);
}

list_add(&ie->list, &cache->list);
update:
if (name_known && ie->name_state != NAME_KNOWN &&
ie->name_state != NAME_PENDING) {
ie->name_state = NAME_KNOWN;
list_del(&ie->list);
}

memcpy(&ie->data, data, sizeof(*data));
Expand All @@ -409,7 +445,7 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
struct inquiry_entry *e;
int copied = 0;

list_for_each_entry(e, &cache->list, list) {
list_for_each_entry(e, &cache->all, all) {
struct inquiry_data *data = &e->data;

if (copied >= num)
Expand Down
51 changes: 43 additions & 8 deletions trunk/net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1533,9 +1533,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
data.clock_offset = info->clock_offset;
data.rssi = 0x00;
data.ssp_mode = 0x00;
hci_inquiry_cache_update(hdev, &data);
hci_inquiry_cache_update(hdev, &data, false);
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
info->dev_class, 0, NULL);
info->dev_class, 0, 1, NULL);
}

hci_dev_unlock(hdev);
Expand Down Expand Up @@ -2572,10 +2572,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
data.ssp_mode = 0x00;
hci_inquiry_cache_update(hdev, &data);
hci_inquiry_cache_update(hdev, &data, false);
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
info->dev_class, info->rssi,
NULL);
1, NULL);
}
} else {
struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
Expand All @@ -2589,10 +2589,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
data.ssp_mode = 0x00;
hci_inquiry_cache_update(hdev, &data);
hci_inquiry_cache_update(hdev, &data, false);
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
info->dev_class, info->rssi,
NULL);
1, NULL);
}
}

Expand Down Expand Up @@ -2710,6 +2710,31 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s
BT_DBG("%s status %d", hdev->name, ev->status);
}

static inline bool eir_has_complete_name(u8 *data, size_t data_len)
{
u8 field_len;
size_t parsed;

for (parsed = 0; parsed < data_len - 1; parsed += field_len) {
field_len = data[0];

if (field_len == 0)
break;

parsed += field_len + 1;

if (parsed > data_len)
break;

if (data[1] == EIR_NAME_COMPLETE)
return true;

data += field_len + 1;
}

return false;
}

static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct inquiry_data data;
Expand All @@ -2724,6 +2749,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev);

for (; num_rsp; num_rsp--, info++) {
bool name_known;

bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
Expand All @@ -2732,9 +2759,17 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
data.ssp_mode = 0x01;
hci_inquiry_cache_update(hdev, &data);

if (test_bit(HCI_MGMT, &hdev->flags))
name_known = eir_has_complete_name(info->data,
sizeof(info->data));
else
name_known = true;

hci_inquiry_cache_update(hdev, &data, name_known);
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
info->dev_class, info->rssi, info->data);
info->dev_class, info->rssi,
!name_known, info->data);
}

hci_dev_unlock(hdev);
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/bluetooth/hci_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)

hci_dev_lock(hdev);

list_for_each_entry(e, &cache->list, list) {
list_for_each_entry(e, &cache->all, all) {
struct inquiry_data *data = &e->data;
seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
batostr(&data->bdaddr),
Expand Down
51 changes: 50 additions & 1 deletion trunk/net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,50 @@ static int stop_discovery(struct sock *sk, u16 index)
return err;
}

static int confirm_name(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct mgmt_cp_confirm_name *cp = (void *) data;
struct inquiry_entry *e;
struct hci_dev *hdev;
int err;

BT_DBG("hci%u", index);

if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
MGMT_STATUS_INVALID_PARAMS);

hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
MGMT_STATUS_INVALID_PARAMS);

hci_dev_lock(hdev);

e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
if (!e) {
err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
MGMT_STATUS_INVALID_PARAMS);
goto failed;
}

if (cp->name_known) {
e->name_state = NAME_KNOWN;
list_del(&e->list);
} else {
e->name_state = NAME_NEEDED;
list_move(&e->list, &hdev->inq_cache.resolve);
}

err = 0;

failed:
hci_dev_unlock(hdev);

return err;
}

static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
Expand Down Expand Up @@ -2215,6 +2259,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_STOP_DISCOVERY:
err = stop_discovery(sk, index);
break;
case MGMT_OP_CONFIRM_NAME:
err = confirm_name(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_BLOCK_DEVICE:
err = block_device(sk, index, buf + sizeof(*hdr), len);
break;
Expand Down Expand Up @@ -2689,7 +2736,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
}

int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
u8 addr_type, u8 *dev_class, s8 rssi,
u8 cfm_name, u8 *eir)
{
struct mgmt_ev_device_found ev;

Expand All @@ -2698,6 +2746,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = link_to_mgmt(link_type, addr_type);
ev.rssi = rssi;
ev.confirm_name = cfm_name;

if (eir)
memcpy(ev.eir, eir, sizeof(ev.eir));
Expand Down

0 comments on commit 7e2d909

Please sign in to comment.