From b57c1a5646739bfc273245dc738f2f12a2d4d3ec Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 3 Jan 2012 16:03:00 +0200 Subject: Bluetooth: Convert inquiry cache to use standard list types This makes it possible to use the convenience functions provided for standard kernel list types and it also makes it easier to extend the use of the cache for the management interface where e.g. name resolving control will be needed. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 31 +++++++++++++++++-------------- net/bluetooth/hci_sysfs.c | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 845da3ee56a0..feeea4df2529 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -357,15 +357,11 @@ 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 *next = cache->list, *e; - - BT_DBG("cache %p", cache); + struct inquiry_entry *p, *n; - cache->list = NULL; - while ((e = next)) { - next = e->next; - kfree(e); + list_for_each_entry_safe(p, n, &hdev->inq_cache.list, list) { + list_del(&p->list); + kfree(p); } } @@ -376,10 +372,12 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b BT_DBG("cache %p, %s", cache, batostr(bdaddr)); - for (e = cache->list; e; e = e->next) + list_for_each_entry(e, &cache->list, list) { if (!bacmp(&e->data.bdaddr, bdaddr)) - break; - return e; + return e; + } + + return NULL; } void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) @@ -396,8 +394,7 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) if (!ie) return; - ie->next = cache->list; - cache->list = ie; + list_add(&ie->list, &cache->list); } memcpy(&ie->data, data, sizeof(*data)); @@ -412,15 +409,21 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) struct inquiry_entry *e; int copied = 0; - for (e = cache->list; e && copied < num; e = e->next, copied++) { + list_for_each_entry(e, &cache->list, list) { struct inquiry_data *data = &e->data; + + if (copied >= num) + break; + bacpy(&info->bdaddr, &data->bdaddr); info->pscan_rep_mode = data->pscan_rep_mode; info->pscan_period_mode = data->pscan_period_mode; info->pscan_mode = data->pscan_mode; memcpy(info->dev_class, data->dev_class, 3); info->clock_offset = data->clock_offset; + info++; + copied++; } BT_DBG("cache %p, copied %d", cache, copied); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 521095614235..ed9cceeec7be 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -388,7 +388,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) hci_dev_lock(hdev); - for (e = cache->list; e; e = e->next) { + list_for_each_entry(e, &cache->list, list) { 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), -- cgit v1.2.3 From 32748db00228b67a5315a91e1a6dd2c54864d87b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 30 Dec 2011 14:57:23 +0200 Subject: Bluetooth: Move Extended Inquiry Response defines to hci.h The EIR defines are needed also outside of mgmt.c (e.g. in hci_event.c to check if EIR data has the complete name) so it's better to have them in a single public place, i.e. hci.h. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 13 +++++++++++++ net/bluetooth/mgmt.c | 12 ------------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5b2fed5eebf2..ce5133b22445 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -284,6 +284,19 @@ enum { #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00 #define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01 +/* Extended Inquiry Response field types */ +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc8e59dda78e..851cb19c55b1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -303,18 +303,6 @@ static u32 get_current_settings(struct hci_dev *hdev) return settings; } -#define EIR_FLAGS 0x01 /* flags */ -#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ -#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ -#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ -#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ -#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ -#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ -#define EIR_NAME_SHORT 0x08 /* shortened local name */ -#define EIR_NAME_COMPLETE 0x09 /* complete local name */ -#define EIR_TX_POWER 0x0A /* transmit power level */ -#define EIR_DEVICE_ID 0x10 /* device ID */ - #define PNP_INFO_SVCLASS_ID 0x1200 static u8 bluetooth_base_uuid[] = { -- cgit v1.2.3 From 561aafbcb2e3f8fee11d3781f866c7b4c4f93a28 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 13:31:59 +0200 Subject: Bluetooth: Add initial mgmt_confirm_name support This patch adds initial support for mgmt_confirm_name. It adds the necessary tracking of the name state by extending the inquiry cache. The actual name resolving operation (to be done once inquiry is finished) is not yet part of this patch. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 29 +++++++++++++++----- net/bluetooth/hci_core.c | 58 ++++++++++++++++++++++++++++++++-------- net/bluetooth/hci_event.c | 51 +++++++++++++++++++++++++++++------ net/bluetooth/hci_sysfs.c | 2 +- net/bluetooth/mgmt.c | 51 ++++++++++++++++++++++++++++++++++- 5 files changed, 163 insertions(+), 28 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 91d1baf05077..2999b6e2c3f0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -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 { @@ -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) @@ -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 { @@ -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); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index feeea4df2529..fc09a3cbe20c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -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) @@ -372,7 +376,7 @@ 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; } @@ -380,7 +384,24 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b 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; @@ -388,13 +409,28 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) 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)); @@ -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) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 001307f81057..9302c3c25568 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -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); @@ -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); @@ -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); } } @@ -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; @@ -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; @@ -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); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index ed9cceeec7be..3600d78c2f25 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -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), diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 851cb19c55b1..39775119585a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1967,6 +1967,50 @@ failed: 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) { @@ -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; @@ -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; @@ -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)); -- cgit v1.2.3 From 3175405b906a85ed2bad21e09c444266e4a05a8e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 13:39:52 +0200 Subject: Bluetooth: Return updated name state with hci_inquiry_cache_update If user-space has already confirmed the name for a remote device we shouldn't request confirmation again. The simplest way to do this is to return the name state from hci_inquiry_cache_update (if it is anything else than unknown then we do not need confirmation from user-space). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 9 +++++++-- net/bluetooth/hci_event.c | 21 ++++++++++++++------- 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2999b6e2c3f0..236f7f0e596e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -384,7 +384,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); 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 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); /* ----- HCI Connections ----- */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fc09a3cbe20c..162176151db9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -400,7 +400,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, return NULL; } -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, +bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { struct inquiry_cache *cache = &hdev->inq_cache; @@ -415,7 +415,7 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, /* Entry not in the cache. Add new one. */ ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); if (!ie) - return; + return false; list_add(&ie->all, &cache->all); @@ -436,6 +436,11 @@ update: memcpy(&ie->data, data, sizeof(*data)); ie->timestamp = jiffies; cache->timestamp = jiffies; + + if (ie->name_state == NAME_NOT_KNOWN) + return false; + + return true; } static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9302c3c25568..d4d20df9fbbf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1525,6 +1525,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * 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; @@ -1533,9 +1535,10 @@ 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, false); + + name_known = hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, 1, NULL); + info->dev_class, 0, !name_known, NULL); } hci_dev_unlock(hdev); @@ -2551,6 +2554,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct { struct inquiry_data data; int num_rsp = *((__u8 *) skb->data); + bool name_known; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -2572,10 +2576,12 @@ 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, false); + + name_known = hci_inquiry_cache_update(hdev, &data, + false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - 1, NULL); + !name_known, NULL); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2589,10 +2595,11 @@ 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, false); + name_known = hci_inquiry_cache_update(hdev, &data, + false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - 1, NULL); + !name_known, NULL); } } @@ -2766,7 +2773,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct else name_known = true; - hci_inquiry_cache_update(hdev, &data, name_known); + name_known = hci_inquiry_cache_update(hdev, &data, name_known); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, !name_known, info->data); -- cgit v1.2.3 From 4663262c294c71aa1139616ae7f24dd345a69c15 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Jan 2012 16:06:08 +0200 Subject: Bluetooth: Flush inquiry cache when starting mgmt triggered inquiry For the remote name state tracking for the management interface to work the cache needs to be flushed whenever inquiry is started. The hci_do_inquiry function is only used by the management interface so by having the flushing done from it ensures that old ioctl based functionality isn't affected. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 162176151db9..5dbfb276edf2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2611,6 +2611,8 @@ int hci_do_inquiry(struct hci_dev *hdev, u8 length) if (test_bit(HCI_INQUIRY, &hdev->flags)) return -EINPROGRESS; + inquiry_cache_flush(hdev); + memset(&cp, 0, sizeof(cp)); memcpy(&cp.lap, lap, sizeof(cp.lap)); cp.length = length; -- cgit v1.2.3 From 30883512be0839349d29c7b0bc31016e0498cf8c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 14:16:21 +0200 Subject: Bluetooth: Rename hdev->inq_cache to hdev->discovery This struct is used for not just inquiry caching but also for general device discovery state tracking so it's better to rename it to something more appropriate. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 16 ++++++++-------- net/bluetooth/hci_core.c | 12 ++++++------ net/bluetooth/hci_sysfs.c | 2 +- net/bluetooth/mgmt.c | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 236f7f0e596e..5a566fd5e2a6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -56,7 +56,7 @@ struct inquiry_entry { struct inquiry_data data; }; -struct inquiry_cache { +struct discovery_state { 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 */ @@ -226,7 +226,7 @@ struct hci_dev { struct list_head mgmt_pending; - struct inquiry_cache inq_cache; + struct discovery_state discovery; struct hci_conn_hash conn_hash; struct list_head blacklist; @@ -357,21 +357,21 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ #define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */ -static inline void inquiry_cache_init(struct hci_dev *hdev) +static inline void discovery_init(struct hci_dev *hdev) { - INIT_LIST_HEAD(&hdev->inq_cache.all); - INIT_LIST_HEAD(&hdev->inq_cache.unknown); - INIT_LIST_HEAD(&hdev->inq_cache.resolve); + INIT_LIST_HEAD(&hdev->discovery.all); + INIT_LIST_HEAD(&hdev->discovery.unknown); + INIT_LIST_HEAD(&hdev->discovery.resolve); } static inline int inquiry_cache_empty(struct hci_dev *hdev) { - return list_empty(&hdev->inq_cache.all); + return list_empty(&hdev->discovery.all); } static inline long inquiry_cache_age(struct hci_dev *hdev) { - struct inquiry_cache *c = &hdev->inq_cache; + struct discovery_state *c = &hdev->discovery; return jiffies - c->timestamp; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5dbfb276edf2..55509b0a810a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -357,7 +357,7 @@ 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 discovery_state *cache = &hdev->discovery; struct inquiry_entry *p, *n; list_for_each_entry_safe(p, n, &cache->all, all) { @@ -371,7 +371,7 @@ static void inquiry_cache_flush(struct hci_dev *hdev) struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; BT_DBG("cache %p, %s", cache, batostr(bdaddr)); @@ -387,7 +387,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bdaddr_t *bdaddr) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; BT_DBG("cache %p, %s", cache, batostr(bdaddr)); @@ -403,7 +403,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); @@ -445,7 +445,7 @@ update: static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) { - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_info *info = (struct inquiry_info *) buf; struct inquiry_entry *e; int copied = 0; @@ -1546,7 +1546,7 @@ int hci_register_dev(struct hci_dev *hdev) init_waitqueue_head(&hdev->req_wait_q); mutex_init(&hdev->req_lock); - inquiry_cache_init(hdev); + discovery_init(hdev); hci_conn_hash_init(hdev); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3600d78c2f25..74b49e330a1d 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -383,7 +383,7 @@ static struct device_type bt_host = { static int inquiry_cache_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; - struct inquiry_cache *cache = &hdev->inq_cache; + struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; hci_dev_lock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 39775119585a..894f11bc571d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2000,7 +2000,7 @@ static int confirm_name(struct sock *sk, u16 index, unsigned char *data, list_del(&e->list); } else { e->name_state = NAME_NEEDED; - list_move(&e->list, &hdev->inq_cache.resolve); + list_move(&e->list, &hdev->discovery.resolve); } err = 0; -- cgit v1.2.3 From ff9ef5787046c3fd20cf9f7ca1cd70260c1eedb9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 14:23:45 +0200 Subject: Bluetooth: Add discovery state tracking This patch adds proper state tracking to the device discovery process. This makes it possible to return appropriate errors when trying to stop a non-active discovery or start discovery when it is already ongoing. Once name resolving is implemented this also makes it possible to know what the right action to do is when a remote name lookup is cancelled. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 +++++++++ net/bluetooth/hci_core.c | 25 +++++++++++++++++++++++++ net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5a566fd5e2a6..2f19de4770b6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -57,6 +57,12 @@ struct inquiry_entry { }; struct discovery_state { + enum { + DISCOVERY_STOPPED, + DISCOVERY_STARTING, + DISCOVERY_ACTIVE, + DISCOVERY_STOPPING, + } state; 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 */ @@ -359,11 +365,14 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); static inline void discovery_init(struct hci_dev *hdev) { + hdev->discovery.state = DISCOVERY_STOPPED; INIT_LIST_HEAD(&hdev->discovery.all); INIT_LIST_HEAD(&hdev->discovery.unknown); INIT_LIST_HEAD(&hdev->discovery.resolve); } +void hci_discovery_set_state(struct hci_dev *hdev, int state); + static inline int inquiry_cache_empty(struct hci_dev *hdev) { return list_empty(&hdev->discovery.all); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55509b0a810a..b68719230601 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -355,6 +355,30 @@ struct hci_dev *hci_dev_get(int index) } /* ---- Inquiry support ---- */ + +void hci_discovery_set_state(struct hci_dev *hdev, int state) +{ + BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); + + if (hdev->discovery.state == state) + return; + + switch (state) { + case DISCOVERY_STOPPED: + mgmt_discovering(hdev, 0); + break; + case DISCOVERY_STARTING: + break; + case DISCOVERY_ACTIVE: + mgmt_discovering(hdev, 1); + break; + case DISCOVERY_STOPPING: + break; + } + + hdev->discovery.state = state; +} + static void inquiry_cache_flush(struct hci_dev *hdev) { struct discovery_state *cache = &hdev->discovery; @@ -367,6 +391,7 @@ static void inquiry_cache_flush(struct hci_dev *hdev) INIT_LIST_HEAD(&cache->unknown); INIT_LIST_HEAD(&cache->resolve); + cache->state = DISCOVERY_STOPPED; } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d4d20df9fbbf..43d69569a0d5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -65,7 +65,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - mgmt_discovering(hdev, 0); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_dev_unlock(hdev); hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); @@ -1119,7 +1119,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) set_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - mgmt_discovering(hdev, 1); + hci_discovery_set_state(hdev, DISCOVERY_ACTIVE); hci_dev_unlock(hdev); } @@ -1507,7 +1507,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff return; hci_dev_lock(hdev); - mgmt_discovering(hdev, 0); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 894f11bc571d..590966ddfa63 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1918,6 +1918,12 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } + if (hdev->discovery.state != DISCOVERY_STOPPED) { + err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_BUSY); + goto failed; + } + cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0); if (!cmd) { err = -ENOMEM; @@ -1927,6 +1933,8 @@ static int start_discovery(struct sock *sk, u16 index, err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); if (err < 0) mgmt_pending_remove(cmd); + else + hci_discovery_set_state(hdev, DISCOVERY_STARTING); failed: hci_dev_unlock(hdev); @@ -1950,6 +1958,12 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock(hdev); + if (hdev->discovery.state != DISCOVERY_ACTIVE) { + err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_REJECTED); + goto failed; + } + cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); if (!cmd) { err = -ENOMEM; @@ -1959,6 +1973,8 @@ static int stop_discovery(struct sock *sk, u16 index) err = hci_cancel_inquiry(hdev); if (err < 0) mgmt_pending_remove(cmd); + else + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); failed: hci_dev_unlock(hdev); -- cgit v1.2.3 From 30dc78e1a2bcbe2a0fca7aa44dfded4bb0db6148 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 4 Jan 2012 15:44:20 +0200 Subject: Bluetooth: Add name resolving support for mgmt based discovery This patch adds the necessary logic to perform name lookups after inquiry completes. This is done by checking for entries in the resolve list after each inquiry complete and remote name complete HCI event. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 8 +++- net/bluetooth/hci_core.c | 34 ++++++++++++++++- net/bluetooth/hci_event.c | 81 ++++++++++++++++++++++++++++++++++++++-- net/bluetooth/mgmt.c | 37 +++++++++++++++--- 4 files changed, 149 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2f19de4770b6..a8680da7f400 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -60,7 +60,8 @@ struct discovery_state { enum { DISCOVERY_STOPPED, DISCOVERY_STARTING, - DISCOVERY_ACTIVE, + DISCOVERY_INQUIRY, + DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; struct list_head all; /* All devices found during inquiry */ @@ -371,6 +372,8 @@ static inline void discovery_init(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->discovery.resolve); } +bool hci_discovery_active(struct hci_dev *hdev); + void hci_discovery_set_state(struct hci_dev *hdev, int state); static inline int inquiry_cache_empty(struct hci_dev *hdev) @@ -393,6 +396,9 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, bdaddr_t *bdaddr); +struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, + bdaddr_t *bdaddr, + int state); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b68719230601..546a42941477 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -356,6 +356,17 @@ struct hci_dev *hci_dev_get(int index) /* ---- Inquiry support ---- */ +bool hci_discovery_active(struct hci_dev *hdev) +{ + struct discovery_state *discov = &hdev->discovery; + + if (discov->state == DISCOVERY_INQUIRY || + discov->state == DISCOVERY_RESOLVING) + return true; + + return false; +} + void hci_discovery_set_state(struct hci_dev *hdev, int state) { BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); @@ -369,9 +380,11 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) break; case DISCOVERY_STARTING: break; - case DISCOVERY_ACTIVE: + case DISCOVERY_INQUIRY: mgmt_discovering(hdev, 1); break; + case DISCOVERY_RESOLVING: + break; case DISCOVERY_STOPPING: break; } @@ -425,6 +438,25 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, return NULL; } +struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, + bdaddr_t *bdaddr, + int state) +{ + struct discovery_state *cache = &hdev->discovery; + struct inquiry_entry *e; + + BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state); + + list_for_each_entry(e, &cache->resolve, list) { + if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state) + return e; + if (!bacmp(&e->data.bdaddr, bdaddr)) + return e; + } + + return NULL; +} + bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 43d69569a0d5..089dff80ccb0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1119,7 +1119,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) set_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_ACTIVE); + hci_discovery_set_state(hdev, DISCOVERY_INQUIRY); hci_dev_unlock(hdev); } @@ -1271,6 +1271,50 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 1; } +static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e) +{ + struct hci_cp_remote_name_req cp; + + memset(&cp, 0, sizeof(cp)); + + bacpy(&cp.bdaddr, &e->data.bdaddr); + cp.pscan_rep_mode = e->data.pscan_rep_mode; + cp.pscan_mode = e->data.pscan_mode; + cp.clock_offset = e->data.clock_offset; + + return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); +} + +static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct discovery_state *discov = &hdev->discovery; + struct inquiry_entry *e; + + if (discov->state == DISCOVERY_STOPPING) + goto discov_complete; + + if (discov->state != DISCOVERY_RESOLVING) + return; + + e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING); + if (e) { + e->name_state = NAME_KNOWN; + list_del(&e->list); + } + + if (list_empty(&discov->resolve)) + goto discov_complete; + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (hci_resolve_name(hdev, e) == 0) { + e->name_state = NAME_PENDING; + return; + } + +discov_complete: + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); +} + static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) { struct hci_cp_remote_name_req *cp; @@ -1289,6 +1333,9 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); + if (test_bit(HCI_MGMT, &hdev->flags)) + hci_resolve_next_name(hdev, &cp->bdaddr); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); if (!conn) goto unlock; @@ -1496,6 +1543,8 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); + struct discovery_state *discov = &hdev->discovery; + struct inquiry_entry *e; BT_DBG("%s status %d", hdev->name, status); @@ -1506,8 +1555,28 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) return; + if (!test_bit(HCI_MGMT, &hdev->flags)) + return; + hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + + if (discov->state != DISCOVERY_INQUIRY) + goto unlock; + + if (list_empty(&discov->resolve)) { + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + goto unlock; + } + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (e && hci_resolve_name(hdev, e) == 0) { + e->name_state = NAME_PENDING; + hci_discovery_set_state(hdev, DISCOVERY_RESOLVING); + } else { + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + } + +unlock: hci_dev_unlock(hdev); } @@ -1807,8 +1876,12 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); - if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags)) - mgmt_remote_name(hdev, &ev->bdaddr, ev->name); + if (test_bit(HCI_MGMT, &hdev->flags)) { + if (ev->status == 0) + mgmt_remote_name(hdev, &ev->bdaddr, ev->name); + + hci_resolve_next_name(hdev, &ev->bdaddr); + } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (!conn) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 590966ddfa63..295cfc8a3076 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1947,6 +1947,8 @@ static int stop_discovery(struct sock *sk, u16 index) { struct hci_dev *hdev; struct pending_cmd *cmd; + struct hci_cp_remote_name_req_cancel cp; + struct inquiry_entry *e; int err; BT_DBG("hci%u", index); @@ -1958,25 +1960,44 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock(hdev); - if (hdev->discovery.state != DISCOVERY_ACTIVE) { + if (!hci_discovery_active(hdev)) { err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_REJECTED); - goto failed; + goto unlock; } cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); if (!cmd) { err = -ENOMEM; - goto failed; + goto unlock; + } + + if (hdev->discovery.state == DISCOVERY_INQUIRY) { + err = hci_cancel_inquiry(hdev); + if (err < 0) + mgmt_pending_remove(cmd); + else + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + goto unlock; + } + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); + if (!e) { + mgmt_pending_remove(cmd); + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + goto unlock; } - err = hci_cancel_inquiry(hdev); + bacpy(&cp.bdaddr, &e->data.bdaddr); + err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, + sizeof(cp), &cp); if (err < 0) mgmt_pending_remove(cmd); else hci_discovery_set_state(hdev, DISCOVERY_STOPPING); -failed: +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2004,6 +2025,12 @@ static int confirm_name(struct sock *sk, u16 index, unsigned char *data, hci_dev_lock(hdev); + if (!hci_discovery_active(hdev)) { + err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_FAILED); + goto failed; + } + e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr); if (!e) { err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, -- cgit v1.2.3 From 25e89e99b4a54a2cb6e27b4675cd71a3d8a9b3fc Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 4 Jan 2012 12:41:58 +0200 Subject: Bluetooth: Process num completed data blocks event Adds support for Number Of Completed Data Blocks Event. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 13 +++++++++++ net/bluetooth/hci_event.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ce5133b22445..6a9d316fb977 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1168,6 +1168,19 @@ struct hci_ev_le_meta { __u8 subevent; } __packed; +#define HCI_EV_NUM_COMP_BLOCKS 0x48 +struct hci_comp_blocks_info { + __le16 handle; + __le16 pkts; + __le16 blocks; +} __packed; + +struct hci_ev_num_comp_blocks { + __le16 num_blocks; + __u8 num_hndl; + struct hci_comp_blocks_info handles[0]; +} __packed; + /* Low energy meta events */ #define HCI_EV_LE_CONN_COMPLETE 0x01 struct hci_ev_le_conn_complete { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 089dff80ccb0..0466ed9c1b47 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2408,6 +2408,56 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s queue_work(hdev->workqueue, &hdev->tx_work); } +static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_num_comp_blocks *ev = (void *) skb->data; + int i; + + if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) { + BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode); + return; + } + + if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) + + ev->num_hndl * sizeof(struct hci_comp_blocks_info)) { + BT_DBG("%s bad parameters", hdev->name); + return; + } + + BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks, + ev->num_hndl); + + for (i = 0; i < ev->num_hndl; i++) { + struct hci_comp_blocks_info *info = &ev->handles[i]; + struct hci_conn *conn; + __u16 handle, block_count; + + handle = __le16_to_cpu(info->handle); + block_count = __le16_to_cpu(info->blocks); + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (!conn) + continue; + + conn->sent -= block_count; + + switch (conn->type) { + case ACL_LINK: + hdev->block_cnt += block_count; + if (hdev->block_cnt > hdev->num_blocks) + hdev->block_cnt = hdev->num_blocks; + break; + + default: + BT_ERR("Unknown type %d conn %p", conn->type, conn); + break; + } + } + + queue_work(hdev->workqueue, &hdev->tx_work); +} + static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_mode_change *ev = (void *) skb->data; @@ -3386,6 +3436,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_remote_oob_data_request_evt(hdev, skb); break; + case HCI_EV_NUM_COMP_BLOCKS: + hci_num_comp_blocks_evt(hdev, skb); + break; + default: BT_DBG("%s event 0x%x", hdev->name, event); break; -- cgit v1.2.3 From 6423cf3a1862d5b162aaa13543bf69216a9f6ac0 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 4 Jan 2012 12:10:41 +0100 Subject: Bluetooth: Fix sk_sndtimeo initialization for L2CAP socket sk_sndtime value should be specified in jiffies thus initial value needs to be converted from miliseconds. Otherwise this timeout is unreliable when CONFIG_HZ is not set to 1000. Signed-off-by: Andrzej Kaczmarek Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c61d967012b2..c57027f7606f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1002,7 +1002,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = l2cap_sock_destruct; - sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; + sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); sock_reset_flag(sk, SOCK_ZAPPED); -- cgit v1.2.3 From b83ddfe2ac670392c27a799371bb1a7e14a7e3d3 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 4 Jan 2012 12:10:42 +0100 Subject: Bluetooth: l2cap_set_timer needs jiffies as timeout value After moving L2CAP timers to workqueues l2cap_set_timer expects timeout value to be specified in jiffies but constants defined in miliseconds are used. This makes timeouts unreliable when CONFIG_HZ is not set to 1000. __set_chan_timer macro still uses jiffies as input to avoid multiple conversions from/to jiffies for sk_sndtimeo value which is already specified in jiffies. Signed-off-by: Andrzej Kaczmarek Ackec-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 6 +++--- net/bluetooth/l2cap_core.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 68f589150692..ab8f7d83079a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -626,13 +626,13 @@ static inline void l2cap_clear_timer(struct l2cap_chan *chan, #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ - L2CAP_DEFAULT_RETRANS_TO); + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ - L2CAP_DEFAULT_MONITOR_TO); + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ - L2CAP_DEFAULT_ACK_TO); + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index faf0b11ac1d3..e35ff4cd33ce 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2970,7 +2970,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; - __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -4478,7 +4479,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_ENC_TIMEOUT)); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); } else { @@ -4546,7 +4548,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) L2CAP_CONN_REQ, sizeof(req), &req); } else { __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); } } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -4566,7 +4569,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } } else { l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } -- cgit v1.2.3 From cc48dc0a996af6ae20e91c551d71e7f72768860f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 4 Jan 2012 16:42:26 +0200 Subject: Bluetooth: Remove magic number from ACL TO Adds HCI_ACL_TX_TIMEOUT and clear conversion from msec to jiffies Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6a9d316fb977..4202c9cb497e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -130,6 +130,7 @@ enum { #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ #define HCI_CMD_TIMEOUT (1000) /* 1 seconds */ +#define HCI_ACL_TX_TIMEOUT (45000) /* 45 seconds */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 546a42941477..f84935e5cbab 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2350,7 +2350,8 @@ static inline void hci_sched_acl(struct hci_dev *hdev) if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45)) + if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) hci_link_tx_to(hdev, ACL_LINK); } -- cgit v1.2.3 From 010666a126fce7b9ecdda7209c558db21d771c56 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:07 +0100 Subject: Bluetooth: Make hci-destruct callback optional Several drivers already provide an empty callback so we can actually make this optional and then remove all those empty callbacks in the drivers. This callback isn't needed at all by most drivers as they can remove their allocated structures on device disconnect and not on hci destruction. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 6 ++++-- net/bluetooth/hci_core.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 25a6c3fd7d1a..86c74cc563ff 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -595,8 +595,10 @@ static inline void hci_conn_put(struct hci_conn *conn) /* ----- HCI Devices ----- */ static inline void __hci_dev_put(struct hci_dev *d) { - if (atomic_dec_and_test(&d->refcnt)) - d->destruct(d); + if (atomic_dec_and_test(&d->refcnt)) { + if (d->destruct) + d->destruct(d); + } } /* diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f84935e5cbab..f23e32a645c8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1551,7 +1551,7 @@ int hci_register_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name, hdev->bus, hdev->owner); - if (!hdev->open || !hdev->close || !hdev->destruct) + if (!hdev->open || !hdev->close) return -EINVAL; /* Do not allow HCI_AMP devices to register at index 0, -- cgit v1.2.3 From 46e06531a5ae13c66f774d3cb1ad78385618a5a2 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:21 +0100 Subject: Bluetooth: Correctly acquire module ref We provide a device-object to other subsystems and we provide our own release-function. Therefore, the device-object must own a reference to our module, otherwise the release-function may get deleted before the device-object does. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 74b49e330a1d..ec03ee2b301e 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -372,6 +372,7 @@ static void bt_host_release(struct device *dev) { void *data = dev_get_drvdata(dev); kfree(data); + module_put(THIS_MODULE); } static struct device_type bt_host = { @@ -523,6 +524,7 @@ void hci_init_sysfs(struct hci_dev *hdev) dev->type = &bt_host; dev->class = bt_class; + __module_get(THIS_MODULE); dev_set_drvdata(dev, hdev); device_initialize(dev); } -- cgit v1.2.3 From e9b9cfa1575e37cb2dbb5534aeaaa16814228887 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:22 +0100 Subject: Bluetooth: Remove HCI-owner field After unregistering an hci_dev object a bluetooth driver does not have any callbacks in the hci_dev structure left over. Therefore, there is no need to keep a reference to the module. Previously, we needed this to protect the hci-destruct callback. However, this callback is no longer available so we do not need this owner field, anymore. Drivers now call hci_unregister_dev() and they are done with the object. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/bfusb.c | 2 -- drivers/bluetooth/bluecard_cs.c | 2 -- drivers/bluetooth/bpa10x.c | 2 -- drivers/bluetooth/bt3c_cs.c | 2 -- drivers/bluetooth/btmrvl_main.c | 1 - drivers/bluetooth/btsdio.c | 2 -- drivers/bluetooth/btuart_cs.c | 2 -- drivers/bluetooth/btusb.c | 2 -- drivers/bluetooth/btwilink.c | 1 - drivers/bluetooth/dtl1_cs.c | 2 -- drivers/bluetooth/hci_ldisc.c | 2 -- drivers/bluetooth/hci_vhci.c | 2 -- include/net/bluetooth/hci_core.h | 13 ++----------- net/bluetooth/hci_core.c | 3 +-- 14 files changed, 3 insertions(+), 35 deletions(-) (limited to 'net/bluetooth') diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index e99ce89e1cad..c7d6ff0ffcf1 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -705,8 +705,6 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i hdev->send = bfusb_send_frame; hdev->ioctl = bfusb_ioctl; - hdev->owner = THIS_MODULE; - if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 5cb325a13745..6b1261f9deb0 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -738,8 +738,6 @@ static int bluecard_open(bluecard_info_t *info) hdev->send = bluecard_hci_send_frame; hdev->ioctl = bluecard_hci_ioctl; - hdev->owner = THIS_MODULE; - id = inb(iobase + 0x30); if ((id & 0x0f) == 0x02) diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 29cd11d401e1..9d635148104c 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -470,8 +470,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * hdev->flush = bpa10x_flush; hdev->send = bpa10x_send_frame; - hdev->owner = THIS_MODULE; - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); err = hci_register_dev(hdev); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index e74334dfc776..0e304cb4bdea 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -584,8 +584,6 @@ static int bt3c_open(bt3c_info_t *info) hdev->send = bt3c_hci_send_frame; hdev->ioctl = bt3c_hci_ioctl; - hdev->owner = THIS_MODULE; - /* Load firmware */ err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev); if (err < 0) { diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 995cf43f4bd2..66b58fd09fbe 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -550,7 +550,6 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) hdev->flush = btmrvl_flush; hdev->send = btmrvl_send_frame; hdev->ioctl = btmrvl_ioctl; - hdev->owner = THIS_MODULE; btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index d38945cc9f05..2d6e4ed1637f 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -337,8 +337,6 @@ static int btsdio_probe(struct sdio_func *func, hdev->flush = btsdio_flush; hdev->send = btsdio_send_frame; - hdev->owner = THIS_MODULE; - err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 84e02f1a45b9..80ad2b9b352e 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -502,8 +502,6 @@ static int btuart_open(btuart_info_t *info) hdev->send = btuart_hci_send_frame; hdev->ioctl = btuart_hci_ioctl; - hdev->owner = THIS_MODULE; - spin_lock_irqsave(&(info->lock), flags); /* Reset UART */ diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 44b5e736ddc3..a36888a9c205 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -997,8 +997,6 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame; hdev->notify = btusb_notify; - hdev->owner = THIS_MODULE; - /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index da9cf6a6e8ac..b81b32e4fa12 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -317,7 +317,6 @@ static int bt_ti_probe(struct platform_device *pdev) hdev->close = ti_st_close; hdev->flush = NULL; hdev->send = ti_st_send_frame; - hdev->owner = THIS_MODULE; err = hci_register_dev(hdev); if (err < 0) { diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index aae40caaa188..295cf1b4a052 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -484,8 +484,6 @@ static int dtl1_open(dtl1_info_t *info) hdev->send = dtl1_hci_send_frame; hdev->ioctl = dtl1_hci_ioctl; - hdev->owner = THIS_MODULE; - spin_lock_irqsave(&(info->lock), flags); /* Reset UART */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 5ea49df3462b..459ff0ba5a42 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -392,8 +392,6 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->send = hci_uart_send_frame; hdev->parent = hu->tty->dev; - hdev->owner = THIS_MODULE; - if (!reset) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 44a801292d62..5f305c131a0d 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -244,8 +244,6 @@ static int vhci_open(struct inode *inode, struct file *file) hdev->flush = vhci_flush; hdev->send = vhci_send_frame; - hdev->owner = THIS_MODULE; - if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); kfree(data); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 935aca8783c4..99984688ccdd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -262,8 +262,6 @@ struct hci_dev { struct rfkill *rfkill; - struct module *owner; - unsigned long dev_flags; int (*open)(struct hci_dev *hdev); @@ -601,11 +599,7 @@ static inline void __hci_dev_put(struct hci_dev *d) * hci_dev_put and hci_dev_hold are macros to avoid dragging all the * overhead of all the modular infrastructure into this header. */ -#define hci_dev_put(d) \ -do { \ - __hci_dev_put(d); \ - module_put(d->owner); \ -} while (0) +#define hci_dev_put(d) __hci_dev_put(d) static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) { @@ -613,10 +607,7 @@ static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) return d; } -#define hci_dev_hold(d) \ -({ \ - try_module_get(d->owner) ? __hci_dev_hold(d) : NULL; \ -}) +#define hci_dev_hold(d) __hci_dev_hold(d) #define hci_dev_lock(d) mutex_lock(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f23e32a645c8..58392a6b48b5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1548,8 +1548,7 @@ int hci_register_dev(struct hci_dev *hdev) struct list_head *head = &hci_dev_list, *p; int i, id, error; - BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name, - hdev->bus, hdev->owner); + BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); if (!hdev->open || !hdev->close) return -EINVAL; -- cgit v1.2.3 From 4c724c7135ca2b407bd318b4267456a7b5723825 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:23 +0100 Subject: Bluetooth: Correctly take hci_dev->dev refcount The hci_dev->dev device structure has an internal refcount. This refcount is used to protect the whole hci_dev object. However, we currently do not use it. Therefore, if someone calls hci_free_dev() we currently immediately destroy the hci_dev object because we never took the device refcount. This even happens if the hci_dev->refcnt is not 0. In fact, the hci_dev->refcnt is totally useless in its current state. Therefore, we simply remove hci_dev->refcnt and instead use hci_dev->dev refcnt. This fixes all the symptoms and also correctly integrates the device structure into our bluetooth bus system. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 5 ++--- net/bluetooth/hci_core.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 99984688ccdd..4ccf3749a9a7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -129,7 +129,6 @@ struct adv_entry { struct hci_dev { struct list_head list; struct mutex lock; - atomic_t refcnt; char name[8]; unsigned long flags; @@ -592,7 +591,7 @@ static inline void hci_conn_put(struct hci_conn *conn) /* ----- HCI Devices ----- */ static inline void __hci_dev_put(struct hci_dev *d) { - atomic_dec(&d->refcnt); + put_device(&d->dev); } /* @@ -603,7 +602,7 @@ static inline void __hci_dev_put(struct hci_dev *d) static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) { - atomic_inc(&d->refcnt); + get_device(&d->dev); return d; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 58392a6b48b5..f5fba65a9e59 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1571,7 +1571,6 @@ int hci_register_dev(struct hci_dev *hdev) hdev->id = id; list_add_tail(&hdev->list, head); - atomic_set(&hdev->refcnt, 1); mutex_init(&hdev->lock); hdev->flags = 0; @@ -1655,6 +1654,7 @@ int hci_register_dev(struct hci_dev *hdev) schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); + __hci_dev_hold(hdev); return id; -- cgit v1.2.3 From dc946bd86f725c42c3ab1caf9966d29f5b364fea Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 7 Jan 2012 15:47:24 +0100 Subject: Bluetooth: Remove __hci_dev_put/hold Since we remove the owner field of hci_dev hci_dev_put and __hci_dev_put do the same so we can merge them into one function. Same for hci_dev_hold and __hci_dev_hold. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 4 ++-- include/net/bluetooth/hci_core.h | 12 ++---------- net/bluetooth/hci_core.c | 4 ++-- 3 files changed, 6 insertions(+), 14 deletions(-) (limited to 'net/bluetooth') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a36888a9c205..d7664ffc5183 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1079,7 +1079,7 @@ static void btusb_disconnect(struct usb_interface *intf) hdev = data->hdev; - __hci_dev_hold(hdev); + hci_dev_hold(hdev); usb_set_intfdata(data->intf, NULL); @@ -1093,7 +1093,7 @@ static void btusb_disconnect(struct usb_interface *intf) else if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); - __hci_dev_put(hdev); + hci_dev_put(hdev); hci_free_dev(hdev); kfree(data); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4ccf3749a9a7..f9c88251fe1a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -589,25 +589,17 @@ static inline void hci_conn_put(struct hci_conn *conn) } /* ----- HCI Devices ----- */ -static inline void __hci_dev_put(struct hci_dev *d) +static inline void hci_dev_put(struct hci_dev *d) { put_device(&d->dev); } -/* - * hci_dev_put and hci_dev_hold are macros to avoid dragging all the - * overhead of all the modular infrastructure into this header. - */ -#define hci_dev_put(d) __hci_dev_put(d) - -static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) +static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) { get_device(&d->dev); return d; } -#define hci_dev_hold(d) __hci_dev_hold(d) - #define hci_dev_lock(d) mutex_lock(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f5fba65a9e59..a3113f8c1f93 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1654,7 +1654,7 @@ int hci_register_dev(struct hci_dev *hdev) schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); - __hci_dev_hold(hdev); + hci_dev_hold(hdev); return id; @@ -1717,7 +1717,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); - __hci_dev_put(hdev); + hci_dev_put(hdev); } EXPORT_SYMBOL(hci_unregister_dev); -- cgit v1.2.3 From cbe8fed490601862310f035b9973509b8634998e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 8 Jan 2012 22:51:16 +0200 Subject: Bluetooth: Remove bogus inline declaration from l2cap_chan_connect As reported by Dan Carpenter this function causes a Sparse warning and shouldn't be declared inline: include/net/bluetooth/l2cap.h:837:30 error: marked inline, but without a definition" Reported-by: Dan Carpenter Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ab8f7d83079a..26486e182f55 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -834,7 +834,7 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); -inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e35ff4cd33ce..dcccae04ae08 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1120,7 +1120,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; -- cgit v1.2.3 From a8b2d5c2cfe1c6398e3fdd4372c4ae7f74fb4493 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 8 Jan 2012 23:11:15 +0200 Subject: Bluetooth: Move mgmt related flags from hdev->flags to hdev->dev_flags There's no point in exposing these to user-space (which is what happens to everything in hdev->flags) so move them to dev_flags instead. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 16 ++++++++-------- net/bluetooth/hci_core.c | 30 +++++++++++++++--------------- net/bluetooth/hci_event.c | 44 ++++++++++++++++++++++---------------------- net/bluetooth/mgmt.c | 30 +++++++++++++++--------------- net/bluetooth/smp.c | 2 +- 5 files changed, 61 insertions(+), 61 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4202c9cb497e..3ee39ed9c29b 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -77,14 +77,6 @@ enum { HCI_RAW, - HCI_SETUP, - HCI_AUTO_OFF, - HCI_MGMT, - HCI_PAIRABLE, - HCI_SERVICE_CACHE, - HCI_LINK_KEYS, - HCI_DEBUG_KEYS, - HCI_RESET, }; @@ -93,6 +85,14 @@ enum { * states from the controller. */ enum { + HCI_SETUP, + HCI_AUTO_OFF, + HCI_MGMT, + HCI_PAIRABLE, + HCI_SERVICE_CACHE, + HCI_LINK_KEYS, + HCI_DEBUG_KEYS, + HCI_LE_SCAN, }; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a3113f8c1f93..3acb23cf6ee4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -668,7 +668,7 @@ int hci_dev_open(__u16 dev) hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); - if (!test_bit(HCI_SETUP, &hdev->flags)) { + if (!test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_powered(hdev, 1); hci_dev_unlock(hdev); @@ -722,10 +722,10 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->discov_timeout = 0; } - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work(&hdev->power_off); - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); hci_dev_lock(hdev); @@ -947,11 +947,11 @@ int hci_get_dev_list(void __user *arg) read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work(&hdev->power_off); - if (!test_bit(HCI_MGMT, &hdev->flags)) - set_bit(HCI_PAIRABLE, &hdev->flags); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); (dr + n)->dev_id = hdev->id; (dr + n)->dev_opt = hdev->flags; @@ -983,11 +983,11 @@ int hci_get_dev_info(void __user *arg) if (!hdev) return -ENODEV; - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work_sync(&hdev->power_off); - if (!test_bit(HCI_MGMT, &hdev->flags)) - set_bit(HCI_PAIRABLE, &hdev->flags); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; @@ -1067,11 +1067,11 @@ static void hci_power_on(struct work_struct *work) if (hci_dev_open(hdev->id) < 0) return; - if (test_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) schedule_delayed_work(&hdev->power_off, msecs_to_jiffies(AUTO_OFF_TIMEOUT)); - if (test_and_clear_bit(HCI_SETUP, &hdev->flags)) + if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) mgmt_index_added(hdev); } @@ -1082,7 +1082,7 @@ static void hci_power_off(struct work_struct *work) BT_DBG("%s", hdev->name); - clear_bit(HCI_AUTO_OFF, &hdev->flags); + clear_bit(HCI_AUTO_OFF, &hdev->dev_flags); hci_dev_close(hdev->id); } @@ -1649,8 +1649,8 @@ int hci_register_dev(struct hci_dev *hdev) } } - set_bit(HCI_AUTO_OFF, &hdev->flags); - set_bit(HCI_SETUP, &hdev->flags); + set_bit(HCI_AUTO_OFF, &hdev->dev_flags); + set_bit(HCI_SETUP, &hdev->dev_flags); schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); @@ -1686,7 +1686,7 @@ void hci_unregister_dev(struct hci_dev *hdev) kfree_skb(hdev->reassembly[i]); if (!test_bit(HCI_INIT, &hdev->flags) && - !test_bit(HCI_SETUP, &hdev->flags)) { + !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0466ed9c1b47..2d39ede1f202 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -211,7 +211,7 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_set_local_name_complete(hdev, sent, status); if (status == 0) @@ -890,7 +890,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); if (rp->status != 0) @@ -916,7 +916,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -951,7 +951,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -967,7 +967,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -982,7 +982,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -998,7 +998,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr, rp->status); @@ -1110,7 +1110,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) hci_req_complete(hdev, HCI_OP_INQUIRY, status); hci_conn_check_pending(hdev); hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_start_discovery_failed(hdev, status); hci_dev_unlock(hdev); return; @@ -1333,7 +1333,7 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) hci_resolve_next_name(hdev, &cp->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); @@ -1555,7 +1555,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) return; - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) return; hci_dev_lock(hdev); @@ -1876,7 +1876,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) { + if (test_bit(HCI_MGMT, &hdev->dev_flags)) { if (ev->status == 0) mgmt_remote_name(hdev, &ev->bdaddr, ev->name); @@ -2505,10 +2505,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff hci_conn_put(conn); } - if (!test_bit(HCI_PAIRABLE, &hdev->flags)) + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags)) hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - else if (test_bit(HCI_MGMT, &hdev->flags)) { + else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { u8 secure; if (conn->pending_sec_level == BT_SECURITY_HIGH) @@ -2532,7 +2532,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s", hdev->name); - if (!test_bit(HCI_LINK_KEYS, &hdev->flags)) + if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags)) return; hci_dev_lock(hdev); @@ -2547,7 +2547,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s found key type %u for %s", hdev->name, key->type, batostr(&ev->bdaddr)); - if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && + if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) && key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; @@ -2609,7 +2609,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff hci_conn_put(conn); } - if (test_bit(HCI_LINK_KEYS, &hdev->flags)) + if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags)) hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, ev->key_type, pin_len); @@ -2890,7 +2890,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.rssi = info->rssi; data.ssp_mode = 0x01; - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) name_known = eir_has_complete_name(info->data, sizeof(info->data)); else @@ -2939,10 +2939,10 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff hci_conn_hold(conn); - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; - if (test_bit(HCI_PAIRABLE, &hdev->flags) || + if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; @@ -3005,7 +3005,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); @@ -3071,7 +3071,7 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) + if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_request(hdev, &ev->bdaddr); hci_dev_unlock(hdev); @@ -3130,7 +3130,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); - if (!test_bit(HCI_MGMT, &hdev->flags)) + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; data = hci_find_remote_oob_data(hdev, &ev->bdaddr); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 295cfc8a3076..3de1e909471a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -226,10 +226,10 @@ static int read_index_list(struct sock *sk) i = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags)) cancel_delayed_work(&d->power_off); - if (test_bit(HCI_SETUP, &d->flags)) + if (test_bit(HCI_SETUP, &d->dev_flags)) continue; put_unaligned_le16(d->id, &rp->index[i++]); @@ -285,7 +285,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_ISCAN, &hdev->flags)) settings |= MGMT_SETTING_DISCOVERABLE; - if (test_bit(HCI_PAIRABLE, &hdev->flags)) + if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_PAIRABLE; if (!(hdev->features[4] & LMP_NO_BREDR)) @@ -419,7 +419,7 @@ static int update_eir(struct hci_dev *hdev) if (hdev->ssp_mode == 0) return 0; - if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return 0; memset(&cp, 0, sizeof(cp)); @@ -451,7 +451,7 @@ static int update_class(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return 0; cod[0] = hdev->minor_class; @@ -469,7 +469,7 @@ static void service_cache_off(struct work_struct *work) struct hci_dev *hdev = container_of(work, struct hci_dev, service_cache.work); - if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return; hci_dev_lock(hdev); @@ -482,10 +482,10 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct hci_dev *hdev) { - if (!test_and_set_bit(HCI_MGMT, &hdev->flags)) + if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); - if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) schedule_delayed_work(&hdev->service_cache, msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); } @@ -502,7 +502,7 @@ static int read_controller_info(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_INFO, MGMT_STATUS_INVALID_PARAMS); - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work_sync(&hdev->power_off); hci_dev_lock(hdev); @@ -851,9 +851,9 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, hci_dev_lock(hdev); if (cp->val) - set_bit(HCI_PAIRABLE, &hdev->flags); + set_bit(HCI_PAIRABLE, &hdev->dev_flags); else - clear_bit(HCI_PAIRABLE, &hdev->flags); + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); if (err < 0) @@ -1008,7 +1008,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, hdev->major_class = cp->major; hdev->minor_class = cp->minor; - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) { + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { hci_dev_unlock(hdev); cancel_delayed_work_sync(&hdev->service_cache); hci_dev_lock(hdev); @@ -1063,12 +1063,12 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, hci_link_keys_clear(hdev); - set_bit(HCI_LINK_KEYS, &hdev->flags); + set_bit(HCI_LINK_KEYS, &hdev->dev_flags); if (cp->debug_keys) - set_bit(HCI_DEBUG_KEYS, &hdev->flags); + set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); else - clear_bit(HCI_DEBUG_KEYS, &hdev->flags); + clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 32c47de30344..65a90242d990 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -217,7 +217,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, { u8 dist_keys = 0; - if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) { + if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { dist_keys = SMP_DIST_ENC_KEY; authreq |= SMP_AUTH_BONDING; } else { -- cgit v1.2.3 From 44b5f7d0cb1939497a0858d9f43d89f039f85887 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 8 Jan 2012 23:39:40 +0200 Subject: Bluetooth: Fix resetting HCI_MGMT flag The HCI_MGMT flag should not be cleared when resetting a HCI device. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2d39ede1f202..f3dafae6e1db 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -195,7 +195,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); - hdev->dev_flags = 0; + /* Reset all flags, except persistent ones like HCI_MGMT */ + hdev->dev_flags &= BIT(HCI_MGMT); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From a3d4e20a88f54571d794cca365f232bfed0669bb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 9 Jan 2012 00:53:02 +0200 Subject: Bluetooth: Sort to-be-resolved devices by RSSI during discovery This patch makes sure that devices with stronger signal (RSSI closer to 0) are sorted first in the resolve list and will therefore get their names resolved first during device discovery. Since it's more likely that the device the user is trying to discover has a strong signal due to its proximity this ensures that the user gets the "device found" event for it more quickly. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 28 +++++++++++++++++++++++++++- net/bluetooth/mgmt.c | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f9c88251fe1a..59e3541e9fc7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -395,6 +395,8 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, bdaddr_t *bdaddr, int state); +void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, + struct inquiry_entry *ie); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3acb23cf6ee4..9963121028e4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -457,6 +457,25 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, return NULL; } +void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, + struct inquiry_entry *ie) +{ + struct discovery_state *cache = &hdev->discovery; + struct list_head *pos = &cache->resolve; + struct inquiry_entry *p; + + list_del(&ie->list); + + list_for_each_entry(p, &cache->resolve, list) { + if (p->name_state != NAME_PENDING && + abs(p->data.rssi) >= abs(ie->data.rssi)) + break; + pos = &p->list; + } + + list_add(&ie->list, pos); +} + bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known) { @@ -466,8 +485,15 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); - if (ie) + if (ie) { + if (ie->name_state == NAME_NEEDED && + data->rssi != ie->data.rssi) { + ie->data.rssi = data->rssi; + hci_inquiry_cache_update_resolve(hdev, ie); + } + goto update; + } /* Entry not in the cache. Add new one. */ ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3de1e909471a..2dae2e8f6234 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2043,7 +2043,7 @@ static int confirm_name(struct sock *sk, u16 index, unsigned char *data, list_del(&e->list); } else { e->name_state = NAME_NEEDED; - list_move(&e->list, &hdev->discovery.resolve); + hci_inquiry_cache_update_resolve(hdev, e); } err = 0; -- cgit v1.2.3 From 8b281b9c7820b054d15cf471c418fd884cbbec78 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 10 Jan 2012 18:33:50 -0200 Subject: Bluetooth: Fix 'enable_hs' type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following build warning: CC [M] net/bluetooth/hci_core.o net/bluetooth/hci_core.c: In function ‘__check_enable_hs’: net/bluetooth/hci_core.c:2587: warning: return from incompatible pointer type module_param in hci_core.c passes 'enable_hs' as bool format, so fix this variable definition type. Signed-off-by: Fabio Estevam Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 2 +- net/bluetooth/hci_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3ee39ed9c29b..84993073c2f1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1415,6 +1415,6 @@ struct hci_inquiry_req { }; #define IREQ_CACHE_FLUSH 0x0001 -extern int enable_hs; +extern bool enable_hs; #endif /* __HCI_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9963121028e4..91166dbbe35c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -55,7 +55,7 @@ #define AUTO_OFF_TIMEOUT 2000 -int enable_hs; +bool enable_hs; static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); -- cgit v1.2.3 From 0ef3ef0f676e3c7aaab4a936635f503770fd38b2 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:46 +0100 Subject: Bluetooth: Set P-bit for SREJ frame only if there are I-frames to ack SREJ frame with P-bit set acknowledges I-frames numbered up to (ReqSeq - 1). With this patch P-bit in SREJ is set only when there are some I-frames to ack. This fixes ambiguous situation when lost of I-frame with TxSeq=0 would result in sending SREJ acking all previous I-frames. Consider following scenario: TxWindow=3 HostA: sent I-frame TxSeq=0 HostA: sent I-frame TxSeq=1 HostA: sent I-frame TxSeq=2 HostB: missed I-frame TxSeq=0 HostB: received I-frame TxSeq=1 HostB: sent SREJ ReqSeq=0 Pbit=1 HostA: received SREJ ReqSeq=0 Pbit=1 <- All I-frames acked or not? ... Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index dcccae04ae08..0d5bb45e7be7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3927,15 +3927,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont __skb_queue_head_init(&chan->srej_q); l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); - set_bit(CONN_SEND_PBIT, &chan->conn_state); + /* Set P-bit only if there are some I-frames to ack. */ + if (__clear_ack_timer(chan)) + set_bit(CONN_SEND_PBIT, &chan->conn_state); err = l2cap_send_srejframe(chan, tx_seq); if (err < 0) { l2cap_send_disconn_req(chan->conn, chan, -err); return err; } - - __clear_ack_timer(chan); } return 0; -- cgit v1.2.3 From b17e73bb4269f47e1ea2d64a834f1cfc8644fabb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:47 +0100 Subject: Bluetooth: Clear ack_timer when sending ack ack_timer should be cleared when sending ACK to avoid acking I-frames twice. This commit introduces helper function (only send ack, not clearing timer) which is used by l2cap_send_ack and l2cap_ack_timeout. This is to avoid clearing ack timer in timer function. Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0d5bb45e7be7..3b9e2813f1fc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1478,7 +1478,7 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan) return ret; } -static void l2cap_send_ack(struct l2cap_chan *chan) +static void __l2cap_send_ack(struct l2cap_chan *chan) { u32 control = 0; @@ -1498,6 +1498,12 @@ static void l2cap_send_ack(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } +static void l2cap_send_ack(struct l2cap_chan *chan) +{ + __clear_ack_timer(chan); + __l2cap_send_ack(chan); +} + static void l2cap_send_srejtail(struct l2cap_chan *chan) { struct srej_list *tail; @@ -1988,7 +1994,7 @@ static void l2cap_ack_timeout(struct work_struct *work) BT_DBG("chan %p", chan); lock_sock(chan->sk); - l2cap_send_ack(chan); + __l2cap_send_ack(chan); release_sock(chan->sk); } -- cgit v1.2.3 From 77f918bc7babb8473933ca0a6deefc64fe24b06c Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:48 +0100 Subject: Bluetooth: Don't send RNR immediately when entering local busy There is no need to send RNR immediately when entring local busy. Also upper layer might clear local busy condition before ack timer expires saving few cycles for sending RNR. This also prevents sending two RNRs in some cases where sending one would be enough i.e received N I-frame can trigger local busy (sending RNR acking up to N-1 I-frame) and later sending ack (RNR acking up to N I-frame). This was affecting TC_ERM_BV_07_C and TC_ERM_BV_22_C with some non default channel parameters (tx window and receiving buffer sizes). Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3b9e2813f1fc..778ceb2b8402 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3719,19 +3719,11 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) { - u32 control; - BT_DBG("chan %p, Enter local busy", chan); set_bit(CONN_LOCAL_BUSY, &chan->conn_state); - control = __set_reqseq(chan, chan->buffer_seq); - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); - l2cap_send_sframe(chan, control); - - set_bit(CONN_RNR_SENT, &chan->conn_state); - - __clear_ack_timer(chan); + __set_ack_timer(chan); } static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) @@ -3871,8 +3863,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont goto drop; } - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) + l2cap_send_ack(chan); goto drop; + } if (tx_seq == chan->expected_tx_seq) goto expected; -- cgit v1.2.3 From 09bfb2ee52a66845bbefad0b6eaeae1b5adea949 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 11 Jan 2012 10:59:49 +0100 Subject: Bluetooth: Drop L2CAP chan reference if ERTM ack_timer fired Reference counter was incremented when starting ack timer but decremented only when clearing timer, not when timer fired. Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 778ceb2b8402..6773453927ef 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1996,6 +1996,8 @@ static void l2cap_ack_timeout(struct work_struct *work) lock_sock(chan->sk); __l2cap_send_ack(chan); release_sock(chan->sk); + + l2cap_chan_put(chan); } static inline void l2cap_ertm_init(struct l2cap_chan *chan) -- cgit v1.2.3 From 5ef8cb9e5b5012a373f48e1e336339864b4c1303 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 13 Jan 2012 17:21:42 +0200 Subject: Bluetooth: Use chan instead of sk Remove unneeded conversion from sk to chan. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6773453927ef..22319377eb20 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -73,7 +73,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); -static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); +static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb); /* ---- L2CAP channels ---- */ @@ -4138,9 +4138,8 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont return 0; } -static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) +int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; u32 control; u16 req_seq; int len, next_tx_seq_offset, req_seq_offset; @@ -4241,7 +4240,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk break; case L2CAP_MODE_ERTM: - l2cap_ertm_data_rcv(sk, skb); + l2cap_ertm_data_rcv(chan, skb); goto done; -- cgit v1.2.3 From 0952a57a25ee9854e1bf21e333b9fd3de211760e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 13 Jan 2012 17:21:43 +0200 Subject: Bluetooth: Change sk to l2cap_chan Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 22319377eb20..a66e5ec9adef 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1518,9 +1518,10 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } -static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) +static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1578,7 +1579,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); put_unaligned_le16(chan->psm, skb_put(skb, 2)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1611,7 +1612,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); @@ -1661,7 +1662,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); - err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { kfree_skb(skb); return ERR_PTR(err); -- cgit v1.2.3 From 7d262f86f6b73efb500be9d9242ef0673221493d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 10 Jan 2012 18:20:49 -0300 Subject: Bluetooth: Add 'eir_len' param to mgmt_device_found() This patch adds a new parameter to mgmt_device_found() to inform the length of 'eir' pointer. EIR data from LE advertising report event doesn't have a fixed length as EIR data from extended inquiry result event does. We needed to change mgmt_device_found() so it copies 'eir_len' bytes instead of HCI_MAX_EIR_LENGTH. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_event.c | 10 ++++++---- net/bluetooth/mgmt.c | 7 +++++-- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 59e3541e9fc7..393acd071cb6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -925,7 +925,7 @@ 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 cfm_name, u8 *eir); + u8 cfm_name, u8 *eir, u8 eir_len); 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); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f3dafae6e1db..3323dc6c9868 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1608,7 +1608,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * name_known = hci_inquiry_cache_update(hdev, &data, false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, NULL); + info->dev_class, 0, !name_known, + NULL, 0); } hci_dev_unlock(hdev); @@ -2705,7 +2706,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL); + !name_known, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2723,7 +2724,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct false); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL); + !name_known, NULL, 0); } } @@ -2900,7 +2901,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct name_known = hci_inquiry_cache_update(hdev, &data, name_known); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, info->data); + !name_known, info->data, + sizeof(info->data)); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2dae2e8f6234..e7bbad80fa7e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2780,10 +2780,13 @@ 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 cfm_name, u8 *eir) + u8 cfm_name, u8 *eir, u8 eir_len) { struct mgmt_ev_device_found ev; + if (eir_len > sizeof(ev.eir)) + return -EINVAL; + memset(&ev, 0, sizeof(ev)); bacpy(&ev.addr.bdaddr, bdaddr); @@ -2792,7 +2795,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev.confirm_name = cfm_name; if (eir) - memcpy(ev.eir, eir, sizeof(ev.eir)); + memcpy(ev.eir, eir, eir_len); if (dev_class) memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); -- cgit v1.2.3 From 3c9e919511f87f10491628c6b44bc4675822f307 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 10 Jan 2012 18:20:50 -0300 Subject: Bluetooth: Report LE devices Devices found during LE scan should be reported to userspace through mgmt_device_found events. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3323dc6c9868..42d63522270f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3208,6 +3208,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, { u8 num_reports = skb->data[0]; void *ptr = &skb->data[1]; + s8 rssi; hci_dev_lock(hdev); @@ -3216,6 +3217,10 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, hci_add_adv_entry(hdev, ev); + rssi = ev->data[ev->length]; + mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, + NULL, rssi, 0, ev->data, ev->length); + ptr += sizeof(*ev) + ev->length + 1; } -- cgit v1.2.3 From 7005ff1780ca7ad5ed2ec710ad35affc48362ebf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Jan 2012 16:14:43 +0200 Subject: Bluetooth: Fix clearing persistent flags There are several other dev_flags besided HCI_MGMT that should not be cleared upon reset. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 42d63522270f..54132a909ea5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -195,8 +195,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); - /* Reset all flags, except persistent ones like HCI_MGMT */ - hdev->dev_flags &= BIT(HCI_MGMT); + /* Reset all flags, except persistent ones */ + hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From afc747a600ff2e3a4eef8f312fc766608a1360e2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 18:11:07 +0200 Subject: Bluetooth: Rename mgmt connected events to match user space User space uses device_(dis)connected instead of just (dis)connected so rename the defines and functions to match this. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 12 +++++++----- 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 393acd071cb6..f3fbfd6f6c3b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -896,10 +896,10 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent); -int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type); -int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, +int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); +int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index be65d3417883..d1d13dc0cca8 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -328,9 +328,9 @@ struct mgmt_ev_new_link_key { struct mgmt_link_key_info key; } __packed; -#define MGMT_EV_CONNECTED 0x000A +#define MGMT_EV_DEVICE_CONNECTED 0x000A -#define MGMT_EV_DISCONNECTED 0x000B +#define MGMT_EV_DEVICE_DISCONNECTED 0x000B #define MGMT_EV_CONNECT_FAILED 0x000C struct mgmt_ev_connect_failed { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 54132a909ea5..e13ce945afc4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1643,7 +1643,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->state = BT_CONFIG; hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; - mgmt_connected(hdev, &ev->bdaddr, conn->type, + mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); } else conn->state = BT_CONNECTED; @@ -1789,7 +1789,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (ev->status != 0) mgmt_disconnect_failed(hdev, &conn->dst, ev->status); else - mgmt_disconnected(hdev, &conn->dst, conn->type, + mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type); } @@ -3188,7 +3188,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); + mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e7bbad80fa7e..c8042c6e2b46 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2464,7 +2464,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } -int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, +int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type) { struct mgmt_addr_info ev; @@ -2472,7 +2472,8 @@ int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev.bdaddr, bdaddr); ev.type = link_to_mgmt(link_type, addr_type); - return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, &ev, sizeof(ev), + NULL); } static void disconnect_rsp(struct pending_cmd *cmd, void *data) @@ -2509,8 +2510,8 @@ static void remove_keys_rsp(struct pending_cmd *cmd, void *data) mgmt_pending_remove(cmd); } -int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type) +int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type) { struct mgmt_addr_info ev; struct sock *sk = NULL; @@ -2521,7 +2522,8 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, bacpy(&ev.bdaddr, bdaddr); ev.type = link_to_mgmt(link_type, addr_type); - err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk); + err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), + sk); if (sk) sock_put(sk); -- cgit v1.2.3 From e319d2e74378660c5e09a1b8703663ba97f0f62a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 19:51:59 +0200 Subject: Bluetooth: Add eir_len parameter to mgmt_ev_device_found This patch add a two byte eir_len parameter mgmt_ev_device_found. Since it's unlikely that the data will in the short term be much bigger than conventional EIR lengths just use a small stack based buffer for now to avoid dynamic memory allocation & freeing. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- include/net/bluetooth/mgmt.h | 3 ++- net/bluetooth/mgmt.c | 28 +++++++++++++++------------- 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f3fbfd6f6c3b..33dff8ef2e08 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -925,7 +925,7 @@ 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 cfm_name, u8 *eir, u8 eir_len); + u8 cfm_name, u8 *eir, u16 eir_len); 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); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index d1d13dc0cca8..4f166c834ddb 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -368,7 +368,8 @@ struct mgmt_ev_device_found { __u8 dev_class[3]; __s8 rssi; __u8 confirm_name; - __u8 eir[HCI_MAX_EIR_LENGTH]; + __le16 eir_len; + __u8 eir[0]; } __packed; #define MGMT_EV_REMOTE_NAME 0x0012 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c8042c6e2b46..b7e7fdfaee38 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2782,27 +2782,29 @@ 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 cfm_name, u8 *eir, u8 eir_len) + u8 cfm_name, u8 *eir, u16 eir_len) { - struct mgmt_ev_device_found ev; + char buf[512]; + struct mgmt_ev_device_found *ev = (void *) buf; + size_t ev_size = sizeof(*ev) + eir_len; - if (eir_len > sizeof(ev.eir)) + if (ev_size > sizeof(buf)) return -EINVAL; - memset(&ev, 0, sizeof(ev)); + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->rssi = rssi; + ev->confirm_name = cfm_name; - 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, eir_len); + if (eir_len > 0) { + put_unaligned_le16(eir_len, &ev->eir_len); + memcpy(ev->eir, eir, eir_len); + } if (dev_class) - memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); + memcpy(ev->dev_class, dev_class, sizeof(ev->dev_class)); - return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name) -- cgit v1.2.3 From 4ddb1930f91b7395a760cd4a8cf1b2a87011571c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 20:04:43 +0200 Subject: Bluetooth: Rename eir_has_complete_name to eir_has_data_type This allows for other uses such as checking for an embedded class of device value in order to decide whether to append the class or not. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e13ce945afc4..d256042a83cf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2842,7 +2842,7 @@ 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) +static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) { u8 field_len; size_t parsed; @@ -2858,7 +2858,7 @@ static inline bool eir_has_complete_name(u8 *data, size_t data_len) if (parsed > data_len) break; - if (data[1] == EIR_NAME_COMPLETE) + if (data[1] == type) return true; data += field_len + 1; @@ -2893,8 +2893,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.ssp_mode = 0x01; if (test_bit(HCI_MGMT, &hdev->dev_flags)) - name_known = eir_has_complete_name(info->data, - sizeof(info->data)); + name_known = eir_has_data_type(info->data, + sizeof(info->data), + EIR_NAME_COMPLETE); else name_known = true; -- cgit v1.2.3 From 6759a67579a927f2a92f398cf67555e6cc92d0ff Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 20:51:14 +0200 Subject: Bluetooth: Move eir_has_data_field to hci_core.h This makes the function accessible from all places it's needed (e.g. mgmt.c and hci_event.c). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 25 +++++++++++++++++++++++++ net/bluetooth/hci_event.c | 25 ------------------------- 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 33dff8ef2e08..393bb73fc999 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -868,6 +868,31 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, read_unlock(&hci_cb_list_lock); } +static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) +{ + 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] == type) + return true; + + data += field_len + 1; + } + + return false; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d256042a83cf..e93afebdcf84 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2842,31 +2842,6 @@ 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_data_type(u8 *data, size_t data_len, u8 type) -{ - 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] == type) - 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; -- cgit v1.2.3 From 1dc06093a9f353ef19b7b5180602884d0ce065c5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Jan 2012 21:01:23 +0200 Subject: Bluetooth: Merge device class into the EIR data in mgmt_ev_device_found There's no need to have a separate device class field since the same information can be encoded into the EIR data. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 11 +++++++++++ include/net/bluetooth/mgmt.h | 1 - net/bluetooth/mgmt.c | 20 +++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 393bb73fc999..a0311018a4d0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -893,6 +893,17 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, + u8 data_len) +{ + eir[eir_len++] = sizeof(type) + data_len; + eir[eir_len++] = type; + memcpy(&eir[eir_len], data, data_len); + eir_len += data_len; + + return eir_len; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4f166c834ddb..bdace523b910 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -365,7 +365,6 @@ struct mgmt_ev_auth_failed { #define MGMT_EV_DEVICE_FOUND 0x0011 struct mgmt_ev_device_found { struct mgmt_addr_info addr; - __u8 dev_class[3]; __s8 rssi; __u8 confirm_name; __le16 eir_len; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b7e7fdfaee38..bec64c98b6a9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2786,23 +2786,29 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; - size_t ev_size = sizeof(*ev) + eir_len; + size_t ev_size; - if (ev_size > sizeof(buf)) + /* Leave 5 bytes for a potential CoD field */ + if (sizeof(*ev) + eir_len + 5 > sizeof(buf)) return -EINVAL; + memset(buf, 0, sizeof(buf)); + 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_len > 0) { - put_unaligned_le16(eir_len, &ev->eir_len); + if (eir_len > 0) memcpy(ev->eir, eir, eir_len); - } - if (dev_class) - memcpy(ev->dev_class, dev_class, sizeof(ev->dev_class)); + if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV)) + eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, + dev_class, 3); + + put_unaligned_le16(eir_len, &ev->eir_len); + + ev_size = sizeof(*ev) + eir_len; return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } -- cgit v1.2.3 From 51a8efd7d02c13cb1c6fdd1cd66788792a3fcc7c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jan 2012 06:10:31 +0200 Subject: Bluetooth: Rename conn->pend to conn->flags These flags can and will be used for more general purpose values than just pending state transitions so the more common name "flags" makes more sense than "pend". Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_conn.c | 20 ++++++++++---------- net/bluetooth/hci_event.c | 36 ++++++++++++++++++------------------ net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/smp.c | 19 +++++++++---------- 5 files changed, 41 insertions(+), 42 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a0311018a4d0..0938168ce602 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -300,7 +300,7 @@ struct hci_conn { __u8 io_capability; __u8 power_save; __u16 disc_timeout; - unsigned long pend; + unsigned long flags; __u8 remote_cap; __u8 remote_oob; @@ -764,7 +764,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) if (conn->type != ACL_LINK && conn->type != LE_LINK) return; - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; @@ -805,7 +805,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) hci_proto_auth_cfm(conn, status); - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3db432473ad5..8a4678a2c982 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -337,7 +337,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn) hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { struct hci_cp_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); @@ -589,9 +589,9 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 acl->power_save = 1; hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); - if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) { + if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { /* defer SCO setup until mode change completed */ - set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend); + set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags); return sco; } @@ -633,13 +633,13 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) conn->auth_type = auth_type; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); if (conn->key_type != 0xff) - set_bit(HCI_CONN_REAUTH_PEND, &conn->pend); + set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); } return 0; @@ -650,7 +650,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 0x01; @@ -700,7 +700,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) goto encrypt; auth: - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return 0; if (!hci_conn_auth(conn, sec_level, auth_type)) @@ -735,7 +735,7 @@ int hci_conn_change_link_key(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_change_conn_link_key cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, @@ -754,7 +754,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) if (!role && conn->link_mode & HCI_LM_MASTER) return 1; - if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { struct hci_cp_switch_role cp; bacpy(&cp.bdaddr, &conn->dst); cp.role = role; @@ -781,7 +781,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (!conn->power_save && !force_active) goto timer; - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { struct hci_cp_exit_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e93afebdcf84..d9a8618ae156 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1344,7 +1344,7 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -1461,9 +1461,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) hci_sco_setup(conn, status); } @@ -1488,9 +1488,9 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) hci_sco_setup(conn, status); } @@ -1817,7 +1817,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!ev->status) { if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) && - test_bit(HCI_CONN_REAUTH_PEND, &conn->pend)) { + test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { conn->link_mode |= HCI_LM_AUTH; @@ -1827,8 +1827,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s mgmt_auth_failed(hdev, &conn->dst, ev->status); } - clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); - clear_bit(HCI_CONN_REAUTH_PEND, &conn->pend); + clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); + clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { @@ -1850,7 +1850,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_conn_put(conn); } - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; @@ -1858,7 +1858,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); hci_encrypt_cfm(conn, ev->status, 0x00); } } @@ -1892,7 +1892,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -1923,7 +1923,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * conn->link_mode &= ~HCI_LM_ENCRYPT; } - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); if (conn->state == BT_CONFIG) { if (!ev->status) @@ -1952,7 +1952,7 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct if (!ev->status) conn->link_mode |= HCI_LM_SECURE; - clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); + clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); hci_key_change_cfm(conn, ev->status); } @@ -2336,7 +2336,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb conn->link_mode |= HCI_LM_MASTER; } - clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend); + clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); hci_role_switch_cfm(conn, ev->status, ev->role); } @@ -2474,14 +2474,14 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb conn->mode = ev->mode; conn->interval = __le16_to_cpu(ev->interval); - if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { if (conn->mode == HCI_CM_ACTIVE) conn->power_save = 1; else conn->power_save = 0; } - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) hci_sco_setup(conn, ev->status); } @@ -3013,7 +3013,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If we're not the initiators request authorization to * proceed from user space (mgmt_user_confirm with * confirm_hint set to 1). */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { BT_DBG("Confirming auto-accept as acceptor"); confirm_hint = 1; goto confirm; @@ -3074,7 +3074,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * initiated the authentication. A traditional auth_complete * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0) + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) mgmt_auth_failed(hdev, &conn->dst, ev->status); hci_conn_put(conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a66e5ec9adef..27b72d954436 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1020,7 +1020,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) __cancel_delayed_work(&conn->info_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { __cancel_delayed_work(&conn->security_timer); smp_chan_destroy(conn); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 65a90242d990..e08fe6c9c9c9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -261,7 +261,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); @@ -449,7 +449,7 @@ static void random_work(struct work_struct *work) memset(stk + smp->smp_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) { + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; goto error; } @@ -506,7 +506,7 @@ void smp_chan_destroy(struct l2cap_conn *conn) { struct smp_chan *smp = conn->smp_chan; - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); if (smp->tfm) crypto_free_blkcipher(smp->tfm); @@ -571,7 +571,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) + if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp = smp_chan_create(conn); smp = conn->smp_chan; @@ -707,8 +707,7 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn) if (!key) return 0; - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, - &hcon->pend)) + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; master = (void *) key->data; @@ -733,7 +732,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (smp_ltk_encrypt(conn)) return 0; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) + if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); @@ -772,7 +771,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) if (smp_ltk_encrypt(conn)) goto done; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) + if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; smp = smp_chan_create(conn); @@ -908,7 +907,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) BT_DBG("conn %p force %d", conn, force); - if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) + if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) return 0; rsp = (void *) &smp->prsp[1]; @@ -982,7 +981,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) } if (conn->hcon->out || force) { - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } -- cgit v1.2.3 From a0c808b373e89aecc3ecae4cbdcdeff68aa12e3e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jan 2012 09:49:58 +0200 Subject: Bluetooth: Convert hdev->out to a bool type The hdev->out variable is essentially a boolean so the type 'bool' makes more sense than u8. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 8 ++++---- net/bluetooth/hci_event.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0938168ce602..520da44940e9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -282,7 +282,7 @@ struct hci_conn { __u16 state; __u8 mode; __u8 type; - __u8 out; + bool out; __u8 attempt; __u8 dev_class[3]; __u8 features[8]; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8a4678a2c982..a707d19ee44e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -51,7 +51,7 @@ static void hci_le_connect(struct hci_conn *conn) struct hci_cp_le_create_conn cp; conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->link_mode |= HCI_LM_MASTER; conn->sec_level = BT_SECURITY_LOW; @@ -83,7 +83,7 @@ void hci_acl_connect(struct hci_conn *conn) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->link_mode = HCI_LM_MASTER; @@ -151,7 +151,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->attempt++; @@ -169,7 +169,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) BT_DBG("%p", conn); conn->state = BT_CONNECT; - conn->out = 1; + conn->out = true; conn->attempt++; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d9a8618ae156..f6c13153a5e7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1154,7 +1154,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (!conn) { conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); if (conn) { - conn->out = 1; + conn->out = true; conn->link_mode |= HCI_LM_MASTER; } else BT_ERR("No memory for new connection"); @@ -1526,7 +1526,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr); if (conn) { conn->dst_type = cp->peer_addr_type; - conn->out = 1; + conn->out = true; } else { BT_ERR("No memory for new connection"); } -- cgit v1.2.3 From b644ba33699711630099efc58a4efc225560aceb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 17 Jan 2012 21:48:47 +0200 Subject: Bluetooth: Update device_connected and device_found events to latest API This patch updates mgmt_ev_device_connected and mgmt_ev_device found to include an EIR-encoded remote name and class whenever possible. With this addition the mgmt_ev_remote_name event becomes unnecessary and can be removed. Since the connected event doesn't map to hci_conn_complete anymore a HCI_CONN_MGMT_CONNECTED flag is added to track when mgmt has been notified about a connection. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 ++-- include/net/bluetooth/mgmt.h | 17 +++++---- net/bluetooth/hci_event.c | 78 ++++++++++++++++++++++++++++------------ net/bluetooth/mgmt.c | 56 +++++++++++++++++++++-------- 4 files changed, 110 insertions(+), 48 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 520da44940e9..18af5427fd0c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -409,6 +409,7 @@ enum { HCI_CONN_MODE_CHANGE_PEND, HCI_CONN_SCO_SETUP_PEND, HCI_CONN_LE_SMP_PEND, + HCI_CONN_MGMT_CONNECTED, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) @@ -933,7 +934,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent); int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type); + u8 addr_type, u8 *name, u8 name_len, + u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); @@ -962,7 +964,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 cfm_name, u8 *eir, u16 eir_len); -int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); +int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, s8 rssi, u8 *name, u8 name_len); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index bdace523b910..6f37983c8775 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -329,6 +329,11 @@ struct mgmt_ev_new_link_key { } __packed; #define MGMT_EV_DEVICE_CONNECTED 0x000A +struct mgmt_ev_device_connected { + struct mgmt_addr_info addr; + __le16 eir_len; + __u8 eir[0]; +} __packed; #define MGMT_EV_DEVICE_DISCONNECTED 0x000B @@ -371,20 +376,14 @@ struct mgmt_ev_device_found { __u8 eir[0]; } __packed; -#define MGMT_EV_REMOTE_NAME 0x0012 -struct mgmt_ev_remote_name { - bdaddr_t bdaddr; - __u8 name[MGMT_MAX_NAME_LENGTH]; -} __packed; - -#define MGMT_EV_DISCOVERING 0x0013 +#define MGMT_EV_DISCOVERING 0x0012 -#define MGMT_EV_DEVICE_BLOCKED 0x0014 +#define MGMT_EV_DEVICE_BLOCKED 0x0013 struct mgmt_ev_device_blocked { bdaddr_t bdaddr; } __packed; -#define MGMT_EV_DEVICE_UNBLOCKED 0x0015 +#define MGMT_EV_DEVICE_UNBLOCKED 0x0014 struct mgmt_ev_device_unblocked { bdaddr_t bdaddr; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f6c13153a5e7..f0b08ab734d7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1286,11 +1286,36 @@ static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } -static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) +static bool hci_resolve_next_name(struct hci_dev *hdev) { struct discovery_state *discov = &hdev->discovery; struct inquiry_entry *e; + if (list_empty(&discov->resolve)) + return false; + + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); + if (hci_resolve_name(hdev, e) == 0) { + e->name_state = NAME_PENDING; + return true; + } + + return false; +} + +static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, + bdaddr_t *bdaddr, u8 *name, u8 name_len) +{ + struct discovery_state *discov = &hdev->discovery; + struct inquiry_entry *e; + + if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, + name, name_len, conn->dev_class); + + if (discov->state == DISCOVERY_STOPPED) + return; + if (discov->state == DISCOVERY_STOPPING) goto discov_complete; @@ -1301,16 +1326,13 @@ static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) if (e) { e->name_state = NAME_KNOWN; list_del(&e->list); + if (name) + mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, + e->data.rssi, name, name_len); } - if (list_empty(&discov->resolve)) - goto discov_complete; - - e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); - if (hci_resolve_name(hdev, e) == 0) { - e->name_state = NAME_PENDING; + if (hci_resolve_next_name(hdev)) return; - } discov_complete: hci_discovery_set_state(hdev, DISCOVERY_STOPPED); @@ -1334,10 +1356,11 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (test_bit(HCI_MGMT, &hdev->dev_flags)) - hci_resolve_next_name(hdev, &cp->bdaddr); + hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0); - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); if (!conn) goto unlock; @@ -1643,8 +1666,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->state = BT_CONFIG; hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; - mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type); } else conn->state = BT_CONNECTED; @@ -1785,7 +1806,8 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (ev->status == 0) conn->state = BT_CLOSED; - if (conn->type == ACL_LINK || conn->type == LE_LINK) { + if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && + (conn->type == ACL_LINK || conn->type == LE_LINK)) { if (ev->status != 0) mgmt_disconnect_failed(hdev, &conn->dst, ev->status); else @@ -1878,14 +1900,18 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->dev_flags)) { - if (ev->status == 0) - mgmt_remote_name(hdev, &ev->bdaddr, ev->name); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - hci_resolve_next_name(hdev, &ev->bdaddr); - } + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + goto check_auth; - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (ev->status == 0) + hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name, + strnlen(ev->name, HCI_MAX_NAME_LENGTH)); + else + hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0); + +check_auth: if (!conn) goto unlock; @@ -1994,7 +2020,10 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); - } + } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &conn->dst, conn->type, + conn->dst_type, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -2763,7 +2792,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); - } + } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &conn->dst, conn->type, + conn->dst_type, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -3164,7 +3196,9 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); + if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &ev->bdaddr, conn->type, + conn->dst_type, NULL, 0, 0); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bec64c98b6a9..ae9283d47e65 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1244,7 +1244,6 @@ static int get_connections(struct sock *sk, u16 index) struct mgmt_rp_get_connections *rp; struct hci_dev *hdev; struct hci_conn *c; - struct list_head *p; size_t rp_len; u16 count; int i, err; @@ -1259,8 +1258,9 @@ static int get_connections(struct sock *sk, u16 index) hci_dev_lock(hdev); count = 0; - list_for_each(p, &hdev->conn_hash.list) { - count++; + list_for_each_entry(c, &hdev->conn_hash.list, list) { + if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + count++; } rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info)); @@ -1274,6 +1274,8 @@ static int get_connections(struct sock *sk, u16 index) i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { + if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + continue; bacpy(&rp->addr[i].bdaddr, &c->dst); rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); if (rp->addr[i].type == MGMT_ADDR_INVALID) @@ -2465,15 +2467,28 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, } int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type) + u8 addr_type, u8 *name, u8 name_len, + u8 *dev_class) { - struct mgmt_addr_info ev; + char buf[512]; + struct mgmt_ev_device_connected *ev = (void *) buf; + u16 eir_len = 0; - bacpy(&ev.bdaddr, bdaddr); - ev.type = link_to_mgmt(link_type, addr_type); + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_mgmt(link_type, addr_type); - return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, &ev, sizeof(ev), - NULL); + if (name_len > 0) + eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, + name, name_len); + + if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) + eir_len = eir_append_data(&ev->eir[eir_len], eir_len, + EIR_CLASS_OF_DEV, dev_class, 3); + + put_unaligned_le16(eir_len, &ev->eir_len); + + return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, + sizeof(*ev) + eir_len, NULL); } static void disconnect_rsp(struct pending_cmd *cmd, void *data) @@ -2813,16 +2828,27 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); } -int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name) +int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, s8 rssi, u8 *name, u8 name_len) { - struct mgmt_ev_remote_name ev; + struct mgmt_ev_device_found *ev; + char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2]; + u16 eir_len; - memset(&ev, 0, sizeof(ev)); + ev = (struct mgmt_ev_device_found *) buf; - bacpy(&ev.bdaddr, bdaddr); - memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + memset(buf, 0, sizeof(buf)); + + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->rssi = rssi; + + eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, + name_len); + + put_unaligned_le16(eir_len, &ev->eir_len); - return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); } int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) -- cgit v1.2.3 From 58a681ef1455aef9caad1d41073868fb399373f6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jan 2012 06:47:28 +0200 Subject: Bluetooth: Merge boolean members of struct hci_conn into flags Now that the flags member of struct hci_conn is supposed to accommodate any boolean type values we can easily merge all boolean members into it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_conn.c | 15 +++++++++------ net/bluetooth/hci_event.c | 21 +++++++++++++-------- 3 files changed, 25 insertions(+), 17 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 18af5427fd0c..7a033111c98f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -286,7 +286,6 @@ struct hci_conn { __u8 attempt; __u8 dev_class[3]; __u8 features[8]; - __u8 ssp_mode; __u16 interval; __u16 pkt_type; __u16 link_policy; @@ -298,12 +297,10 @@ struct hci_conn { __u8 pin_length; __u8 enc_key_size; __u8 io_capability; - __u8 power_save; __u16 disc_timeout; unsigned long flags; __u8 remote_cap; - __u8 remote_oob; __u8 remote_auth; unsigned int sent; @@ -410,6 +407,9 @@ enum { HCI_CONN_SCO_SETUP_PEND, HCI_CONN_LE_SMP_PEND, HCI_CONN_MGMT_CONNECTED, + HCI_CONN_SSP_ENABLED, + HCI_CONN_POWER_SAVE, + HCI_CONN_REMOTE_OOB, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a707d19ee44e..8288e303621a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -105,7 +105,8 @@ void hci_acl_connect(struct hci_conn *conn) } memcpy(conn->dev_class, ie->data.dev_class, 3); - conn->ssp_mode = ie->data.ssp_mode; + if (ie->data.ssp_mode > 0) + set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } cp.pkt_type = cpu_to_le16(conn->pkt_type); @@ -386,7 +387,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->remote_auth = 0xff; conn->key_type = 0xff; - conn->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; switch (type) { @@ -586,7 +587,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { - acl->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &acl->flags); hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { @@ -607,7 +608,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 && + if (test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && + conn->hdev->ssp_mode > 0 && !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; @@ -671,7 +673,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* For non 2.1 devices and low security level we don't need the link key. */ if (sec_level == BT_SECURITY_LOW && - (!conn->ssp_mode || !conn->hdev->ssp_mode)) + (!test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) || + !conn->hdev->ssp_mode)) return 1; /* For other security levels we need the link key. */ @@ -778,7 +781,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (conn->mode != HCI_CM_SNIFF) goto timer; - if (!conn->power_save && !force_active) + if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active) goto timer; if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f0b08ab734d7..02ad53801732 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1264,7 +1264,8 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) && + if (!(hdev->ssp_mode > 0 && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) && conn->pending_sec_level != BT_SECURITY_HIGH && !(conn->auth_type & 0x01)) return 0; @@ -1838,7 +1839,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s goto unlock; if (!ev->status) { - if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) && + if (!(test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && + hdev->ssp_mode > 0) && test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { @@ -1853,7 +1855,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { - if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) { + if (!ev->status && hdev->ssp_mode > 0 && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; @@ -2505,9 +2508,9 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { if (conn->mode == HCI_CM_ACTIVE) - conn->power_save = 1; + set_bit(HCI_CONN_POWER_SAVE, &conn->flags); else - conn->power_save = 0; + clear_bit(HCI_CONN_POWER_SAVE, &conn->flags); } if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) @@ -2780,7 +2783,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b if (ie) ie->data.ssp_mode = (ev->features[0] & 0x01); - conn->ssp_mode = (ev->features[0] & 0x01); + if (ev->features[0] & 0x01) + set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } if (conn->state != BT_CONFIG) @@ -2962,7 +2966,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; - if ((conn->out == 0x01 || conn->remote_oob == 0x01) && + if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) && hci_find_remote_oob_data(hdev, &conn->dst)) cp.oob_data = 0x01; else @@ -2998,8 +3002,9 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s goto unlock; conn->remote_cap = ev->capability; - conn->remote_oob = ev->oob_data; conn->remote_auth = ev->authentication; + if (ev->oob_data) + set_bit(HCI_CONN_REMOTE_OOB, &conn->flags); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3 From 84bde9d6c0e6830f4a8685a5d237965053118bf9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 25 Jan 2012 14:21:06 +0200 Subject: Bluetooth: Convert hdev->ssp_mode to a flag The ssp_mode is essentially just a boolean so it's more appropriate to have it simply as a flag in hdev->dev_flags. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_conn.c | 6 +++--- net/bluetooth/hci_event.c | 17 ++++++++++++----- net/bluetooth/mgmt.c | 4 ++-- 5 files changed, 18 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index dd2cc6cb35b3..cb9097acbf44 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -94,6 +94,7 @@ enum { HCI_DEBUG_KEYS, HCI_LE_SCAN, + HCI_SSP_ENABLED, }; /* HCI ioctl defines */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7a033111c98f..94ba8693e9d1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -144,7 +144,6 @@ struct hci_dev { __u8 features[8]; __u8 host_features[8]; __u8 commands[64]; - __u8 ssp_mode; __u8 hci_ver; __u16 hci_rev; __u8 lmp_ver; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8288e303621a..6ec259e84b95 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -609,8 +609,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn) BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - conn->hdev->ssp_mode > 0 && - !(conn->link_mode & HCI_LM_ENCRYPT)) + test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags) && + !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; return 1; @@ -674,7 +674,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) key. */ if (sec_level == BT_SECURITY_LOW && (!test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) || - !conn->hdev->ssp_mode)) + !test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags))) return 1; /* For other security levels we need the link key. */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 02ad53801732..eb198ccbc10d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -429,7 +429,10 @@ static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - hdev->ssp_mode = rp->mode; + if (rp->mode) + set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); } static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) @@ -446,7 +449,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) if (!sent) return; - hdev->ssp_mode = *((__u8 *) sent); + if (*((u8 *) sent)) + set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); } static u8 hci_get_inquiry_mode(struct hci_dev *hdev) @@ -1264,7 +1270,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!(hdev->ssp_mode > 0 && + if (!(test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) && conn->pending_sec_level != BT_SECURITY_HIGH && !(conn->auth_type & 0x01)) @@ -1840,7 +1846,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!ev->status) { if (!(test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - hdev->ssp_mode > 0) && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) && test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { @@ -1855,7 +1861,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { - if (!ev->status && hdev->ssp_mode > 0 && + if (!ev->status && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ae9283d47e65..89707996d352 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -297,7 +297,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_AUTH, &hdev->flags)) settings |= MGMT_SETTING_LINK_SECURITY; - if (hdev->ssp_mode > 0) + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SSP; return settings; @@ -416,7 +416,7 @@ static int update_eir(struct hci_dev *hdev) if (!(hdev->features[6] & LMP_EXT_INQ)) return 0; - if (hdev->ssp_mode == 0) + if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) return 0; if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) -- cgit v1.2.3 From aa64a8b500e61c33c17f1d5e7de0cc154489c59e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Jan 2012 21:33:12 +0200 Subject: Bluetooth: Add a convenience function to check for SSP enabled It's a very common test to see if both the local and the remote device have SSP enabled. By creating a simple function to test this we can shorten many if-statements in the code. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 +++++++ net/bluetooth/hci_conn.c | 8 ++------ net/bluetooth/hci_event.c | 12 ++++-------- 3 files changed, 13 insertions(+), 14 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 94ba8693e9d1..25f449fcd693 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -411,6 +411,13 @@ enum { HCI_CONN_REMOTE_OOB, }; +static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + return (test_bit(HCI_SSP_ENABLED, &hdev->flags) && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)); +} + static inline void hci_conn_hash_init(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6ec259e84b95..eae7a53467ef 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -608,9 +608,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn) { BT_DBG("conn %p", conn); - if (test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags) && - !(conn->link_mode & HCI_LM_ENCRYPT)) + if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; return 1; @@ -672,9 +670,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* For non 2.1 devices and low security level we don't need the link key. */ - if (sec_level == BT_SECURITY_LOW && - (!test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) || - !test_bit(HCI_SSP_ENABLED, &conn->hdev->dev_flags))) + if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn)) return 1; /* For other security levels we need the link key. */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index eb198ccbc10d..6fb9016652b7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1270,8 +1270,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!(test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) && + if (!hci_conn_ssp_enabled(conn) && conn->pending_sec_level != BT_SECURITY_HIGH && !(conn->auth_type & 0x01)) return 0; @@ -1845,9 +1844,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s goto unlock; if (!ev->status) { - if (!(test_bit(HCI_CONN_SSP_ENABLED, &conn->flags) && - test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) && - test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { + if (!hci_conn_ssp_enabled(conn) && + test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { conn->link_mode |= HCI_LM_AUTH; @@ -1861,9 +1859,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags); if (conn->state == BT_CONFIG) { - if (!ev->status && - test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)) { + if (!ev->status && hci_conn_ssp_enabled(conn)) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; cp.encrypt = 0x01; -- cgit v1.2.3 From 61e1b4b7de5c7e3b671e069f8bf7ee94dedbfde0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 19 Jan 2012 11:19:50 +0200 Subject: Bluetooth: trivial: space correction Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 27b72d954436..cba1f683b649 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4720,7 +4720,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) c->state, __le16_to_cpu(c->psm), c->scid, c->dcid, c->imtu, c->omtu, c->sec_level, c->mode); -} + } read_unlock(&chan_list_lock); -- cgit v1.2.3 From d22015aad40b4316f0f74c8e410debca44c3e6e2 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sun, 22 Jan 2012 00:28:34 +0200 Subject: Bluetooth: silence lockdep warning Since bluetooth uses multiple protocols types, to avoid lockdep warnings, we need to use different lockdep classes (one for each protocol type). This is already done in bt_sock_create but it misses a couple of cases when new connections are created. This patch corrects that to fix the following warning: <4>[ 1864.732366] ======================================================= <4>[ 1864.733030] [ INFO: possible circular locking dependency detected ] <4>[ 1864.733544] 3.0.16-mid3-00007-gc9a0f62 #3 <4>[ 1864.733883] ------------------------------------------------------- <4>[ 1864.734408] t.android.btclc/4204 is trying to acquire lock: <4>[ 1864.734869] (rfcomm_mutex){+.+.+.}, at: [] rfcomm_dlc_close+0x15/0x30 <4>[ 1864.735541] <4>[ 1864.735549] but task is already holding lock: <4>[ 1864.736045] (sk_lock-AF_BLUETOOTH){+.+.+.}, at: [] lock_sock+0xa/0xc <4>[ 1864.736732] <4>[ 1864.736740] which lock already depends on the new lock. <4>[ 1864.736750] <4>[ 1864.737428] <4>[ 1864.737437] the existing dependency chain (in reverse order) is: <4>[ 1864.738016] <4>[ 1864.738023] -> #1 (sk_lock-AF_BLUETOOTH){+.+.+.}: <4>[ 1864.738549] [] lock_acquire+0x104/0x140 <4>[ 1864.738977] [] lock_sock_nested+0x58/0x68 <4>[ 1864.739411] [] l2cap_sock_sendmsg+0x3e/0x76 <4>[ 1864.739858] [] __sock_sendmsg+0x50/0x59 <4>[ 1864.740279] [] sock_sendmsg+0x94/0xa8 <4>[ 1864.740687] [] kernel_sendmsg+0x28/0x37 <4>[ 1864.741106] [] rfcomm_send_frame+0x30/0x38 <4>[ 1864.741542] [] rfcomm_send_ua+0x58/0x5a <4>[ 1864.741959] [] rfcomm_run+0x441/0xb52 <4>[ 1864.742365] [] kthread+0x63/0x68 <4>[ 1864.742742] [] kernel_thread_helper+0x6/0xd <4>[ 1864.743187] <4>[ 1864.743193] -> #0 (rfcomm_mutex){+.+.+.}: <4>[ 1864.743667] [] __lock_acquire+0x988/0xc00 <4>[ 1864.744100] [] lock_acquire+0x104/0x140 <4>[ 1864.744519] [] __mutex_lock_common+0x3b/0x33f <4>[ 1864.744975] [] mutex_lock_nested+0x2d/0x36 <4>[ 1864.745412] [] rfcomm_dlc_close+0x15/0x30 <4>[ 1864.745842] [] __rfcomm_sock_close+0x5f/0x6b <4>[ 1864.746288] [] rfcomm_sock_shutdown+0x2f/0x62 <4>[ 1864.746737] [] sys_socketcall+0x1db/0x422 <4>[ 1864.747165] [] syscall_call+0x7/0xb Signed-off-by: Octavian Purdila Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 2 ++ net/bluetooth/af_bluetooth.c | 12 +++++------- net/bluetooth/l2cap_sock.c | 2 ++ net/bluetooth/rfcomm/sock.c | 2 ++ 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index abaad6ed9b83..4a82ca0bb0b2 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -256,4 +256,6 @@ void l2cap_exit(void); int sco_init(void); void sco_exit(void); +void bt_sock_reclassify_lock(struct sock *sk, int proto); + #endif /* __BLUETOOTH_H */ diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index ef92864ac625..72eb187a5f60 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -71,19 +71,16 @@ static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_AVDTP", }; -static inline void bt_sock_reclassify_lock(struct socket *sock, int proto) +void bt_sock_reclassify_lock(struct sock *sk, int proto) { - struct sock *sk = sock->sk; - - if (!sk) - return; - + BUG_ON(!sk); BUG_ON(sock_owned_by_user(sk)); sock_lock_init_class_and_name(sk, bt_slock_key_strings[proto], &bt_slock_key[proto], bt_key_strings[proto], &bt_lock_key[proto]); } +EXPORT_SYMBOL(bt_sock_reclassify_lock); int bt_sock_register(int proto, const struct net_proto_family *ops) { @@ -145,7 +142,8 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto, if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { err = bt_proto[proto]->create(net, sock, proto, kern); - bt_sock_reclassify_lock(sock, proto); + if (!err) + bt_sock_reclassify_lock(sock->sk, proto); module_put(bt_proto[proto]->owner); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c57027f7606f..401d9428ae4c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -849,6 +849,8 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) if (!sk) return NULL; + bt_sock_reclassify_lock(sk, BTPROTO_L2CAP); + l2cap_sock_init(sk, parent); return l2cap_pi(sk)->chan; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index f066678faeee..22169c3f1482 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -956,6 +956,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * if (!sk) goto done; + bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM); + rfcomm_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, &src); bacpy(&bt_sk(sk)->dst, &dst); -- cgit v1.2.3 From 2f7719ce54bf6e877987f6ef578b580a51d8c2e3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 20 Jan 2012 14:08:03 +0200 Subject: Bluetooth: Add alloc_skb chan operator Add channel-specific skb allocation method Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 +++ net/bluetooth/l2cap_core.c | 23 +++++++++++++++-------- net/bluetooth/l2cap_sock.c | 9 +++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 238daf84184c..e7a8cc7d07f4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -506,6 +506,9 @@ struct l2cap_ops { int (*recv) (void *data, struct sk_buff *skb); void (*close) (void *data); void (*state_change) (void *data, int state); + struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, + unsigned long len, int nb, int *err); + }; struct l2cap_conn { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cba1f683b649..b2f52f87b98e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1520,7 +1520,6 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1536,7 +1535,9 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr while (len) { count = min_t(unsigned int, conn->mtu, len); - *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); + *frag = chan->ops->alloc_skb(chan, count, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!*frag) return err; if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) @@ -1566,8 +1567,10 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, BT_DBG("sk %p len %d priority %u", sk, (int)len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) return ERR_PTR(err); @@ -1600,8 +1603,10 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, BT_DBG("sk %p len %d", sk, (int)len); count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) return ERR_PTR(err); @@ -1647,8 +1652,10 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, hlen += L2CAP_FCS_SIZE; count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = bt_skb_send_alloc(sk, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + + skb = chan->ops->alloc_skb(chan, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) return ERR_PTR(err); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 401d9428ae4c..16360298590f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -899,12 +899,21 @@ static void l2cap_sock_state_change_cb(void *data, int state) sk->sk_state = state; } +static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long len, int nb, int *err) +{ + struct sock *sk = chan->sk; + + return bt_skb_send_alloc(sk, len, nb, err); +} + static struct l2cap_ops l2cap_chan_ops = { .name = "L2CAP Socket Interface", .new_connection = l2cap_sock_new_connection_cb, .recv = l2cap_sock_recv_cb, .close = l2cap_sock_close_cb, .state_change = l2cap_sock_state_change_cb, + .alloc_skb = l2cap_sock_alloc_skb_cb, }; static void l2cap_sock_destruct(struct sock *sk) -- cgit v1.2.3 From cad8f1d072375a550ca81419799ba381118c14bb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 23 Jan 2012 10:06:05 +0100 Subject: Bluetooth: Make l2cap_ertm_data_rcv static It is not used outside of l2cap_core.c. Also l2cap_ertm_data_rcv is only used after it is defined so there is no need for forward declaration. Signed-off-by: Szymon Janc Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b2f52f87b98e..942ba1d1a38c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -73,8 +73,6 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); -static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb); - /* ---- L2CAP channels ---- */ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) @@ -4146,7 +4144,7 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont return 0; } -int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) +static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { u32 control; u16 req_seq; -- cgit v1.2.3 From cb601d7e65f497a2a172d65b2ef1d738ac6fe4f4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 30 Jan 2012 09:22:09 -0300 Subject: Bluetooth: Use GFP_KERNEL in hci_conn_add() This function is called in process context only, so it should use GFP_KERNEL to allocate memory. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index eae7a53467ef..9ec7b8efae50 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -373,7 +373,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) BT_DBG("%s dst %s", hdev->name, batostr(dst)); - conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); + conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); if (!conn) return NULL; -- cgit v1.2.3 From 75d7735c7a3ddc3842473219460285748d10db11 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 30 Jan 2012 09:22:10 -0300 Subject: Bluetooth: Use GFP_KERNEL in hci_chan_create() This function is called in process context only, so it should use GFP_KERNEL to allocate memory. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 9ec7b8efae50..7b38a0ba8765 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -945,7 +945,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s conn %p", hdev->name, conn); - chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC); + chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); if (!chan) return NULL; -- cgit v1.2.3 From e72acc13c770a82b4ce4a07e9716f29320eae0f8 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 27 Jan 2012 19:42:03 -0300 Subject: Bluetooth: Remove unneeded locking We don't need locking hdev in hci_conn_timeout() since it doesn't access any hdev's shared resources, it basically queues HCI commands. Signed-off-by: Andre Guedes Signed-off-by: Vinicius Costa Gomes Reviewed-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7b38a0ba8765..67c94c4dfc3c 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -280,7 +280,6 @@ static void hci_conn_timeout(struct work_struct *work) { struct hci_conn *conn = container_of(work, struct hci_conn, disc_work.work); - struct hci_dev *hdev = conn->hdev; __u8 reason; BT_DBG("conn %p state %d", conn, conn->state); @@ -288,8 +287,6 @@ static void hci_conn_timeout(struct work_struct *work) if (atomic_read(&conn->refcnt)) return; - hci_dev_lock(hdev); - switch (conn->state) { case BT_CONNECT: case BT_CONNECT2: @@ -309,8 +306,6 @@ static void hci_conn_timeout(struct work_struct *work) conn->state = BT_CLOSED; break; } - - hci_dev_unlock(hdev); } /* Enter sniff mode */ -- cgit v1.2.3 From 17cd3f374be6648bd46c86ff8f2a2511d3f416ee Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Mon, 30 Jan 2012 18:26:28 -0200 Subject: Bluetooth: Remove usage of __cancel_delayed_work() __cancel_delayed_work() is being used in some paths where we cannot sleep waiting for the delayed work to finish. However, that function might return while the timer is running and the work will be queued again. Replace the calls with safer cancel_delayed_work() version which spins until the timer handler finishes on other CPUs and cancels the delayed work. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 4 ++-- net/bluetooth/l2cap_core.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e7a8cc7d07f4..42fdbb833254 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -614,7 +614,7 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan, { BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); - if (!__cancel_delayed_work(work)) + if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); schedule_delayed_work(work, timeout); } @@ -624,7 +624,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan, { bool ret; - ret = __cancel_delayed_work(work); + ret = cancel_delayed_work(work); if (ret) l2cap_chan_put(chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 942ba1d1a38c..ae7fb27525d3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2588,7 +2588,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && cmd->ident == conn->info_ident) { - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work(&conn->info_timer); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -3135,7 +3135,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) return 0; - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; @@ -4509,7 +4509,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (hcon->type == LE_LINK) { smp_distribute_keys(conn, 0); - __cancel_delayed_work(&conn->security_timer); + cancel_delayed_work(&conn->security_timer); } rcu_read_lock(); -- cgit v1.2.3 From 127074bfa3c11c12e0160437e31b08c6b27412a4 Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Mon, 30 Jan 2012 18:26:29 -0200 Subject: Bluetooth: Fix possible use after free in delete path We need to use the _sync() version for cancelling the info and security timer in the L2CAP connection delete path. Otherwise the delayed work handler might run after the connection object is freed. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ae7fb27525d3..09cd8601ea81 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1016,10 +1016,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { - __cancel_delayed_work(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } -- cgit v1.2.3 From f7aa611a0ecf1d22f21e26279e1a3baf1db6b973 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Mon, 30 Jan 2012 19:29:12 -0300 Subject: Bluetooth: Rename smp_key_size to enc_key_size This makes clear that this is the size of the key used to encrypt the link. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/smp.h | 2 +- net/bluetooth/smp.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index aeaf5fa2b9f1..7b3acdd29134 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -127,7 +127,7 @@ struct smp_chan { u8 rrnd[16]; /* SMP Pairing Random (remote) */ u8 pcnf[16]; /* SMP Pairing Confirm */ u8 tk[16]; /* SMP Temporary Key */ - u8 smp_key_size; + u8 enc_key_size; unsigned long smp_flags; struct crypto_blkcipher *tfm; struct work_struct confirm; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e08fe6c9c9c9..581833436afa 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -250,7 +250,7 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) (max_key_size < SMP_MIN_ENC_KEY_SIZE)) return SMP_ENC_KEY_SIZE; - smp->smp_key_size = max_key_size; + smp->enc_key_size = max_key_size; return 0; } @@ -446,8 +446,8 @@ static void random_work(struct work_struct *work) smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); swap128(key, stk); - memset(stk + smp->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); + memset(stk + smp->enc_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; @@ -455,7 +455,7 @@ static void random_work(struct work_struct *work) } hci_le_start_enc(hcon, ediv, rand, stk); - hcon->enc_key_size = smp->smp_key_size; + hcon->enc_key_size = smp->enc_key_size; } else { u8 stk[16], r[16], rand[8]; __le16 ediv; @@ -469,10 +469,10 @@ static void random_work(struct work_struct *work) smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); swap128(key, stk); - memset(stk + smp->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); + memset(stk + smp->enc_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size, + hci_add_ltk(hcon->hdev, 0, conn->dst, smp->enc_key_size, ediv, rand, stk); } @@ -819,7 +819,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, rp->ediv, rp->rand, smp->tk); smp_distribute_keys(conn, 1); @@ -940,7 +940,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, ediv, ident.rand, enc.ltk); ident.ediv = cpu_to_le16(ediv); -- cgit v1.2.3 From 4777bfdebbddc1f58d9148de5a3e00375d063768 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 30 Jan 2012 23:31:28 -0300 Subject: Bluetooth: Use GFP_KERNEL in hci_add_adv_entry() This function is not called in interrupt context anymore, so it should use GFP_KERNEL to allocate memory. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 91166dbbe35c..45e2d2a72b15 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1553,7 +1553,7 @@ int hci_add_adv_entry(struct hci_dev *hdev, if (hci_find_adv_entry(hdev, &ev->bdaddr)) return 0; - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; -- cgit v1.2.3 From 66f01296962dfebf032c18ffe61c53a199b4a7bd Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 27 Jan 2012 19:32:39 +0200 Subject: Bluetooth: Fix RFCOMM session reference counting issue There is an imbalance in the rfcomm_session_hold / rfcomm_session_put operations which causes the following crash: [ 685.010159] BUG: unable to handle kernel paging request at 6b6b6b6b [ 685.010169] IP: [] rfcomm_process_dlcs+0x1b/0x15e [ 685.010181] *pdpt = 000000002d665001 *pde = 0000000000000000 [ 685.010191] Oops: 0000 [#1] PREEMPT SMP [ 685.010247] [ 685.010255] Pid: 947, comm: krfcommd Tainted: G C 3.0.16-mid8-dirty #44 [ 685.010266] EIP: 0060:[] EFLAGS: 00010246 CPU: 1 [ 685.010274] EIP is at rfcomm_process_dlcs+0x1b/0x15e [ 685.010281] EAX: e79f551c EBX: 6b6b6b6b ECX: 00000007 EDX: e79f40b4 [ 685.010288] ESI: e79f4060 EDI: ed4e1f70 EBP: ed4e1f68 ESP: ed4e1f50 [ 685.010295] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 685.010303] Process krfcommd (pid: 947, ti=ed4e0000 task=ed43e5e0 task.ti=ed4e0000) [ 685.010308] Stack: [ 685.010312] ed4e1f68 c149eb53 e5925150 e79f4060 ed500000 ed4e1f70 ed4e1f80 c149ec10 [ 685.010331] 00000000 ed43e5e0 00000000 ed4e1f90 ed4e1f9c c149ec87 0000bf54 00000000 [ 685.010348] 00000000 ee03bf54 c149ec37 ed4e1fe4 c104fe01 00000000 00000000 00000000 [ 685.010367] Call Trace: [ 685.010376] [] ? rfcomm_process_rx+0x6e/0x74 [ 685.010387] [] rfcomm_process_sessions+0xb7/0xde [ 685.010398] [] rfcomm_run+0x50/0x6d [ 685.010409] [] ? rfcomm_process_sessions+0xde/0xde [ 685.010419] [] kthread+0x63/0x68 [ 685.010431] [] ? __init_kthread_worker+0x42/0x42 [ 685.010442] [] kernel_thread_helper+0x6/0xd This issue has been brought up earlier here: https://lkml.org/lkml/2011/5/21/127 The issue appears to be the rfcomm_session_put in rfcomm_recv_ua. This operation doesn't seem be to required as for the non-initiator case we have the rfcomm_process_rx doing an explicit put and in the initiator case the last dlc_unlink will drive the reference counter to 0. There have been several attempts to fix these issue: 6c2718d Bluetooth: Do not call rfcomm_session_put() for RFCOMM UA on closed socket 683d949 Bluetooth: Never deallocate a session when some DLC points to it but AFAICS they do not fix the issue just make it harder to reproduce. Signed-off-by: Octavian Purdila Signed-off-by: Gopala Krishna Murala Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/rfcomm/core.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 501649bf5596..8a602388f1e7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1164,12 +1164,18 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) break; case BT_DISCONN: - /* When socket is closed and we are not RFCOMM - * initiator rfcomm_process_rx already calls - * rfcomm_session_put() */ - if (s->sock->sk->sk_state != BT_CLOSED) - if (list_empty(&s->dlcs)) - rfcomm_session_put(s); + /* rfcomm_session_put is called later so don't do + * anything here otherwise we will mess up the session + * reference counter: + * + * (a) when we are the initiator dlc_unlink will drive + * the reference counter to 0 (there is no initial put + * after session_add) + * + * (b) when we are not the initiator rfcomm_rx_process + * will explicitly call put to balance the initial hold + * done after session add. + */ break; } } -- cgit v1.2.3 From f1c09c07cd1a6c1676c4df6450d2b28875e184c1 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 1 Feb 2012 18:27:56 -0300 Subject: Bluetooth: Fix invalid memory access when there's no SMP channel We only should try to free the SMP channel that was created if there is a pending SMP session. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 581833436afa..9ff56e18d99b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -263,8 +263,11 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); - cancel_delayed_work_sync(&conn->security_timer); - smp_chan_destroy(conn); + + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { + cancel_delayed_work_sync(&conn->security_timer); + smp_chan_destroy(conn); + } } #define JUST_WORKS 0x00 @@ -506,7 +509,7 @@ void smp_chan_destroy(struct l2cap_conn *conn) { struct smp_chan *smp = conn->smp_chan; - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); + BUG_ON(!smp); if (smp->tfm) crypto_free_blkcipher(smp->tfm); -- cgit v1.2.3 From b7d05bad1c10a363b6b99f66ac1fa76b6892e618 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 13 Jan 2012 15:11:30 +0100 Subject: Bluetooth: Fix l2cap conn failures for ssp devices Commit 330605423c fixed l2cap conn establishment for non-ssp remote devices by not setting HCI_CONN_ENCRYPT_PEND every time conn security is tested (which was always returning failure on any subsequent security checks). However, this broke l2cap conn establishment for ssp remote devices when an ACL link was already established at SDP-level security. This fix ensures that encryption must be pending whenever authentication is also pending. Signed-off-by: Peter Hurley Tested-by: Daniel Wagner Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 67c94c4dfc3c..aca71c087a1d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -630,6 +630,10 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; + + /* encrypt must be pending if auth is also pending */ + set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); -- cgit v1.2.3 From 7a7f1e7c857959f5298020969741e389f21edbae Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 16 Jan 2012 13:34:29 +0530 Subject: Bluetooth: Send correct response to IO Capability Request This patch sends correct IO Capability response to remote device in case Local Device supports KeyBoardDisplay IO Capability as this capability is not valid as per BT spec for IO capability Request Reply Command. This capability is mapped to DisplayYesNo which is in accordance with BT spec. Signed-off-by: Hemant Gupta Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6fb9016652b7..041a35eb25c6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2965,7 +2965,10 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff struct hci_cp_io_capability_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); - cp.capability = conn->io_capability; + /* Change the IO capability from KeyboardDisplay + * to DisplayYesNo as it is not supported by BT spec. */ + cp.capability = (conn->io_capability == 0x04) ? + 0x01 : conn->io_capability; conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; -- cgit v1.2.3 From 95947a391ebe685b9870cd25cac1433aedf5d49c Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 23 Jan 2012 15:36:11 +0530 Subject: Bluetooth: Fix clearing of debug and linkkey flags This patch fixes clearing of HCI_LINK_KEYS and HCI_DEBUG_KEYS dev_flags while resetting. Without this patch pairing does not work over management interface for BR-EDR devices. Signed-off-by: Hemant Gupta Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 041a35eb25c6..a86f82b11316 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -196,7 +196,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); /* Reset all flags, except persistent ones */ - hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF); + hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF) | + BIT(HCI_LINK_KEYS) | BIT(HCI_DEBUG_KEYS); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From 28424707a2e4ad38ab546d2ed5e3d6b035a84258 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Feb 2012 04:02:29 +0200 Subject: Bluetooth: mgmt: Implement Cancel Pair Device command This patch implements the Cancel Pair Device command for mgmt. It's used by user space to cancel an ongoing pairing attempt which was triggered by the Pair Device command. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 42eb48bb2c3b..72975fd53988 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -39,6 +39,7 @@ #define MGMT_STATUS_INVALID_PARAMS 0x0d #define MGMT_STATUS_DISCONNECTED 0x0e #define MGMT_STATUS_NOT_POWERED 0x0f +#define MGMT_STATUS_CANCELLED 0x10 struct mgmt_hdr { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 89707996d352..00ab083749eb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1594,6 +1594,54 @@ unlock: return err; } +static int cancel_pair_device(struct sock *sk, u16 index, + unsigned char *data, u16 len) +{ + struct mgmt_addr_info *addr = (void *) data; + struct hci_dev *hdev; + struct pending_cmd *cmd; + struct hci_conn *conn; + int err; + + BT_DBG(""); + + if (len != sizeof(*addr)) + return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); + if (!cmd) { + err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + goto unlock; + } + + conn = cmd->user_data; + + if (bacmp(&addr->bdaddr, &conn->dst) != 0) { + err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS); + goto unlock; + } + + pairing_complete(cmd, MGMT_STATUS_CANCELLED); + + err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr, + sizeof(*addr)); +unlock: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, u16 mgmt_op, u16 hci_op, __le32 passkey) { @@ -2271,6 +2319,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_PAIR_DEVICE: err = pair_device(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_CANCEL_PAIR_DEVICE: + err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); + break; case MGMT_OP_USER_CONFIRM_REPLY: err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len); break; -- cgit v1.2.3 From 3c4e0df028935618d052235ba85bc7079be13394 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 2 Feb 2012 10:32:17 +0200 Subject: Bluetooth: Use list _safe deleting from conn_hash_list Use list_for_each_entry_safe which is safe version against removal of list entry. Otherwise we remove hci_conn element and reference next element which result in accessing LIST_POISON. [ 95.571834] Bluetooth: unknown link type 127 [ 95.578349] BUG: unable to handle kernel paging request at 20002000 [ 95.580236] IP: [<20002000>] 0x20001fff [ 95.580763] *pde = 00000000 [ 95.581196] Oops: 0000 [#1] SMP ... [ 95.582298] Pid: 3355, comm: hciconfig Tainted: G O 3.2.0-VirttualBox [ 95.582298] EIP: 0060:[<20002000>] EFLAGS: 00210206 CPU: 0 [ 95.582298] EIP is at 0x20002000 ... [ 95.582298] Call Trace: [ 95.582298] [] ? hci_conn_hash_flush+0x76/0xf0 [bluetooth] [ 95.582298] [] hci_dev_do_close+0xc1/0x2e0 [bluetooth] [ 95.582298] [] ? hci_dev_get+0x69/0xb0 [bluetooth] [ 95.582298] [] hci_dev_close+0x2a/0x50 [bluetooth] [ 95.582298] [] hci_sock_ioctl+0x1af/0x3f0 [bluetooth] [ 95.582298] [] ? handle_pte_fault+0x8a/0x8f0 [ 95.582298] [] sock_ioctl+0x5f/0x260 [ 95.582298] [] ? sock_fasync+0x90/0x90 [ 95.582298] [] do_vfs_ioctl+0x83/0x5b0 [ 95.582298] [] ? do_page_fault+0x297/0x500 [ 95.582298] [] ? spurious_fault+0xd0/0xd0 [ 95.582298] [] ? up_read+0x1b/0x30 [ 95.582298] [] ? do_page_fault+0x297/0x500 [ 95.582298] [] ? init_fpu+0xef/0x160 [ 95.582298] [] ? do_debug+0x180/0x180 [ 95.582298] [] ? fpu_finit+0x28/0x80 [ 95.582298] [] sys_ioctl+0x87/0x90 [ 95.582298] [] sysenter_do_call+0x12/0x38 ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index aca71c087a1d..b074bd698cf6 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -795,11 +795,11 @@ timer: void hci_conn_hash_flush(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; - struct hci_conn *c; + struct hci_conn *c, *n; BT_DBG("hdev %s", hdev->name); - list_for_each_entry_rcu(c, &h->list, list) { + list_for_each_entry_safe(c, n, &h->list, list) { c->state = BT_CLOSED; hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); -- cgit v1.2.3 From 2a5a5ec620a29d4ba07743c3151cdf0a417c8f8c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 2 Feb 2012 10:32:18 +0200 Subject: Bluetooth: Use list _safe deleting from conn chan_list Fixes possible bug when deleting element from the list in function hci_chan_list_flush. list_for_each_entry_rcu is used and after deleting element from the list we also free pointer and then list_entry_rcu is taken from freed pointer. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b074bd698cf6..b4ecddee11b5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -975,10 +975,10 @@ int hci_chan_del(struct hci_chan *chan) void hci_chan_list_flush(struct hci_conn *conn) { - struct hci_chan *chan; + struct hci_chan *chan, *n; BT_DBG("conn %p", conn); - list_for_each_entry_rcu(chan, &conn->chan_list, list) + list_for_each_entry_safe(chan, n, &conn->chan_list, list) hci_chan_del(chan); } -- cgit v1.2.3 From 650f726d16a3f25153d785b531516f6e90d2014f Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:07:59 -0300 Subject: Bluetooth: Fix doing some useless casts when receiving MGMT commands Every command handler of mgmt does a cast to the command structure so it can properly interpreted. So we can avoid that cast if we make those functions receive a void * directly. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 205 +++++++++++++++++++++------------------------------ 1 file changed, 83 insertions(+), 122 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 00ab083749eb..ad8986276848 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -611,15 +611,13 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings)); } -static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int set_powered(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_mode *cp; + struct mgmt_mode *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; int err, up; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -664,17 +662,14 @@ failed: return err; } -static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_set_discoverable *cp; + struct mgmt_cp_set_discoverable *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; u8 scan; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -734,17 +729,14 @@ failed: return err; } -static int set_connectable(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_mode *cp; + struct mgmt_mode *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; u8 scan; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -827,16 +819,13 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, return 0; } -static int set_pairable(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_mode *cp; + struct mgmt_mode *cp = data; struct hci_dev *hdev; __le32 ev; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -870,15 +859,13 @@ failed: return err; } -static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_add_uuid *cp; + struct mgmt_cp_add_uuid *cp = data; struct hci_dev *hdev; struct bt_uuid *uuid; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -920,16 +907,14 @@ failed: return err; } -static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) { + struct mgmt_cp_remove_uuid *cp = data; struct list_head *p, *n; - struct mgmt_cp_remove_uuid *cp; struct hci_dev *hdev; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int err, found; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -983,15 +968,12 @@ unlock: return err; } -static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_set_dev_class *cp; + struct mgmt_cp_set_dev_class *cp = data; int err; - cp = (void *) data; - BT_DBG("request for hci%u", index); if (len != sizeof(*cp)) @@ -1026,16 +1008,13 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, return err; } -static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_load_link_keys *cp; + struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; int i; - cp = (void *) data; - if (len < sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); @@ -1085,19 +1064,16 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, return 0; } -static int remove_keys(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_remove_keys *cp; + struct mgmt_cp_remove_keys *cp = data; struct mgmt_rp_remove_keys rp; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; int err; - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, MGMT_STATUS_INVALID_PARAMS); @@ -1154,10 +1130,10 @@ unlock: return err; } -static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int disconnect(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_disconnect *cp; + struct mgmt_cp_disconnect *cp = data; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; @@ -1165,8 +1141,6 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_DISCONNECT, MGMT_STATUS_INVALID_PARAMS); @@ -1314,12 +1288,11 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, return err; } -static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct hci_conn *conn; - struct mgmt_cp_pin_code_reply *cp; + struct mgmt_cp_pin_code_reply *cp = data; struct mgmt_cp_pin_code_neg_reply ncp; struct hci_cp_pin_code_reply reply; struct pending_cmd *cmd; @@ -1327,8 +1300,6 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); @@ -1366,7 +1337,8 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, goto failed; } - cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len); + cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, + len); if (!cmd) { err = -ENOMEM; goto failed; @@ -1387,17 +1359,14 @@ failed: return err; } -static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_pin_code_neg_reply *cp; + struct mgmt_cp_pin_code_neg_reply *cp = data; int err; BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); @@ -1424,16 +1393,13 @@ failed: return err; } -static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_set_io_capability *cp; + struct mgmt_cp_set_io_capability *cp = data; BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, MGMT_STATUS_INVALID_PARAMS); @@ -1508,10 +1474,10 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, status); } -static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) +static int pair_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_pair_device *cp; + struct mgmt_cp_pair_device *cp = data; struct mgmt_rp_pair_device rp; struct pending_cmd *cmd; u8 sec_level, auth_type; @@ -1520,8 +1486,6 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG(""); - cp = (void *) data; - if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); @@ -1721,7 +1685,7 @@ done: static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_confirm_reply *cp = (void *) data; + struct mgmt_cp_user_confirm_reply *cp = data; BT_DBG(""); @@ -1752,7 +1716,7 @@ static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_passkey_reply *cp = (void *) data; + struct mgmt_cp_user_passkey_reply *cp = data; BT_DBG(""); @@ -1768,7 +1732,7 @@ static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data; + struct mgmt_cp_user_passkey_neg_reply *cp = data; BT_DBG(""); @@ -1781,10 +1745,10 @@ static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } -static int set_local_name(struct sock *sk, u16 index, unsigned char *data, +static int set_local_name(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; + struct mgmt_cp_set_local_name *mgmt_cp = data; struct hci_cp_write_local_name hci_cp; struct hci_dev *hdev; struct pending_cmd *cmd; @@ -1803,7 +1767,8 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, hci_dev_lock(hdev); - cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, + len); if (!cmd) { err = -ENOMEM; goto failed; @@ -1872,11 +1837,11 @@ unlock: return err; } -static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int add_remote_oob_data(struct sock *sk, u16 index, void *data, + u16 len) { struct hci_dev *hdev; - struct mgmt_cp_add_remote_oob_data *cp = (void *) data; + struct mgmt_cp_add_remote_oob_data *cp = data; int err; BT_DBG("hci%u ", index); @@ -1908,10 +1873,10 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, } static int remove_remote_oob_data(struct sock *sk, u16 index, - unsigned char *data, u16 len) + void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; + struct mgmt_cp_remove_remote_oob_data *cp = data; int err; BT_DBG("hci%u ", index); @@ -1942,9 +1907,9 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, } static int start_discovery(struct sock *sk, u16 index, - unsigned char *data, u16 len) + void *data, u16 len) { - struct mgmt_cp_start_discovery *cp = (void *) data; + struct mgmt_cp_start_discovery *cp = data; struct pending_cmd *cmd; struct hci_dev *hdev; int err; @@ -2054,10 +2019,9 @@ unlock: return err; } -static int confirm_name(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_confirm_name *cp = (void *) data; + struct mgmt_cp_confirm_name *cp = data; struct inquiry_entry *e; struct hci_dev *hdev; int err; @@ -2104,11 +2068,10 @@ failed: return err; } -static int block_device(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int block_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_block_device *cp = (void *) data; + struct mgmt_cp_block_device *cp = data; int err; BT_DBG("hci%u", index); @@ -2138,11 +2101,10 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, return err; } -static int unblock_device(struct sock *sk, u16 index, unsigned char *data, - u16 len) +static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_unblock_device *cp = (void *) data; + struct mgmt_cp_unblock_device *cp = data; int err; BT_DBG("hci%u", index); @@ -2174,10 +2136,10 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, } static int set_fast_connectable(struct sock *sk, u16 index, - unsigned char *data, u16 len) + void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_mode *cp = (void *) data; + struct mgmt_mode *cp = data; struct hci_cp_write_page_scan_activity acp; u8 type; int err; @@ -2231,7 +2193,8 @@ done: int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { - unsigned char *buf; + void *buf; + u8 *cp; struct mgmt_hdr *hdr; u16 opcode, index, len; int err; @@ -2250,7 +2213,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } - hdr = (struct mgmt_hdr *) buf; + hdr = buf; opcode = get_unaligned_le16(&hdr->opcode); index = get_unaligned_le16(&hdr->index); len = get_unaligned_le16(&hdr->len); @@ -2260,6 +2223,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } + cp = buf + sizeof(*hdr); + switch (opcode) { case MGMT_OP_READ_VERSION: err = read_version(sk); @@ -2271,98 +2236,94 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = read_controller_info(sk, index); break; case MGMT_OP_SET_POWERED: - err = set_powered(sk, index, buf + sizeof(*hdr), len); + err = set_powered(sk, index, cp, len); break; case MGMT_OP_SET_DISCOVERABLE: - err = set_discoverable(sk, index, buf + sizeof(*hdr), len); + err = set_discoverable(sk, index, cp, len); break; case MGMT_OP_SET_CONNECTABLE: - err = set_connectable(sk, index, buf + sizeof(*hdr), len); + err = set_connectable(sk, index, cp, len); break; case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, index, buf + sizeof(*hdr), - len); + err = set_fast_connectable(sk, index, cp, len); break; case MGMT_OP_SET_PAIRABLE: - err = set_pairable(sk, index, buf + sizeof(*hdr), len); + err = set_pairable(sk, index, cp, len); break; case MGMT_OP_ADD_UUID: - err = add_uuid(sk, index, buf + sizeof(*hdr), len); + err = add_uuid(sk, index, cp, len); break; case MGMT_OP_REMOVE_UUID: - err = remove_uuid(sk, index, buf + sizeof(*hdr), len); + err = remove_uuid(sk, index, cp, len); break; case MGMT_OP_SET_DEV_CLASS: - err = set_dev_class(sk, index, buf + sizeof(*hdr), len); + err = set_dev_class(sk, index, cp, len); break; case MGMT_OP_LOAD_LINK_KEYS: - err = load_link_keys(sk, index, buf + sizeof(*hdr), len); + err = load_link_keys(sk, index, cp, len); break; case MGMT_OP_REMOVE_KEYS: - err = remove_keys(sk, index, buf + sizeof(*hdr), len); + err = remove_keys(sk, index, cp, len); break; case MGMT_OP_DISCONNECT: - err = disconnect(sk, index, buf + sizeof(*hdr), len); + err = disconnect(sk, index, cp, len); break; case MGMT_OP_GET_CONNECTIONS: err = get_connections(sk, index); break; case MGMT_OP_PIN_CODE_REPLY: - err = pin_code_reply(sk, index, buf + sizeof(*hdr), len); + err = pin_code_reply(sk, index, cp, len); break; case MGMT_OP_PIN_CODE_NEG_REPLY: - err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len); + err = pin_code_neg_reply(sk, index, cp, len); break; case MGMT_OP_SET_IO_CAPABILITY: - err = set_io_capability(sk, index, buf + sizeof(*hdr), len); + err = set_io_capability(sk, index, cp, len); break; case MGMT_OP_PAIR_DEVICE: - err = pair_device(sk, index, buf + sizeof(*hdr), len); + err = pair_device(sk, index, cp, len); break; case MGMT_OP_CANCEL_PAIR_DEVICE: err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); break; case MGMT_OP_USER_CONFIRM_REPLY: - err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len); + err = user_confirm_reply(sk, index, cp, len); break; case MGMT_OP_USER_CONFIRM_NEG_REPLY: - err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr), - len); + err = user_confirm_neg_reply(sk, index, cp, len); break; case MGMT_OP_USER_PASSKEY_REPLY: - err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len); + err = user_passkey_reply(sk, index, cp, len); break; case MGMT_OP_USER_PASSKEY_NEG_REPLY: - err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr), - len); + err = user_passkey_neg_reply(sk, index, cp, len); break; case MGMT_OP_SET_LOCAL_NAME: - err = set_local_name(sk, index, buf + sizeof(*hdr), len); + err = set_local_name(sk, index, cp, len); break; case MGMT_OP_READ_LOCAL_OOB_DATA: err = read_local_oob_data(sk, index); break; case MGMT_OP_ADD_REMOTE_OOB_DATA: - err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); + err = add_remote_oob_data(sk, index, cp, len); break; case MGMT_OP_REMOVE_REMOTE_OOB_DATA: - err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), - len); + err = remove_remote_oob_data(sk, index, cp, len); break; case MGMT_OP_START_DISCOVERY: - err = start_discovery(sk, index, buf + sizeof(*hdr), len); + err = start_discovery(sk, index, cp, len); break; 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); + err = confirm_name(sk, index, cp, len); break; case MGMT_OP_BLOCK_DEVICE: - err = block_device(sk, index, buf + sizeof(*hdr), len); + err = block_device(sk, index, cp, len); break; case MGMT_OP_UNBLOCK_DEVICE: - err = unblock_device(sk, index, buf + sizeof(*hdr), len); + err = unblock_device(sk, index, cp, len); break; default: BT_DBG("Unknown op %u", opcode); -- cgit v1.2.3 From b899efaf9b26cadb084752862490b4fc44bc3169 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:00 -0300 Subject: Bluetooth: Add new structures for handling SMP Long Term Keys This includes a new list for storing the keys and a new structure used to represent each key. Some notes: authenticated is used to identify that the key may be used to setup a HIGH security link. As the same list is used to store both the STK's and the LTK's the type field is used so we can separate between those two types of keys and if the key should be used when in the master or slave role. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 5 +++++ include/net/bluetooth/hci_core.h | 16 ++++++++++++++++ net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cb9097acbf44..83f045a515a0 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -274,6 +274,11 @@ enum { #define HCI_LK_SMP_LTK 0x81 #define HCI_LK_SMP_IRK 0x82 #define HCI_LK_SMP_CSRK 0x83 +/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */ +#define HCI_SMP_STK 0x80 +#define HCI_SMP_STK_SLAVE 0x81 +#define HCI_SMP_LTK 0x82 +#define HCI_SMP_LTK_SLAVE 0x83 /* ---- HCI Error Codes ---- */ #define HCI_ERROR_AUTH_FAILURE 0x05 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 896d9e4955fc..c998176a503d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -88,6 +88,18 @@ struct bt_uuid { u8 svc_hint; }; +struct smp_ltk { + struct list_head list; + bdaddr_t bdaddr; + u8 bdaddr_type; + u8 authenticated; + u8 type; + u8 enc_size; + __le16 ediv; + u8 rand[8]; + u8 val[16]; +} __packed; + struct key_master_id { __le16 ediv; u8 rand[8]; @@ -239,6 +251,8 @@ struct hci_dev { struct list_head link_keys; + struct list_head long_term_keys; + struct list_head remote_oob_data; struct list_head adv_entries; @@ -647,8 +661,10 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); struct link_key *hci_find_link_key_type(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]); +int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 45e2d2a72b15..a28e637152fe 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1163,6 +1163,18 @@ int hci_link_keys_clear(struct hci_dev *hdev) return 0; } +int hci_smp_ltks_clear(struct hci_dev *hdev) +{ + struct smp_ltk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + list_del(&k->list); + kfree(k); + } + + return 0; +} + struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *k; @@ -1355,6 +1367,23 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct smp_ltk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + if (bacmp(bdaddr, &k->bdaddr)) + continue; + + BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); + + list_del(&k->list); + kfree(k); + } + + return 0; +} + /* HCI command timer function */ static void hci_cmd_timer(unsigned long arg) { @@ -1638,6 +1667,7 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); + INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); @@ -1739,6 +1769,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); + hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); -- cgit v1.2.3 From c9839a11c0e460a2457e7cac76650d07773e6c3b Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:01 -0300 Subject: Bluetooth: Use the updated key structures for handling LTKs This updates all the users of the older way, that was using the link_keys list to store the SMP keys, to use the new way. This includes defining new types for the keys, we have a type for each combination of STK/LTK and Master/Slave. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 11 +++--- net/bluetooth/hci_core.c | 76 +++++++++++++++++----------------------- net/bluetooth/hci_event.c | 11 ++++-- net/bluetooth/smp.c | 38 ++++++++++++-------- 4 files changed, 71 insertions(+), 65 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c998176a503d..2649caf4db96 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -658,12 +658,13 @@ int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); -struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); -struct link_key *hci_find_link_key_type(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type); +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); +int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, + int new_key, u8 authenticated, u8 tk[16], + u8 enc_size, u16 ediv, u8 rand[8]); +struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a28e637152fe..84b7a9e4f2f6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1222,41 +1222,35 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return 0; } -struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) { - struct link_key *k; - - list_for_each_entry(k, &hdev->link_keys, list) { - struct key_master_id *id; + struct smp_ltk *k; - if (k->type != HCI_LK_SMP_LTK) + list_for_each_entry(k, &hdev->long_term_keys, list) { + if (k->ediv != ediv || + memcmp(rand, k->rand, sizeof(k->rand))) continue; - if (k->dlen != sizeof(*id)) - continue; - - id = (void *) &k->data; - if (id->ediv == ediv && - (memcmp(rand, id->rand, sizeof(id->rand)) == 0)) - return k; + return k; } return NULL; } EXPORT_SYMBOL(hci_find_ltk); -struct link_key *hci_find_link_key_type(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type) +struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type) { - struct link_key *k; + struct smp_ltk *k; - list_for_each_entry(k, &hdev->link_keys, list) - if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0) + list_for_each_entry(k, &hdev->long_term_keys, list) + if (addr_type == k->bdaddr_type && + bacmp(bdaddr, &k->bdaddr) == 0) return k; return NULL; } -EXPORT_SYMBOL(hci_find_link_key_type); +EXPORT_SYMBOL(hci_find_ltk_by_addr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) @@ -1313,40 +1307,36 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, return 0; } -int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]) +int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, + int new_key, u8 authenticated, u8 tk[16], + u8 enc_size, u16 ediv, u8 rand[8]) { - struct link_key *key, *old_key; - struct key_master_id *id; - u8 old_key_type; + struct smp_ltk *key, *old_key; - BT_DBG("%s addr %s", hdev->name, batostr(bdaddr)); + if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK)) + return 0; - old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK); - if (old_key) { + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); + if (old_key) key = old_key; - old_key_type = old_key->type; - } else { - key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC); + else { + key = kzalloc(sizeof(*key), GFP_ATOMIC); if (!key) return -ENOMEM; - list_add(&key->list, &hdev->link_keys); - old_key_type = 0xff; + list_add(&key->list, &hdev->long_term_keys); } - key->dlen = sizeof(*id); - bacpy(&key->bdaddr, bdaddr); - memcpy(key->val, ltk, sizeof(key->val)); - key->type = HCI_LK_SMP_LTK; - key->pin_len = key_size; - - id = (void *) &key->data; - id->ediv = ediv; - memcpy(id->rand, rand, sizeof(id->rand)); + key->bdaddr_type = addr_type; + memcpy(key->val, tk, sizeof(key->val)); + key->authenticated = authenticated; + key->ediv = ediv; + key->enc_size = enc_size; + key->type = type; + memcpy(key->rand, rand, sizeof(key->rand)); - if (new_key) - mgmt_new_link_key(hdev, key, old_key_type); + if (!new_key) + return 0; return 0; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a86f82b11316..23dbb31f0423 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3256,7 +3256,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, struct hci_cp_le_ltk_reply cp; struct hci_cp_le_ltk_neg_reply neg; struct hci_conn *conn; - struct link_key *ltk; + struct smp_ltk *ltk; BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); @@ -3272,10 +3272,17 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, memcpy(cp.ltk, ltk->val, sizeof(ltk->val)); cp.handle = cpu_to_le16(conn->handle); - conn->pin_length = ltk->pin_len; + + if (ltk->authenticated) + conn->sec_level = BT_SECURITY_HIGH; hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); + if (ltk->type & HCI_SMP_STK) { + list_del(<k->list); + kfree(ltk); + } + hci_dev_unlock(hdev); return; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9ff56e18d99b..0563f737779a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -475,8 +475,9 @@ static void random_work(struct work_struct *work) memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - hci_add_ltk(hcon->hdev, 0, conn->dst, smp->enc_key_size, - ediv, rand, stk); + hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type, + HCI_SMP_STK_SLAVE, 0, 0, stk, + smp->enc_key_size, ediv, rand); } return; @@ -701,22 +702,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_ltk_encrypt(struct l2cap_conn *conn) { - struct link_key *key; - struct key_master_id *master; + struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; - key = hci_find_link_key_type(hcon->hdev, conn->dst, - HCI_LK_SMP_LTK); + key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type); if (!key) return 0; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; - master = (void *) key->data; - hci_le_start_enc(hcon, master->ediv, master->rand, - key->val); - hcon->enc_key_size = key->pin_len; + hci_le_start_enc(hcon, key->ediv, key->rand, key->val); + hcon->enc_key_size = key->enc_size; return 1; @@ -819,13 +816,19 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; + struct hci_dev *hdev = conn->hcon->hdev; + struct hci_conn *hcon = conn->hcon; + u8 authenticated; skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, - rp->ediv, rp->rand, smp->tk); - + hci_dev_lock(hdev); + authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH); + hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, + HCI_SMP_LTK, 1, authenticated, smp->tk, + smp->enc_key_size, rp->ediv, rp->rand); smp_distribute_keys(conn, 1); + hci_dev_unlock(hdev); return 0; } @@ -935,6 +938,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (*keydist & SMP_DIST_ENC_KEY) { struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; + struct hci_conn *hcon = conn->hcon; + u8 authenticated; __le16 ediv; get_random_bytes(enc.ltk, sizeof(enc.ltk)); @@ -943,8 +948,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size, - ediv, ident.rand, enc.ltk); + authenticated = hcon->sec_level == BT_SECURITY_HIGH; + hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, + HCI_SMP_LTK_SLAVE, 1, authenticated, + enc.ltk, smp->enc_key_size, + ediv, ident.rand); ident.ediv = cpu_to_le16(ediv); -- cgit v1.2.3 From 346af67b8d116f01ef696fd47959a55deb2db8b6 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:02 -0300 Subject: Bluetooth: Add MGMT handlers for dealing with SMP LTK's This adds a method to notify that a new LTK is available and a handler to store keys coming from userspace into the kernel LTK list. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 + net/bluetooth/mgmt.c | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2649caf4db96..7793fc644b87 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -995,6 +995,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr); +int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); + /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad8986276848..fd0b08115f2e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2191,6 +2191,60 @@ done: return err; } +static int load_long_term_keys(struct sock *sk, u16 index, + void *cp_data, u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_load_long_term_keys *cp = cp_data; + u16 key_count, expected_len; + int i; + + if (len < sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + EINVAL); + + key_count = get_unaligned_le16(&cp->key_count); + + expected_len = sizeof(*cp) + key_count * + sizeof(struct mgmt_ltk_info); + if (expected_len != len) { + BT_ERR("load_keys: expected %u bytes, got %u bytes", + len, expected_len); + return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + EINVAL); + } + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + ENODEV); + + BT_DBG("hci%u key_count %u", index, key_count); + + hci_dev_lock(hdev); + + hci_smp_ltks_clear(hdev); + + for (i = 0; i < key_count; i++) { + struct mgmt_ltk_info *key = &cp->keys[i]; + u8 type; + + if (key->master) + type = HCI_SMP_LTK; + else + type = HCI_SMP_LTK_SLAVE; + + hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, + type, 0, key->authenticated, key->val, + key->enc_size, key->ediv, key->rand); + } + + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return 0; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { void *buf; @@ -2325,6 +2379,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_UNBLOCK_DEVICE: err = unblock_device(sk, index, cp, len); break; + case MGMT_OP_LOAD_LONG_TERM_KEYS: + err = load_long_term_keys(sk, index, cp, len); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, @@ -2478,6 +2535,29 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } +int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) +{ + struct mgmt_ev_new_long_term_key ev; + + memset(&ev, 0, sizeof(ev)); + + ev.store_hint = persistent; + bacpy(&ev.key.addr.bdaddr, &key->bdaddr); + ev.key.addr.type = key->bdaddr_type; + ev.key.authenticated = key->authenticated; + ev.key.enc_size = key->enc_size; + ev.key.ediv = key->ediv; + + if (key->type == HCI_SMP_LTK) + ev.key.master = 1; + + memcpy(ev.key.rand, key->rand, sizeof(key->rand)); + memcpy(ev.key.val, key->val, sizeof(key->val)); + + return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, + &ev, sizeof(ev), NULL); +} + int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *name, u8 name_len, u8 *dev_class) -- cgit v1.2.3 From b0dbfb46ba0c0d2fe4c90e2046f7b36275763a7e Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:03 -0300 Subject: Bluetooth: Add support for removing LTK's when pairing is removed Instead of having a separated command for removing SMP keys, we use the Remove Keys command to remove *all* keys. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fd0b08115f2e..9e5dead1dbef 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1089,6 +1089,12 @@ static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) bacpy(&rp.bdaddr, &cp->bdaddr); rp.status = MGMT_STATUS_FAILED; + err = hci_remove_ltk(hdev, &cp->bdaddr); + if (err < 0) { + err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err); + goto unlock; + } + err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { rp.status = MGMT_STATUS_NOT_PAIRED; -- cgit v1.2.3 From 261cc5aa9e54aac633dcc3b6469739cb6e23e21a Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Thu, 2 Feb 2012 21:08:05 -0300 Subject: Bluetooth: Add support for notifying userspace of new LTK's If we want to have proper pairing support over LE we need to inform userspace that a new LTK is available, so userspace can store that key permanently. Signed-off-by: Vinicius Costa Gomes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 84b7a9e4f2f6..76dc1538e321 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1338,6 +1338,9 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (!new_key) return 0; + if (type & HCI_SMP_LTK) + mgmt_new_ltk(hdev, key, 1); + return 0; } -- cgit v1.2.3 From b71d385a18cd4516c62d0198c9ec37e658112f75 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 3 Feb 2012 16:27:54 +0200 Subject: Bluetooth: Recalculate sched HCI blk/pkt flow ctrl Split HCI scheduling for block and packet flow control. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 85 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 76dc1538e321..9a56a4084482 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2384,18 +2384,19 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) } -static inline void hci_sched_acl(struct hci_dev *hdev) +static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) +{ + /* Calculate count of blocks used by this packet */ + return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); +} + +static inline void hci_sched_acl_pkt(struct hci_dev *hdev) { struct hci_chan *chan; struct sk_buff *skb; int quote; unsigned int cnt; - BT_DBG("%s", hdev->name); - - if (!hci_conn_num(hdev, ACL_LINK)) - return; - if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ @@ -2435,6 +2436,78 @@ static inline void hci_sched_acl(struct hci_dev *hdev) hci_prio_recalculate(hdev, ACL_LINK); } +static inline void hci_sched_acl_blk(struct hci_dev *hdev) +{ + struct hci_chan *chan; + struct sk_buff *skb; + int quote; + unsigned int cnt; + + if (!test_bit(HCI_RAW, &hdev->flags)) { + /* ACL tx timeout must be longer than maximum + * link supervision timeout (40.9 seconds) */ + if (!hdev->block_cnt && time_after(jiffies, hdev->acl_last_tx + + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) + hci_link_tx_to(hdev, ACL_LINK); + } + + cnt = hdev->block_cnt; + + while (hdev->block_cnt > 0 && + (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { + u32 priority = (skb_peek(&chan->data_q))->priority; + while (quote > 0 && (skb = skb_peek(&chan->data_q))) { + int blocks; + + BT_DBG("chan %p skb %p len %d priority %u", chan, skb, + skb->len, skb->priority); + + /* Stop if priority has changed */ + if (skb->priority < priority) + break; + + skb = skb_dequeue(&chan->data_q); + + blocks = __get_blocks(hdev, skb); + if (blocks > hdev->block_cnt) + return; + + hci_conn_enter_active_mode(chan->conn, + bt_cb(skb)->force_active); + + hci_send_frame(skb); + hdev->acl_last_tx = jiffies; + + hdev->block_cnt -= blocks; + quote -= blocks; + + chan->sent += blocks; + chan->conn->sent += blocks; + } + } + + if (cnt != hdev->block_cnt) + hci_prio_recalculate(hdev, ACL_LINK); +} + +static inline void hci_sched_acl(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (!hci_conn_num(hdev, ACL_LINK)) + return; + + switch (hdev->flow_ctl_mode) { + case HCI_FLOW_CTL_MODE_PACKET_BASED: + hci_sched_acl_pkt(hdev); + break; + + case HCI_FLOW_CTL_MODE_BLOCK_BASED: + hci_sched_acl_blk(hdev); + break; + } +} + /* Schedule SCO */ static inline void hci_sched_sco(struct hci_dev *hdev) { -- cgit v1.2.3 From 63d2bc1b9a4d77f90b9719c3ff2570a274a7a22f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 3 Feb 2012 16:27:55 +0200 Subject: Bluetooth: Helper removes duplicated code Use __check_timout helper to remove duplicated code Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9a56a4084482..95eeae59812d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2390,22 +2390,25 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); } -static inline void hci_sched_acl_pkt(struct hci_dev *hdev) +static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt) { - struct hci_chan *chan; - struct sk_buff *skb; - int quote; - unsigned int cnt; - if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + + if (!cnt && time_after(jiffies, hdev->acl_last_tx + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) hci_link_tx_to(hdev, ACL_LINK); } +} - cnt = hdev->acl_cnt; +static inline void hci_sched_acl_pkt(struct hci_dev *hdev) +{ + unsigned int cnt = hdev->acl_cnt; + struct hci_chan *chan; + struct sk_buff *skb; + int quote; + + __check_timeout(hdev, cnt); while (hdev->acl_cnt && (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { @@ -2438,20 +2441,12 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev) static inline void hci_sched_acl_blk(struct hci_dev *hdev) { + unsigned int cnt = hdev->block_cnt; struct hci_chan *chan; struct sk_buff *skb; int quote; - unsigned int cnt; - - if (!test_bit(HCI_RAW, &hdev->flags)) { - /* ACL tx timeout must be longer than maximum - * link supervision timeout (40.9 seconds) */ - if (!hdev->block_cnt && time_after(jiffies, hdev->acl_last_tx + - msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) - hci_link_tx_to(hdev, ACL_LINK); - } - cnt = hdev->block_cnt; + __check_timeout(hdev, cnt); while (hdev->block_cnt > 0 && (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { -- cgit v1.2.3 From 8af59467412b4b61850d3ccb3737c09ecc6dc100 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 3 Feb 2012 21:29:40 +0200 Subject: Bluetooth: Add missing QUIRK_NO_RESET test to hci_dev_do_close We should only perform a reset in hci_dev_do_close if the HCI_QUIRK_NO_RESET flag is set (since in such a case a reset will not be performed when initializing the device). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 95eeae59812d..8bffd3eb344d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -767,7 +767,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); - if (!test_bit(HCI_RAW, &hdev->flags)) { + if (!test_bit(HCI_RAW, &hdev->flags) && + test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); __hci_request(hdev, hci_reset_req, 0, msecs_to_jiffies(250)); -- cgit v1.2.3 From c599008f8f999dab8cb4a6404be99bdc4716ba15 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:47:57 -0300 Subject: Bluetooth: LE scan should send Discovering events Send MGMT Discovering events once LE scan starts/stops so the userspace can track when local adapters are discovering LE devices. This way, we also keep the same behavior of inquiry which sends MGMT Discovering events once inquiry starts/stops even if it is triggered by an external tool (e.g. hcitool). Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 2 ++ net/bluetooth/hci_event.c | 5 +++++ 3 files changed, 8 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9751da78341d..bf2ef5667887 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -61,6 +61,7 @@ struct discovery_state { DISCOVERY_STOPPED, DISCOVERY_STARTING, DISCOVERY_INQUIRY, + DISCOVERY_LE_SCAN, DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8bffd3eb344d..1705d9372725 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -361,6 +361,7 @@ bool hci_discovery_active(struct hci_dev *hdev) struct discovery_state *discov = &hdev->discovery; if (discov->state == DISCOVERY_INQUIRY || + discov->state == DISCOVERY_LE_SCAN || discov->state == DISCOVERY_RESOLVING) return true; @@ -381,6 +382,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STARTING: break; case DISCOVERY_INQUIRY: + case DISCOVERY_LE_SCAN: mgmt_discovering(hdev, 1); break; case DISCOVERY_RESOLVING: diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 23dbb31f0423..8971c18205c0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1056,12 +1056,17 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, hci_dev_lock(hdev); hci_adv_entries_clear(hdev); + hci_discovery_set_state(hdev, DISCOVERY_LE_SCAN); hci_dev_unlock(hdev); break; case LE_SCANNING_DISABLED: clear_bit(HCI_LE_SCAN, &hdev->dev_flags); + hci_dev_lock(hdev); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + hci_dev_unlock(hdev); + schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); break; -- cgit v1.2.3 From 6fbe195dc41c4fae1fa7aca1a38c888de1d24e2d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:47:58 -0300 Subject: Bluetooth: Minor code refactoring This patch does a trivial code refacting in hci_discovery_active. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1705d9372725..1175f27bd445 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -360,12 +360,15 @@ bool hci_discovery_active(struct hci_dev *hdev) { struct discovery_state *discov = &hdev->discovery; - if (discov->state == DISCOVERY_INQUIRY || - discov->state == DISCOVERY_LE_SCAN || - discov->state == DISCOVERY_RESOLVING) + switch (discov->state) { + case DISCOVERY_INQUIRY: + case DISCOVERY_LE_SCAN: + case DISCOVERY_RESOLVING: return true; - return false; + default: + return false; + } } void hci_discovery_set_state(struct hci_dev *hdev, int state) -- cgit v1.2.3 From 7ba8b4be38e7c83b2b13333a82a0ecde921a7390 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:47:59 -0300 Subject: Bluetooth: Add hci_do_le_scan() This patch adds to hci_core the hci_do_le_scan function which should be used to scan LE devices. In order to enable LE scan, hci_do_le_scan() sends commands (Set LE Scan Parameters and Set LE Scan Enable) to the controller and waits for its results. If commands were executed successfully a delayed work is scheduled to disable the ongoing scanning after some amount of time. This function blocks. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 8 +++++ net/bluetooth/hci_core.c | 74 ++++++++++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 13 +++++-- 3 files changed, 92 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bf2ef5667887..3e70872bffea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -122,6 +122,12 @@ struct adv_entry { u8 bdaddr_type; }; +struct le_scan_params { + u8 type; + u16 interval; + u16 window; +}; + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -261,6 +267,8 @@ struct hci_dev { unsigned long dev_flags; + struct delayed_work le_scan_disable; + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1175f27bd445..ae86cdd80ac0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -759,6 +759,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); + cancel_delayed_work_sync(&hdev->le_scan_disable); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); @@ -1596,6 +1598,76 @@ int hci_add_adv_entry(struct hci_dev *hdev, return 0; } +static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) +{ + struct le_scan_params *param = (struct le_scan_params *) opt; + struct hci_cp_le_set_scan_param cp; + + memset(&cp, 0, sizeof(cp)); + cp.type = param->type; + cp.interval = cpu_to_le16(param->interval); + cp.window = cpu_to_le16(param->window); + + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp); +} + +static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) +{ + struct hci_cp_le_set_scan_enable cp; + + memset(&cp, 0, sizeof(cp)); + cp.enable = 1; + + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); +} + +static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, + u16 window, int timeout) +{ + long timeo = msecs_to_jiffies(3000); + struct le_scan_params param; + int err; + + BT_DBG("%s", hdev->name); + + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return -EINPROGRESS; + + param.type = type; + param.interval = interval; + param.window = window; + + hci_req_lock(hdev); + + err = __hci_request(hdev, le_scan_param_req, (unsigned long) ¶m, + timeo); + if (!err) + err = __hci_request(hdev, le_scan_enable_req, 0, timeo); + + hci_req_unlock(hdev); + + if (err < 0) + return err; + + schedule_delayed_work(&hdev->le_scan_disable, + msecs_to_jiffies(timeout)); + + return 0; +} + +static void le_scan_disable_work(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, + le_scan_disable.work); + struct hci_cp_le_set_scan_enable cp; + + BT_DBG("%s", hdev->name); + + memset(&cp, 0, sizeof(cp)); + + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1682,6 +1754,8 @@ int hci_register_dev(struct hci_dev *hdev) atomic_set(&hdev->promisc, 0); + INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); + write_unlock(&hci_dev_list_lock); hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8971c18205c0..97152d9d7116 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1031,6 +1031,8 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); + + hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status); } static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, @@ -1041,15 +1043,17 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, 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; switch (cp->enable) { case LE_SCANNING_ENABLED: + hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status); + + if (status) + return; + set_bit(HCI_LE_SCAN, &hdev->dev_flags); cancel_delayed_work_sync(&hdev->adv_work); @@ -1061,6 +1065,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, break; case LE_SCANNING_DISABLED: + if (status) + return; + clear_bit(HCI_LE_SCAN, &hdev->dev_flags); hci_dev_lock(hdev); -- cgit v1.2.3 From 28b75a89480df99a17c8facd5c33985847d06bb6 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:48:00 -0300 Subject: Bluetooth: Add hci_le_scan() We are not supposed to block in start_discovery() because start_discovery code is running in write() syscall context and this would block the write operation on the mgmt socket. This way, we cannot directly call hci_do_le_scan() to scan LE devices in start_discovery(). To overcome this issue a derefered work (hdev->le_scan) was created so we can properly call hci_do_le_scan(). The helper function hci_le_scan() simply set LE scan parameters and queue hdev->le_scan work. The work is queued on system_long_wq since it can sleep for a few seconds in the worst case (timeout). Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 6 ++++++ net/bluetooth/hci_core.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3e70872bffea..7107790817a5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,6 +126,7 @@ struct le_scan_params { u8 type; u16 interval; u16 window; + int timeout; }; #define NUM_REASSEMBLY 4 @@ -269,6 +270,9 @@ struct hci_dev { struct delayed_work le_scan_disable; + struct work_struct le_scan; + struct le_scan_params le_scan_params; + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); @@ -1033,5 +1037,7 @@ void hci_le_ltk_neg_reply(struct hci_conn *conn); int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); +int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, + int timeout); #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ae86cdd80ac0..3d09f4b4ca68 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -735,6 +735,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); + cancel_work_sync(&hdev->le_scan); + hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); @@ -1668,6 +1670,37 @@ static void le_scan_disable_work(struct work_struct *work) hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } +static void le_scan_work(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan); + struct le_scan_params *param = &hdev->le_scan_params; + + BT_DBG("%s", hdev->name); + + hci_do_le_scan(hdev, param->type, param->interval, + param->window, param->timeout); +} + +int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, + int timeout) +{ + struct le_scan_params *param = &hdev->le_scan_params; + + BT_DBG("%s", hdev->name); + + if (work_busy(&hdev->le_scan)) + return -EINPROGRESS; + + param->type = type; + param->interval = interval; + param->window = window; + param->timeout = timeout; + + queue_work(system_long_wq, &hdev->le_scan); + + return 0; +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1754,6 +1787,8 @@ int hci_register_dev(struct hci_dev *hdev) atomic_set(&hdev->promisc, 0); + INIT_WORK(&hdev->le_scan, le_scan_work); + INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); write_unlock(&hci_dev_list_lock); -- cgit v1.2.3 From 3fd2415363629b779549705f341e0645e32c1ad5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:48:01 -0300 Subject: Bluetooth: MGMT start discovery LE-Only support This patch adds LE-Only discovery procedure support to MGMT Start Discovery command. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 13 ++++++++++++- net/bluetooth/mgmt.c | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 97152d9d7116..ad5f37b13f77 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1033,6 +1033,13 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status); + + if (status) { + hci_dev_lock(hdev); + mgmt_start_discovery_failed(hdev, status); + hci_dev_unlock(hdev); + return; + } } static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, @@ -1051,8 +1058,12 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, case LE_SCANNING_ENABLED: hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status); - if (status) + if (status) { + hci_dev_lock(hdev); + mgmt_start_discovery_failed(hdev, status); + hci_dev_unlock(hdev); return; + } set_bit(HCI_LE_SCAN, &hdev->dev_flags); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9e5dead1dbef..8c9de58779c7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,6 +35,15 @@ #define MGMT_VERSION 0 #define MGMT_REVISION 1 +/* + * These LE scan and inquiry parameters were chosen according to LE General + * Discovery Procedure specification. + */ +#define LE_SCAN_TYPE 0x01 +#define LE_SCAN_WIN 0x12 +#define LE_SCAN_INT 0x12 +#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */ + #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ #define SERVICE_CACHE_TIMEOUT (5 * 1000) @@ -1916,6 +1925,7 @@ static int start_discovery(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; + unsigned long discov_type = cp->type; struct pending_cmd *cmd; struct hci_dev *hdev; int err; @@ -1951,7 +1961,15 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + if (test_bit(MGMT_ADDR_BREDR, &discov_type)) + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) && + test_bit(MGMT_ADDR_LE_RANDOM, &discov_type)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + else + err = -EINVAL; + if (err < 0) mgmt_pending_remove(cmd); else -- cgit v1.2.3 From e87775250f322b8f1612cf9918fcde827948f087 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 3 Feb 2012 17:48:02 -0300 Subject: Bluetooth: Fix indentation This patch fixes a #define indentation in mgmt.c. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8c9de58779c7..de7326b111ba 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -44,7 +44,7 @@ #define LE_SCAN_INT 0x12 #define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */ -#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ +#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ #define SERVICE_CACHE_TIMEOUT (5 * 1000) -- cgit v1.2.3 From 053c7e0c4a40e2bb44e3c1e61e263be00688a136 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 4 Feb 2012 00:06:00 +0200 Subject: Bluetooth: Fix device_found event length for remote name resolving The correct length of the event is the size of the ev struct (not size of the pointer like the code was previously using) plus the length of the variable-sized EIR data at the end of the struct. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index de7326b111ba..11ee5db16e97 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2964,7 +2964,8 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, put_unaligned_le16(eir_len, &ev->eir_len); - return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, + sizeof(*ev) + eir_len, NULL); } int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) -- cgit v1.2.3 From 343fb14549a736b348b08e702057487a7ec44d5d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 22 Nov 2011 17:14:19 -0300 Subject: Bluetooth: Add BT_DBG to mgmt_discovering() This is helpful for device discovery implementation & debuging. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 11ee5db16e97..77bc5a4b026c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3002,6 +3002,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) { struct pending_cmd *cmd; + BT_DBG("%s discovering %u", hdev->name, discovering); + if (discovering) cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev); else -- cgit v1.2.3 From cf4cd00915c659dc7b496c454bee36bb6b833fd1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 6 Feb 2012 15:03:59 +0200 Subject: Bluetooth: Change chan_ready param from sk to chan Change is needed to remove dependency on sk when possible before introducing l2cap channel lock. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 09cd8601ea81..80fbfcf0674d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -907,9 +907,9 @@ clean: release_sock(parent); } -static void l2cap_chan_ready(struct sock *sk) +static void l2cap_chan_ready(struct l2cap_chan *chan) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct sock *sk = chan->sk; struct sock *parent = bt_sk(sk)->parent; BT_DBG("sk %p, parent %p", sk, parent); @@ -945,7 +945,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->type == LE_LINK) { if (smp_conn_security(conn, chan->sec_level)) - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); @@ -2874,7 +2874,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); goto unlock; } @@ -3005,7 +3005,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } done: @@ -4524,7 +4524,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (chan->scid == L2CAP_CID_LE_DATA) { if (!status && encrypt) { chan->sec_level = hcon->sec_level; - l2cap_chan_ready(sk); + l2cap_chan_ready(chan); } bh_unlock_sock(sk); -- cgit v1.2.3 From 5491120e75afe2a7f5b6f3a207de6d99934e5475 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 6 Feb 2012 15:04:00 +0200 Subject: Bluetooth: Clean up l2cap_chan_add Change elseif to switch. This make sense even more with following patches which otherwise have to add more elseifs statements. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 80fbfcf0674d..48fc01ef16b6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -320,7 +320,8 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->conn = conn; - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { + switch (chan->chan_type) { + case L2CAP_CHAN_CONN_ORIENTED: if (conn->hcon->type == LE_LINK) { /* LE connection */ chan->omtu = L2CAP_LE_DEFAULT_MTU; @@ -331,12 +332,16 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->scid = l2cap_alloc_cid(conn); chan->omtu = L2CAP_DEFAULT_MTU; } - } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { + break; + + case L2CAP_CHAN_CONN_LESS: /* Connectionless socket */ chan->scid = L2CAP_CID_CONN_LESS; chan->dcid = L2CAP_CID_CONN_LESS; chan->omtu = L2CAP_DEFAULT_MTU; - } else { + break; + + default: /* Raw socket can send/recv signalling messages only */ chan->scid = L2CAP_CID_SIGNALING; chan->dcid = L2CAP_CID_SIGNALING; -- cgit v1.2.3 From 6d5922b01b5e8d684dae5baaea596a4a749738e3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 6 Feb 2012 15:04:01 +0200 Subject: Bluetooth: Remove unneeded sk variable In debug use chan %p instead of sk. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 48fc01ef16b6..f1a6b3cbdba7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1561,13 +1561,12 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d priority %u", sk, (int)len, priority); + BT_DBG("chan %p len %d priority %u", chan, (int)len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1597,13 +1596,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("chan %p len %d", chan, (int)len); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1632,13 +1630,12 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 control, u16 sdulen) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, (int)len); + BT_DBG("chan %p len %d", chan, (int)len); if (!conn) return ERR_PTR(-ENOTCONN); -- cgit v1.2.3 From 8ed7a0ae7834cbefb82ed15a92e36983924efa23 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 7 Feb 2012 15:43:01 +0100 Subject: Bluetooth: Fix possible missing I-Frame acknowledgement Make l2cap_ertm_send return number of pending I-Frames transmitted instead of all (pending + retransmitted) I-Frames transmitted. As only pending I-Frames are considered as acknowledgement, this could lead to situation when no ACK was sent in __l2cap_send_ack (if only already transmitted I-Frames were retransmitted). Signed-off-by: Szymon Janc Signed-off-by: Luiz Augusto von Dentz Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f1a6b3cbdba7..9add85271658 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1453,8 +1453,10 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - if (bt_cb(skb)->retries == 1) + if (bt_cb(skb)->retries == 1) { chan->unacked_frames++; + nsent++; + } chan->frames_sent++; @@ -1462,8 +1464,6 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) chan->tx_send_head = NULL; else chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); - - nsent++; } return nsent; -- cgit v1.2.3 From 930fa4aee934ad59ed82163cdbee4922b883ef79 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 7 Feb 2012 15:43:02 +0100 Subject: Bluetooth: Fix double acking I-Frames when sending pending I-Frames Pending I-Frame(s) are considered as acknowledgement. To void double acking (via I-Frame and later via RR) clear ack timer when sending first pending I-Frame. Signed-off-by: Szymon Janc Signed-off-by: Luiz Augusto von Dentz Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9add85271658..8efac7884ffb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1455,7 +1455,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) if (bt_cb(skb)->retries == 1) { chan->unacked_frames++; - nsent++; + + if (!nsent++) + __clear_ack_timer(chan); } chan->frames_sent++; -- cgit v1.2.3 From 124f6e35286c9d8dc96f147a9026081256136615 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 13:50:12 +0200 Subject: Bluetooth: Update and rename mgmt_remove_keys to mgmt_unpair_device This patch renames the mgmt_remove_keys command to mgmt_unpair_device and updates its parameters to match the latest API (specifically, it adds an address type parameter to the command and its response). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 34 ++++++++++++------------- net/bluetooth/mgmt.c | 60 +++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 43 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 72975fd53988..4c18cd5fb8c1 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -175,17 +175,7 @@ struct mgmt_cp_load_long_term_keys { struct mgmt_ltk_info keys[0]; } __packed; -#define MGMT_OP_REMOVE_KEYS 0x0014 -struct mgmt_cp_remove_keys { - bdaddr_t bdaddr; - __u8 disconnect; -} __packed; -struct mgmt_rp_remove_keys { - bdaddr_t bdaddr; - __u8 status; -}; - -#define MGMT_OP_DISCONNECT 0x0015 +#define MGMT_OP_DISCONNECT 0x0014 struct mgmt_cp_disconnect { bdaddr_t bdaddr; } __packed; @@ -194,13 +184,13 @@ struct mgmt_rp_disconnect { __u8 status; } __packed; -#define MGMT_OP_GET_CONNECTIONS 0x0016 +#define MGMT_OP_GET_CONNECTIONS 0x0015 struct mgmt_rp_get_connections { __le16 conn_count; struct mgmt_addr_info addr[0]; } __packed; -#define MGMT_OP_PIN_CODE_REPLY 0x0017 +#define MGMT_OP_PIN_CODE_REPLY 0x0016 struct mgmt_cp_pin_code_reply { bdaddr_t bdaddr; __u8 pin_len; @@ -211,17 +201,17 @@ struct mgmt_rp_pin_code_reply { uint8_t status; } __packed; -#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0018 +#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017 struct mgmt_cp_pin_code_neg_reply { bdaddr_t bdaddr; } __packed; -#define MGMT_OP_SET_IO_CAPABILITY 0x0019 +#define MGMT_OP_SET_IO_CAPABILITY 0x0018 struct mgmt_cp_set_io_capability { __u8 io_capability; } __packed; -#define MGMT_OP_PAIR_DEVICE 0x001A +#define MGMT_OP_PAIR_DEVICE 0x0019 struct mgmt_cp_pair_device { struct mgmt_addr_info addr; __u8 io_cap; @@ -231,7 +221,17 @@ struct mgmt_rp_pair_device { __u8 status; } __packed; -#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001B +#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A + +#define MGMT_OP_UNPAIR_DEVICE 0x001B +struct mgmt_cp_unpair_device { + struct mgmt_addr_info addr; + __u8 disconnect; +} __packed; +struct mgmt_rp_unpair_device { + struct mgmt_addr_info addr; + __u8 status; +}; #define MGMT_OP_USER_CONFIRM_REPLY 0x001C struct mgmt_cp_user_confirm_reply { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 77bc5a4b026c..c64e5db7f596 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1073,57 +1073,63 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) return 0; } -static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) +static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_remove_keys *cp = data; - struct mgmt_rp_remove_keys rp; + struct mgmt_cp_unpair_device *cp = data; + struct mgmt_rp_unpair_device rp; struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; int err; if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, + return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, + return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); memset(&rp, 0, sizeof(rp)); - bacpy(&rp.bdaddr, &cp->bdaddr); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; rp.status = MGMT_STATUS_FAILED; - err = hci_remove_ltk(hdev, &cp->bdaddr); - if (err < 0) { - err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err); - goto unlock; - } + if (cp->addr.type == MGMT_ADDR_BREDR) + err = hci_remove_link_key(hdev, &cp->addr.bdaddr); + else + err = hci_remove_ltk(hdev, &cp->addr.bdaddr); - err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { rp.status = MGMT_STATUS_NOT_PAIRED; goto unlock; } if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); goto unlock; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (cp->addr.type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + &cp->addr.bdaddr); + else + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, + &cp->addr.bdaddr); + if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); goto unlock; } - cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp)); + cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp, + sizeof(*cp)); if (!cmd) { err = -ENOMEM; goto unlock; @@ -1137,7 +1143,7 @@ static int remove_keys(struct sock *sk, u16 index, void *data, u16 len) unlock: if (err < 0) - err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2340,9 +2346,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_LOAD_LINK_KEYS: err = load_link_keys(sk, index, cp, len); break; - case MGMT_OP_REMOVE_KEYS: - err = remove_keys(sk, index, cp, len); - break; case MGMT_OP_DISCONNECT: err = disconnect(sk, index, cp, len); break; @@ -2364,6 +2367,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_CANCEL_PAIR_DEVICE: err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_UNPAIR_DEVICE: + err = unpair_device(sk, index, cp, len); + break; case MGMT_OP_USER_CONFIRM_REPLY: err = user_confirm_reply(sk, index, cp, len); break; @@ -2624,18 +2630,19 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) mgmt_pending_remove(cmd); } -static void remove_keys_rsp(struct pending_cmd *cmd, void *data) +static void unpair_device_rsp(struct pending_cmd *cmd, void *data) { u8 *status = data; - struct mgmt_cp_remove_keys *cp = cmd->param; - struct mgmt_rp_remove_keys rp; + struct mgmt_cp_unpair_device *cp = cmd->param; + struct mgmt_rp_unpair_device rp; memset(&rp, 0, sizeof(rp)); - bacpy(&rp.bdaddr, &cp->bdaddr); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; if (status != NULL) rp.status = *status; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp, + cmd_complete(cmd->sk, cmd->index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -2659,7 +2666,8 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, if (sk) sock_put(sk); - mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL); + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, + NULL); return err; } -- cgit v1.2.3 From 88c3df13ca06718e5a8f509ae9cbb1228c10d537 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 14:27:38 +0200 Subject: Bluetooth: Update mgmt_disconnect to match latest API This patch adds an address type parameter to the disconnect command and response in order to match the latest mgmt API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/hci_event.c | 28 +++++++++++++++++++++++++--- net/bluetooth/mgmt.c | 28 +++++++++++++--------------- 4 files changed, 42 insertions(+), 21 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7107790817a5..634a0cdcdad6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -958,7 +958,8 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); -int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); +int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4c18cd5fb8c1..735e547e3448 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -177,10 +177,10 @@ struct mgmt_cp_load_long_term_keys { #define MGMT_OP_DISCONNECT 0x0014 struct mgmt_cp_disconnect { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; struct mgmt_rp_disconnect { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ad5f37b13f77..f0c822db28d9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1550,6 +1550,28 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) hci_dev_unlock(hdev); } +static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_disconnect *cp; + struct hci_conn *conn; + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) + mgmt_disconnect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, status); + + hci_dev_unlock(hdev); +} + static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) { struct hci_cp_le_create_conn *cp; @@ -1839,7 +1861,8 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && (conn->type == ACL_LINK || conn->type == LE_LINK)) { if (ev->status != 0) - mgmt_disconnect_failed(hdev, &conn->dst, ev->status); + mgmt_disconnect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, ev->status); else mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type); @@ -2350,8 +2373,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) break; case HCI_OP_DISCONNECT: - if (ev->status != 0) - mgmt_disconnect_failed(hdev, NULL, ev->status); + hci_cs_disconnect(hdev, ev->status); break; case HCI_OP_LE_CREATE_CONN: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c64e5db7f596..f1257ee5afbc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1185,9 +1185,10 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - if (!conn) - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (cp->addr.type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); + else + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); if (!conn) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, @@ -2619,7 +2620,8 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) struct sock **sk = data; struct mgmt_rp_disconnect rp; - bacpy(&rp.bdaddr, &cp->bdaddr); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; rp.status = 0; cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); @@ -2672,27 +2674,23 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, return err; } -int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) +int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) { + struct mgmt_rp_disconnect rp; struct pending_cmd *cmd; - u8 mgmt_err = mgmt_status(status); int err; cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev); if (!cmd) return -ENOENT; - if (bdaddr) { - struct mgmt_rp_disconnect rp; - - bacpy(&rp.bdaddr, bdaddr); - rp.status = status; + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = link_to_mgmt(link_type, addr_type); + rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, + err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); - } else - err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, - mgmt_err); mgmt_pending_remove(cmd); -- cgit v1.2.3 From 272d90df2d4d065e782cafb08358bd8918bf703a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:26:12 +0200 Subject: Bluetooth: Add address type to user_confirm and user_passkey messages This patch upadate the user confirm and user passkey mgmt messages to match the latest API specification by adding an address type parameter to them. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 18 ++++---- include/net/bluetooth/mgmt.h | 16 +++---- net/bluetooth/hci_event.c | 14 +++--- net/bluetooth/mgmt.c | 98 ++++++++++++++++++++-------------------- net/bluetooth/smp.c | 4 +- 5 files changed, 79 insertions(+), 71 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 634a0cdcdad6..5f27694068f2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -968,16 +968,18 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - __le32 value, u8 confirm_hint); + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint); int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); -int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status); -int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr); + u8 link_type, u8 addr_type, u8 status); +int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); +int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type); int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); -int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status); + u8 link_type, u8 addr_type, u8 status); +int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); 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, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 735e547e3448..378d498896b3 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -235,31 +235,31 @@ struct mgmt_rp_unpair_device { #define MGMT_OP_USER_CONFIRM_REPLY 0x001C struct mgmt_cp_user_confirm_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; struct mgmt_rp_user_confirm_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D struct mgmt_cp_user_confirm_neg_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_USER_PASSKEY_REPLY 0x001E struct mgmt_cp_user_passkey_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __le32 passkey; } __packed; struct mgmt_rp_user_passkey_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; #define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F struct mgmt_cp_user_passkey_neg_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020 @@ -376,14 +376,14 @@ struct mgmt_ev_pin_code_request { #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F struct mgmt_ev_user_confirm_request { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 confirm_hint; __le32 value; } __packed; #define MGMT_EV_USER_PASSKEY_REQUEST 0x0010 struct mgmt_ev_user_passkey_request { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_EV_AUTH_FAILED 0x0011 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f0c822db28d9..3bf3f4d59bcc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -960,8 +960,8 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, - rp->status); + mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, + 0, rp->status); hci_dev_unlock(hdev); } @@ -977,6 +977,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); @@ -991,8 +992,8 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, - rp->status); + mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK, + 0, rp->status); hci_dev_unlock(hdev); } @@ -1008,6 +1009,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr, + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); @@ -3123,7 +3125,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, } confirm: - mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey, + mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey, confirm_hint); unlock: @@ -3140,7 +3142,7 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_passkey_request(hdev, &ev->bdaddr); + mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0); hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f1257ee5afbc..16fc828096f6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1629,7 +1629,8 @@ unlock: } static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, - u16 mgmt_op, u16 hci_op, __le32 passkey) + u8 type, u16 mgmt_op, u16 hci_op, + __le32 passkey) { struct pending_cmd *cmd; struct hci_dev *hdev; @@ -1648,24 +1649,18 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, goto done; } - /* - * Check for an existing ACL link, if present pair via - * HCI commands. - * - * If no ACL link is present, check for an LE link and if - * present, pair via the SMP engine. - * - * If neither ACL nor LE links are present, fail with error. - */ - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); - if (!conn) { + if (type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); + else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); - if (!conn) { - err = cmd_status(sk, index, mgmt_op, + + if (!conn) { + err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_CONNECTED); - goto done; - } + goto done; + } + if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) { /* Continue with pairing via SMP */ err = smp_user_confirm_reply(conn, mgmt_op, passkey); @@ -1715,9 +1710,9 @@ static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_CONFIRM_REPLY, - HCI_OP_USER_CONFIRM_REPLY, 0); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_CONFIRM_REPLY, + HCI_OP_USER_CONFIRM_REPLY, 0); } static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, @@ -1731,9 +1726,9 @@ static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_CONFIRM_NEG_REPLY, - HCI_OP_USER_CONFIRM_NEG_REPLY, 0); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_CONFIRM_NEG_REPLY, + HCI_OP_USER_CONFIRM_NEG_REPLY, 0); } static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) @@ -1746,9 +1741,10 @@ static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY, EINVAL); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_PASSKEY_REPLY, - HCI_OP_USER_PASSKEY_REPLY, cp->passkey); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_PASSKEY_REPLY, + HCI_OP_USER_PASSKEY_REPLY, + cp->passkey); } static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, @@ -1762,9 +1758,9 @@ static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY, EINVAL); - return user_pairing_resp(sk, index, &cp->bdaddr, - MGMT_OP_USER_PASSKEY_NEG_REPLY, - HCI_OP_USER_PASSKEY_NEG_REPLY, 0); + return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_USER_PASSKEY_NEG_REPLY, + HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } static int set_local_name(struct sock *sk, u16 index, void *data, @@ -2765,13 +2761,15 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - __le32 value, u8 confirm_hint) + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; BT_DBG("%s", hdev->name); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_mgmt(link_type, addr_type); ev.confirm_hint = confirm_hint; put_unaligned_le32(value, &ev.value); @@ -2779,20 +2777,23 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, NULL); } -int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr) +int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type) { struct mgmt_ev_user_passkey_request ev; BT_DBG("%s", hdev->name); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_mgmt(link_type, addr_type); return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), NULL); } static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status, u8 opcode) + u8 link_type, u8 addr_type, u8 status, + u8 opcode) { struct pending_cmd *cmd; struct mgmt_rp_user_confirm_reply rp; @@ -2802,7 +2803,8 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return -ENOENT; - bacpy(&rp.bdaddr, bdaddr); + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = link_to_mgmt(link_type, addr_type); rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); @@ -2812,31 +2814,31 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_CONFIRM_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_CONFIRM_REPLY); } -int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status) +int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_CONFIRM_NEG_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_CONFIRM_NEG_REPLY); } int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_PASSKEY_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_PASSKEY_REPLY); } -int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 status) +int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) { - return user_pairing_resp_complete(hdev, bdaddr, status, - MGMT_OP_USER_PASSKEY_NEG_REPLY); + return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, + status, MGMT_OP_USER_PASSKEY_NEG_REPLY); } int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0563f737779a..589766d06f22 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -349,9 +349,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, hci_dev_lock(hcon->hdev); if (method == REQ_PASSKEY) - ret = mgmt_user_passkey_request(hcon->hdev, conn->dst); + ret = mgmt_user_passkey_request(hcon->hdev, conn->dst, + hcon->type, hcon->dst_type); else ret = mgmt_user_confirm_request(hcon->hdev, conn->dst, + hcon->type, hcon->dst_type, cpu_to_le32(passkey), 0); hci_dev_unlock(hcon->hdev); -- cgit v1.2.3 From 664ce4cc293cd6c76236617f78689d0e03e69287 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:44:09 +0200 Subject: Bluetooth: Add address type to Out Of Band mgmt messages This patch updates the implementation for these mgmt to be up to date with the latest API specification. Right now the address type isn't actually used for anything but that might change in the future. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/mgmt.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 378d498896b3..f284499b5f7f 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -270,14 +270,14 @@ struct mgmt_rp_read_local_oob_data { #define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021 struct mgmt_cp_add_remote_oob_data { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 hash[16]; __u8 randomizer[16]; } __packed; #define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022 struct mgmt_cp_remove_remote_oob_data { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_START_DISCOVERY 0x0023 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 16fc828096f6..763a447b2532 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1875,7 +1875,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); - err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, @@ -1910,7 +1910,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, hci_dev_lock(hdev); - err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); + err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); -- cgit v1.2.3 From 88c1fe4ba55c7245ad2f3c81689f854287875121 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:56:11 +0200 Subject: Bluetooth: Add address type to mgmt blacklist messages This patch updates the implmentation for mgmt_block_device and mgmt_unblock_device and their corresponding events to match the latest API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 8 ++++---- include/net/bluetooth/mgmt.h | 8 ++++---- net/bluetooth/hci_core.c | 8 ++++---- net/bluetooth/hci_sock.c | 4 ++-- net/bluetooth/mgmt.c | 14 ++++++++------ 5 files changed, 22 insertions(+), 20 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5f27694068f2..14a655f3929c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -646,8 +646,8 @@ int hci_inquiry(void __user *arg); struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_blacklist_clear(struct hci_dev *hdev); -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_uuids_clear(struct hci_dev *hdev); @@ -992,8 +992,8 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); -int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr); -int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr); +int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index f284499b5f7f..92f85c834677 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -299,12 +299,12 @@ struct mgmt_rp_confirm_name { #define MGMT_OP_BLOCK_DEVICE 0x0026 struct mgmt_cp_block_device { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_UNBLOCK_DEVICE 0x0027 struct mgmt_cp_unblock_device { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_EV_CMD_COMPLETE 0x0001 @@ -405,10 +405,10 @@ struct mgmt_ev_device_found { #define MGMT_EV_DEVICE_BLOCKED 0x0014 struct mgmt_ev_device_blocked { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_EV_DEVICE_UNBLOCKED 0x0015 struct mgmt_ev_device_unblocked { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3d09f4b4ca68..9ada16449aed 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1489,7 +1489,7 @@ int hci_blacklist_clear(struct hci_dev *hdev) return 0; } -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; @@ -1507,10 +1507,10 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) list_add(&entry->list, &hdev->blacklist); - return mgmt_device_blocked(hdev, bdaddr); + return mgmt_device_blocked(hdev, bdaddr, type); } -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; @@ -1524,7 +1524,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) list_del(&entry->list); kfree(entry); - return mgmt_device_unblocked(hdev, bdaddr); + return mgmt_device_unblocked(hdev, bdaddr, type); } static void hci_clear_adv_cache(struct work_struct *work) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0dcc96266779..9e854d9fb460 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -190,7 +190,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &bdaddr); + err = hci_blacklist_add(hdev, &bdaddr, 0); hci_dev_unlock(hdev); @@ -207,7 +207,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &bdaddr); + err = hci_blacklist_del(hdev, &bdaddr, 0); hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 763a447b2532..413a0b97c533 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2114,7 +2114,7 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &cp->bdaddr); + err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_FAILED); @@ -2147,7 +2147,7 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &cp->bdaddr); + err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, @@ -3026,27 +3026,29 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) sizeof(discovering), NULL); } -int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr) +int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct pending_cmd *cmd; struct mgmt_ev_device_blocked ev; cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); } -int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr) +int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct pending_cmd *cmd; struct mgmt_ev_device_unblocked ev; cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev); - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); -- cgit v1.2.3 From bab73cb68435232ba78a4bd1ac1a85862e3be0bb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 16:07:29 +0200 Subject: Bluetooth: Add address type to mgmt_ev_auth_failed This patch updates the Authentication Failed mgmt event to match the latest API specification by adding an address type to it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/hci_event.c | 6 ++++-- net/bluetooth/mgmt.c | 6 ++++-- net/bluetooth/smp.c | 5 ++++- 5 files changed, 15 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 14a655f3929c..ccb24a4212cd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -980,7 +980,8 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); -int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); +int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, u8 status); 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); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 92f85c834677..17bbf8bf04ae 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -388,7 +388,7 @@ struct mgmt_ev_user_passkey_request { #define MGMT_EV_AUTH_FAILED 0x0011 struct mgmt_ev_auth_failed { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3bf3f4d59bcc..b0784ee5f8b9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1901,7 +1901,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->sec_level = conn->pending_sec_level; } } else { - mgmt_auth_failed(hdev, &conn->dst, ev->status); + mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, + ev->status); } clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); @@ -3166,7 +3167,8 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) - mgmt_auth_failed(hdev, &conn->dst, ev->status); + mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, + ev->status); hci_conn_put(conn); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 413a0b97c533..545919828562 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2841,11 +2841,13 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, status, MGMT_OP_USER_PASSKEY_NEG_REPLY); } -int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) +int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, u8 status) { struct mgmt_ev_auth_failed ev; - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_mgmt(link_type, addr_type); ev.status = mgmt_status(status); return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 589766d06f22..f6a6d8be3051 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -257,12 +257,15 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) { + struct hci_conn *hcon = conn->hcon; + if (send) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); - mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); + mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, + hcon->dst_type, reason); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { cancel_delayed_work_sync(&conn->security_timer); -- cgit v1.2.3 From 82eb703efc2ad2ac52cada85a5119bb9dfcea942 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 17:19:27 +0200 Subject: Bluetooth: Fix mgmt_unpair_device command status The default response status to unpair_device should be set as 0 instead of a generic failure value. When disconnection is not needed (i.e. we can reply imediately) we should return success and not failure. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 545919828562..0cf0f4dc8213 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1097,7 +1097,6 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - rp.status = MGMT_STATUS_FAILED; if (cp->addr.type == MGMT_ADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); -- cgit v1.2.3 From b1078ad0be344e7bec6e7991f33df17565d24e08 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 17:21:16 +0200 Subject: Bluetooth: Add Device Unpaired mgmt event This patch add a new Device Unpaired mgmt event. This will be sent to all mgmt sockets except the one that requested unpairing (that socket will get a command complete instead). The event is also reserved for future SMP updates where a remote device will be able to request pairing revocation from us. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 5 +++++ net/bluetooth/mgmt.c | 27 +++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 17bbf8bf04ae..5b5edeed59e2 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -412,3 +412,8 @@ struct mgmt_ev_device_blocked { struct mgmt_ev_device_unblocked { struct mgmt_addr_info addr; } __packed; + +#define MGMT_EV_DEVICE_UNPAIRED 0x0016 +struct mgmt_ev_device_unpaired { + struct mgmt_addr_info addr; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0cf0f4dc8213..a2c2e12516c6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1073,6 +1073,18 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) return 0; } +static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, struct sock *skip_sk) +{ + struct mgmt_ev_device_unpaired ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = addr_type; + + return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev), + skip_sk); +} + static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; @@ -1111,6 +1123,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -1124,6 +1137,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) if (!conn) { err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, sizeof(rp)); + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -2629,18 +2643,17 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) static void unpair_device_rsp(struct pending_cmd *cmd, void *data) { - u8 *status = data; + struct hci_dev *hdev = data; struct mgmt_cp_unpair_device *cp = cmd->param; struct mgmt_rp_unpair_device rp; memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - if (status != NULL) - rp.status = *status; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); + + cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp)); mgmt_pending_remove(cmd); } @@ -2664,7 +2677,7 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, sock_put(sk); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, - NULL); + hdev); return err; } @@ -2689,6 +2702,8 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, mgmt_pending_remove(cmd); + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, + hdev); return err; } -- cgit v1.2.3 From aa2b86d761a95068354511de755695ef6b53afc7 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 9 Feb 2012 21:58:30 +0100 Subject: Bluetooth: Introduce to_hci_dev() We currently use dev_set_drvdata to keep a pointer to ourself. This doesn't make sense as we are the bus and not a driver. Therefore, introduce to_hci_dev() so we can get a struct hci_dev pointer from a struct device pointer. dev_set/get_drvdata() is reserved for drivers that provide a device and not for the bus using the device. The bus can use simple pointer arithmetic to retrieve its private data. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_sysfs.c | 33 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ccb24a4212cd..221d772ded55 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -623,6 +623,8 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) #define hci_dev_lock(d) mutex_lock(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) +#define to_hci_dev(d) container_of(d, struct hci_dev, dev) + struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index ec03ee2b301e..2a0243add1e4 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -189,19 +189,19 @@ static inline char *host_typetostr(int type) static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", host_bustostr(hdev->bus)); } static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type)); } static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); char name[HCI_MAX_NAME_LENGTH + 1]; int i; @@ -214,20 +214,20 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); } static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", batostr(&hdev->bdaddr)); } static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", hdev->features[0], hdev->features[1], @@ -238,31 +238,31 @@ static ssize_t show_features(struct device *dev, struct device_attribute *attr, static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->manufacturer); } static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->hci_ver); } static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->hci_rev); } static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->idle_timeout); } static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); unsigned int val; int rv; @@ -280,13 +280,13 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->sniff_max_interval); } static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); u16 val; int rv; @@ -304,13 +304,13 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->sniff_min_interval); } static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = dev_get_drvdata(dev); + struct hci_dev *hdev = to_hci_dev(dev); u16 val; int rv; @@ -370,7 +370,7 @@ static const struct attribute_group *bt_host_groups[] = { static void bt_host_release(struct device *dev) { - void *data = dev_get_drvdata(dev); + void *data = to_hci_dev(dev); kfree(data); module_put(THIS_MODULE); } @@ -525,7 +525,6 @@ void hci_init_sysfs(struct hci_dev *hdev) dev->class = bt_class; __module_get(THIS_MODULE); - dev_set_drvdata(dev, hdev); device_initialize(dev); } -- cgit v1.2.3 From 3dc07322b1ce3c8477690d54ebbf15a165f43066 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 9 Feb 2012 21:58:33 +0100 Subject: Bluetooth: Introduce to_hci_conn This avoids using the dev_set/get_drvdata() functions to retrieve a pointer to our own structure. We can use simple pointer arithmetic here. The drvdata field is actually not needed by any other code-path but this makes the code more consistent with hci_dev. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_sysfs.c | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4559189a22a1..b20d990436b4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -623,6 +623,7 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) #define hci_dev_unlock(d) mutex_unlock(&d->lock) #define to_hci_dev(d) container_of(d, struct hci_dev, dev) +#define to_hci_conn(c) container_of(c, struct hci_conn, dev) static inline void *hci_get_drvdata(struct hci_dev *hdev) { diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 2a0243add1e4..17e6cd48ad4d 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -33,19 +33,19 @@ static inline char *link_typetostr(int type) static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_conn *conn = dev_get_drvdata(dev); + struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "%s\n", link_typetostr(conn->type)); } static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_conn *conn = dev_get_drvdata(dev); + struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "%s\n", batostr(&conn->dst)); } static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_conn *conn = dev_get_drvdata(dev); + struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", conn->features[0], conn->features[1], @@ -79,7 +79,7 @@ static const struct attribute_group *bt_link_groups[] = { static void bt_link_release(struct device *dev) { - void *data = dev_get_drvdata(dev); + void *data = to_hci_conn(dev); kfree(data); } @@ -120,8 +120,6 @@ void hci_conn_add_sysfs(struct hci_conn *conn) dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); - dev_set_drvdata(&conn->dev, conn); - if (device_add(&conn->dev) < 0) { BT_ERR("Failed to register connection device"); return; -- cgit v1.2.3 From 2dd106887d6503819f2cedc408497023547439bb Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 9 Feb 2012 21:58:34 +0100 Subject: Bluetooth: Use proper datatypes in release-callbacks This enhances code readability a lot and avoids using void* even though we know the type of the variable. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 17e6cd48ad4d..bc154298979a 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -79,8 +79,8 @@ static const struct attribute_group *bt_link_groups[] = { static void bt_link_release(struct device *dev) { - void *data = to_hci_conn(dev); - kfree(data); + struct hci_conn *conn = to_hci_conn(dev); + kfree(conn); } static struct device_type bt_link = { @@ -368,8 +368,8 @@ static const struct attribute_group *bt_host_groups[] = { static void bt_host_release(struct device *dev) { - void *data = to_hci_dev(dev); - kfree(data); + struct hci_dev *hdev = to_hci_dev(dev); + kfree(hdev); module_put(THIS_MODULE); } -- cgit v1.2.3 From e70bb2e89959983aebcfce28f645a1104ffa9ab2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Feb 2012 16:59:33 +0200 Subject: Bluetooth: Implement Read Supported Commands commands for mgmt This patch implements the Read Supported Commands mgmt command which was recently added to the API specification. It returns a list of supported commands and events to user space. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 7 ++++ net/bluetooth/mgmt.c | 99 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5b5edeed59e2..255a99600f08 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -63,6 +63,13 @@ struct mgmt_rp_read_version { __le16 revision; } __packed; +#define MGMT_OP_READ_COMMANDS 0x0002 +struct mgmt_rp_read_commands { + __le16 num_commands; + __le16 num_events; + __le16 opcodes[0]; +} __packed; + #define MGMT_OP_READ_INDEX_LIST 0x0003 struct mgmt_rp_read_index_list { __le16 num_controllers; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a2c2e12516c6..8efbd8eaa1b3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,6 +35,69 @@ #define MGMT_VERSION 0 #define MGMT_REVISION 1 +static const u16 mgmt_commands[] = { + MGMT_OP_READ_INDEX_LIST, + MGMT_OP_READ_INFO, + MGMT_OP_SET_POWERED, + MGMT_OP_SET_DISCOVERABLE, + MGMT_OP_SET_CONNECTABLE, + MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_OP_SET_PAIRABLE, + MGMT_OP_SET_LINK_SECURITY, + MGMT_OP_SET_SSP, + MGMT_OP_SET_HS, + MGMT_OP_SET_LE, + MGMT_OP_SET_DEV_CLASS, + MGMT_OP_SET_LOCAL_NAME, + MGMT_OP_ADD_UUID, + MGMT_OP_REMOVE_UUID, + MGMT_OP_LOAD_LINK_KEYS, + MGMT_OP_LOAD_LONG_TERM_KEYS, + MGMT_OP_DISCONNECT, + MGMT_OP_GET_CONNECTIONS, + MGMT_OP_PIN_CODE_REPLY, + MGMT_OP_PIN_CODE_NEG_REPLY, + MGMT_OP_SET_IO_CAPABILITY, + MGMT_OP_PAIR_DEVICE, + MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_OP_UNPAIR_DEVICE, + MGMT_OP_USER_CONFIRM_REPLY, + MGMT_OP_USER_CONFIRM_NEG_REPLY, + MGMT_OP_USER_PASSKEY_REPLY, + MGMT_OP_USER_PASSKEY_NEG_REPLY, + MGMT_OP_READ_LOCAL_OOB_DATA, + MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_OP_START_DISCOVERY, + MGMT_OP_STOP_DISCOVERY, + MGMT_OP_CONFIRM_NAME, + MGMT_OP_BLOCK_DEVICE, + MGMT_OP_UNBLOCK_DEVICE, +}; + +static const u16 mgmt_events[] = { + MGMT_EV_CONTROLLER_ERROR, + MGMT_EV_INDEX_ADDED, + MGMT_EV_INDEX_REMOVED, + MGMT_EV_NEW_SETTINGS, + MGMT_EV_CLASS_OF_DEV_CHANGED, + MGMT_EV_LOCAL_NAME_CHANGED, + MGMT_EV_NEW_LINK_KEY, + MGMT_EV_NEW_LONG_TERM_KEY, + MGMT_EV_DEVICE_CONNECTED, + MGMT_EV_DEVICE_DISCONNECTED, + MGMT_EV_CONNECT_FAILED, + MGMT_EV_PIN_CODE_REQUEST, + MGMT_EV_USER_CONFIRM_REQUEST, + MGMT_EV_USER_PASSKEY_REQUEST, + MGMT_EV_AUTH_FAILED, + MGMT_EV_DEVICE_FOUND, + MGMT_EV_DISCOVERING, + MGMT_EV_DEVICE_BLOCKED, + MGMT_EV_DEVICE_UNBLOCKED, + MGMT_EV_DEVICE_UNPAIRED, +}; + /* * These LE scan and inquiry parameters were chosen according to LE General * Discovery Procedure specification. @@ -206,6 +269,39 @@ static int read_version(struct sock *sk) sizeof(rp)); } +static int read_commands(struct sock *sk) +{ + struct mgmt_rp_read_commands *rp; + u16 num_commands = ARRAY_SIZE(mgmt_commands); + u16 num_events = ARRAY_SIZE(mgmt_events); + u16 *opcode; + size_t rp_size; + int i, err; + + BT_DBG("sock %p", sk); + + rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16)); + + rp = kmalloc(rp_size, GFP_KERNEL); + if (!rp) + return -ENOMEM; + + put_unaligned_le16(num_commands, &rp->num_commands); + put_unaligned_le16(num_events, &rp->num_events); + + for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) + put_unaligned_le16(mgmt_commands[i], opcode); + + for (i = 0; i < num_events; i++, opcode++) + put_unaligned_le16(mgmt_events[i], opcode); + + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp, + rp_size); + kfree(rp); + + return err; +} + static int read_index_list(struct sock *sk) { struct mgmt_rp_read_index_list *rp; @@ -2323,6 +2419,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_READ_VERSION: err = read_version(sk); break; + case MGMT_OP_READ_COMMANDS: + err = read_commands(sk); + break; case MGMT_OP_READ_INDEX_LIST: err = read_index_list(sk); break; -- cgit v1.2.3 From 203159d486006a18fa1ccf787a10d15d3128cdac Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Feb 2012 15:41:01 -0300 Subject: Bluetooth: Fix discovery state machine In case of Start Discovery command failure, we should set the discovery state to DISCOVERY_STOPPED. Otherwise, we stuck at DISCOVERY_STARTING state and subsequent Start Discovery commands will simply fail. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8efbd8eaa1b3..066d338be1ce 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3096,6 +3096,8 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) struct pending_cmd *cmd; int err; + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev); if (!cmd) return -ENOENT; -- cgit v1.2.3 From 7b99b659d90c5d421cb1867295c78a4c0c030734 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 13 Feb 2012 15:41:02 -0300 Subject: Bluetooth: Fix event sending with DISCOVERY_STOPPED state We are not supposed to send mgmt_discovering events if we are transiting from DISCOVERY_STARTING to DISCOVERY_STOPPED state. It doesn't make sense to send mgmt_discovering event once discovery procedure has not been even started. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9ada16449aed..dc31e7d6028e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -380,7 +380,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: - mgmt_discovering(hdev, 0); + if (hdev->discovery.state != DISCOVERY_STARTING) + mgmt_discovering(hdev, 0); break; case DISCOVERY_STARTING: break; -- cgit v1.2.3 From 7ddb6e0f3f7aa265c905b947e9ac4ab9562e52f2 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 14 Feb 2012 15:12:57 +0200 Subject: Bluetooth: Do not dereference zero sk Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 16360298590f..138fe3446678 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -795,7 +795,7 @@ static void l2cap_sock_kill(struct sock *sk) static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_chan *chan; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -803,6 +803,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) if (!sk) return 0; + chan = l2cap_pi(sk)->chan; + lock_sock(sk); if (!sk->sk_shutdown) { if (chan->mode == L2CAP_MODE_ERTM) -- cgit v1.2.3 From 76a7f3a40c2bfbdb5f2b23ac780fa4e4f22e8659 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 00:34:40 +0200 Subject: Bluetooth: Remove unused member from cmd_lookup struct The val member of cmd_lookup isn't used anywhere so it can be removed. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 066d338be1ce..5520858553cc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2561,7 +2561,6 @@ int mgmt_index_removed(struct hci_dev *hdev) } struct cmd_lookup { - u8 val; struct sock *sk; struct hci_dev *hdev; }; @@ -2584,7 +2583,7 @@ static void settings_rsp(struct pending_cmd *cmd, void *data) int mgmt_powered(struct hci_dev *hdev, u8 powered) { - struct cmd_lookup match = { powered, NULL, hdev }; + struct cmd_lookup match = { NULL, hdev }; __le32 ev; int ret; @@ -2608,7 +2607,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { - struct cmd_lookup match = { discoverable, NULL, hdev }; + struct cmd_lookup match = { NULL, hdev }; __le32 ev; int ret; @@ -2627,7 +2626,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { __le32 ev; - struct cmd_lookup match = { connectable, NULL, hdev }; + struct cmd_lookup match = { NULL, hdev }; int ret; mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, -- cgit v1.2.3 From 7bb895d68e0c18b730bd89f2ed7e58de0e3a591a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 01:20:00 +0200 Subject: Bluetooth: mgmt: Use more consistent error variable names For simple integer errors the variable name "err" is more consistent with the existing code base than "ret". Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5520858553cc..d5dbe402bc03 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2585,7 +2585,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) { struct cmd_lookup match = { NULL, hdev }; __le32 ev; - int ret; + int err; mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); @@ -2596,50 +2596,50 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); - return ret; + return err; } int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { struct cmd_lookup match = { NULL, hdev }; __le32 ev; - int ret; + int err; mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); - return ret; + return err; } int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { __le32 ev; struct cmd_lookup match = { NULL, hdev }; - int ret; + int err; mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, &match); ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); - return ret; + return err; } int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) -- cgit v1.2.3 From 33ef95ed30283eb17c686a815caf1d33e966fe4a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 16 Feb 2012 23:56:27 +0200 Subject: Bluetooth: mgmt: Add support for Set Link Security command The Set Link Security mgmt command is used to enable or disable link level security, also known as Security Mode 3. This is rarely enabled in modern systems but the command needs to be available for completeness, qualification purposes and those few systems that actually want to enable it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 3 ++ net/bluetooth/mgmt.c | 87 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b20d990436b4..66f84adbbbef 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -994,6 +994,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); +int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); 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); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b0784ee5f8b9..239e9fb8f7c5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -254,6 +254,9 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_AUTH, &hdev->flags); } + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_auth_enable_complete(hdev, status); + hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d5dbe402bc03..0c9fbb45d2e9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -964,6 +964,65 @@ failed: return err; } +static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct pending_cmd *cmd; + struct hci_dev *hdev; + uint8_t val; + int err; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_NOT_POWERED); + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + MGMT_STATUS_BUSY); + goto failed; + } + + val = !!cp->val; + + if (test_bit(HCI_AUTH, &hdev->flags) == val) { + err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2443,6 +2502,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_PAIRABLE: err = set_pairable(sk, index, cp, len); break; + case MGMT_OP_SET_LINK_SECURITY: + err = set_link_security(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; @@ -2965,6 +3027,31 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); } +int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + __le32 ev; + int err; + + if (status) { + u8 mgmt_err = mgmt_status(status); + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, + cmd_status_rsp, &mgmt_err); + return 0; + } + + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, + &match); + + ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + + if (match.sk) + sock_put(match.sk); + + return err; +} + int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; -- cgit v1.2.3 From ed2c4ee360709ca838efa0ea4d6295590aff3d24 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 00:56:28 +0200 Subject: Bluetooth: mgmt: Add support for Set SSP command The Set SSP mgmt command can be used for enabling and disabling Secure Simple Pairing support for controllers that support it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 6 ++- net/bluetooth/mgmt.c | 85 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 66f84adbbbef..43e0b1eda020 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -995,6 +995,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status); 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); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 239e9fb8f7c5..179d127601fc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -447,7 +447,7 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); if (status) - return; + goto done; sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); if (!sent) @@ -457,6 +457,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); else clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + +done: + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_ssp_enable_complete(hdev, status); } static u8 hci_get_inquiry_mode(struct hci_dev *hdev) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0c9fbb45d2e9..36c4ff6fdf05 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1023,6 +1023,64 @@ failed: return err; } +static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct pending_cmd *cmd; + struct hci_dev *hdev; + uint8_t val; + int err; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_POWERED); + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); + goto failed; + } + + val = !!cp->val; + + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) { + err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_unlock(hdev); + hci_dev_put(hdev); + + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2505,6 +2563,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_LINK_SECURITY: err = set_link_security(sk, index, cp, len); break; + case MGMT_OP_SET_SSP: + err = set_ssp(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; @@ -3052,6 +3113,30 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) return err; } +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + __le32 ev; + int err; + + if (status) { + u8 mgmt_err = mgmt_status(status); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, + cmd_status_rsp, &mgmt_err); + return 0; + } + + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); + + ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + + if (match.sk) + sock_put(match.sk); + + return err; +} + int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; -- cgit v1.2.3 From 3ed7003e724a04482e0ef1e794eece8c1c177b37 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 16 Feb 2012 23:32:42 -0800 Subject: Bluetooth: Add logging functions bt_info and bt_err Use specific logging functions instead of a generic bt_printk function can save some text. Remove now unused bt_printk function. Add compatibility BT_INFO and BT_ERR macros. (compiled x86 and defconfig with bluetooth and all bluetooth drivers) $ size net/bluetooth/built-in.o* text data bss dec hex filename 381662 20072 100416 502150 7a986 net/bluetooth/built-in.o.allyesconfig.new 382463 20072 100400 502935 7ac97 net/bluetooth/built-in.o.allyesconfig.old 126635 1388 132 128155 1f49b net/bluetooth/built-in.o.defconfig.new 127175 1388 132 128695 1f6b7 net/bluetooth/built-in.o.defconfig.old $ size drivers/bluetooth/built-in.o* 127575 8976 29476 166027 2888b drivers/bluetooth/built-in.o.allyesconfig.new 129512 8976 29516 168004 29044 drivers/bluetooth/built-in.o.allyesconfig.old 52998 3292 156 56446 dc7e drivers/bluetooth/built-in.o.defconfig.new 54358 3292 156 57806 e1ce drivers/bluetooth/built-in.o.defconfig.old Signed-off-by: Joe Perches Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 14 ++++++++------ net/bluetooth/lib.c | 27 ++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 4a82ca0bb0b2..9f5f2c1c5554 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -109,12 +109,14 @@ struct bt_power { */ #define BT_CHANNEL_POLICY_AMP_PREFERRED 2 -__printf(2, 3) -int bt_printk(const char *level, const char *fmt, ...); - -#define BT_INFO(fmt, arg...) bt_printk(KERN_INFO, pr_fmt(fmt), ##arg) -#define BT_ERR(fmt, arg...) bt_printk(KERN_ERR, pr_fmt(fmt), ##arg) -#define BT_DBG(fmt, arg...) pr_debug(fmt "\n", ##arg) +__printf(1, 2) +int bt_info(const char *fmt, ...); +__printf(1, 2) +int bt_err(const char *fmt, ...); + +#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__) +#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__) +#define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__) /* Connection and socket states */ enum { diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 86a6bed229df..506628876f36 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -24,6 +24,8 @@ /* Bluetooth kernel library. */ +#define pr_fmt(fmt) "Bluetooth: " fmt + #include #include @@ -151,7 +153,26 @@ int bt_to_errno(__u16 code) } EXPORT_SYMBOL(bt_to_errno); -int bt_printk(const char *level, const char *format, ...) +int bt_info(const char *format, ...) +{ + struct va_format vaf; + va_list args; + int r; + + va_start(args, format); + + vaf.fmt = format; + vaf.va = &args; + + r = pr_info("%pV", &vaf); + + va_end(args); + + return r; +} +EXPORT_SYMBOL(bt_info); + +int bt_err(const char *format, ...) { struct va_format vaf; va_list args; @@ -162,10 +183,10 @@ int bt_printk(const char *level, const char *format, ...) vaf.fmt = format; vaf.va = &args; - r = printk("%sBluetooth: %pV\n", level, &vaf); + r = pr_err("%pV", &vaf); va_end(args); return r; } -EXPORT_SYMBOL(bt_printk); +EXPORT_SYMBOL(bt_err); -- cgit v1.2.3 From 20d1803a70ddafc8410b461caaa397e49da246ac Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 17 Feb 2012 11:40:55 +0200 Subject: Bluetooth: Move scope of state_to_string Function state_to_string will be used in other files in debug statements. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 27 +++++++++++++++++++++++++++ net/bluetooth/l2cap_core.c | 26 -------------------------- 2 files changed, 27 insertions(+), 26 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 9f5f2c1c5554..5ca9219fe940 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -131,6 +131,33 @@ enum { BT_CLOSED }; +/* If unused will be removed by compiler */ +static inline const char *state_to_string(int state) +{ + switch (state) { + case BT_CONNECTED: + return "BT_CONNECTED"; + case BT_OPEN: + return "BT_OPEN"; + case BT_BOUND: + return "BT_BOUND"; + case BT_LISTEN: + return "BT_LISTEN"; + case BT_CONNECT: + return "BT_CONNECT"; + case BT_CONNECT2: + return "BT_CONNECT2"; + case BT_CONFIG: + return "BT_CONFIG"; + case BT_DISCONN: + return "BT_DISCONN"; + case BT_CLOSED: + return "BT_CLOSED"; + } + + return "invalid state"; +} + /* BD Address */ typedef struct { __u8 b[6]; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8efac7884ffb..252a96e474ca 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -215,32 +215,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static char *state_to_string(int state) -{ - switch(state) { - case BT_CONNECTED: - return "BT_CONNECTED"; - case BT_OPEN: - return "BT_OPEN"; - case BT_BOUND: - return "BT_BOUND"; - case BT_LISTEN: - return "BT_LISTEN"; - case BT_CONNECT: - return "BT_CONNECT"; - case BT_CONNECT2: - return "BT_CONNECT2"; - case BT_CONFIG: - return "BT_CONFIG"; - case BT_DISCONN: - return "BT_DISCONN"; - case BT_CLOSED: - return "BT_CLOSED"; - } - - return "invalid state"; -} - static void l2cap_state_change(struct l2cap_chan *chan, int state) { BT_DBG("%p %s -> %s", chan, state_to_string(chan->state), -- cgit v1.2.3 From e05dcc3291dcfe9ab1b456f38ccb3041ebbda59c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 17 Feb 2012 11:40:56 +0200 Subject: Bluetooth: Use symbolic names for state in debug Use state_to_string function in debug statements. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/l2cap_core.c | 5 +++-- net/bluetooth/l2cap_sock.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 42fdbb833254..bbb0e214e51d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -612,7 +612,8 @@ static inline void l2cap_chan_put(struct l2cap_chan *c) static inline void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) { - BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); + BT_DBG("chan %p state %s timeout %ld", chan, + state_to_string(chan->state), timeout); if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b4ecddee11b5..f38e1b11d835 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -282,7 +282,7 @@ static void hci_conn_timeout(struct work_struct *work) disc_work.work); __u8 reason; - BT_DBG("conn %p state %d", conn, conn->state); + BT_DBG("conn %p state %s", conn, state_to_string(conn->state)); if (atomic_read(&conn->refcnt)) return; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 252a96e474ca..88968e711d3d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -231,7 +231,7 @@ static void l2cap_chan_timeout(struct work_struct *work) struct sock *sk = chan->sk; int reason; - BT_DBG("chan %p state %d", chan, chan->state); + BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); lock_sock(sk); @@ -413,7 +413,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) struct l2cap_conn *conn = chan->conn; struct sock *sk = chan->sk; - BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket); + BT_DBG("chan %p state %s sk %p", chan, + state_to_string(chan->state), sk); switch (chan->state) { case BT_LISTEN: diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 138fe3446678..b48d6c1b9db6 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -783,7 +783,7 @@ static void l2cap_sock_kill(struct sock *sk) if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) return; - BT_DBG("sk %p state %d", sk, sk->sk_state); + BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state)); /* Kill poor orphan */ -- cgit v1.2.3 From 42d2d87cfe837e987802588f8d8b119a76714a74 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 17 Feb 2012 11:40:57 +0200 Subject: Bluetooth: Prefix hex numbers with object name Several hex numbers were printed without object name which complicates debugging. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/l2cap_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f38e1b11d835..7ee6895c4b0c 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -80,7 +80,7 @@ void hci_acl_connect(struct hci_conn *conn) struct inquiry_entry *ie; struct hci_cp_create_conn cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); conn->state = BT_CONNECT; conn->out = true; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 88968e711d3d..37736c6603fc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -217,7 +217,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) static void l2cap_state_change(struct l2cap_chan *chan, int state) { - BT_DBG("%p %s -> %s", chan, state_to_string(chan->state), + BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), state_to_string(state)); chan->state = state; -- cgit v1.2.3 From d753fdc40f60da2eef03b4816392081a552fea5a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:06:34 +0200 Subject: Bluetooth: mgmt: Add address type to link key messages The latest mgmt API includes an address type wherever there's an address present. This patch updates the link key messages to match it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/mgmt.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 255a99600f08..5aafe929d011 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -153,7 +153,7 @@ struct mgmt_cp_remove_uuid { } __packed; struct mgmt_link_key_info { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; u8 type; u8 val[16]; u8 pin_len; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 36c4ff6fdf05..b0de7194249e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1274,8 +1274,8 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; - hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, - key->pin_len); + hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val, + key->type, key->pin_len); } cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); @@ -2788,7 +2788,8 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, memset(&ev, 0, sizeof(ev)); ev.store_hint = persistent; - bacpy(&ev.key.bdaddr, &key->bdaddr); + bacpy(&ev.key.addr.bdaddr, &key->bdaddr); + ev.key.addr.type = MGMT_ADDR_BREDR; ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; -- cgit v1.2.3 From d8457698e7f23a05055396a15ec72ba663282867 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:24:57 +0200 Subject: Bluetooth: mgmt: Add address type to PIN code messages The latest mgmt API includes address types for all messages containing an address. This patch updates the PIN code messages to match this. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 8 ++++---- net/bluetooth/mgmt.c | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5aafe929d011..eb584cc287d6 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -199,18 +199,18 @@ struct mgmt_rp_get_connections { #define MGMT_OP_PIN_CODE_REPLY 0x0016 struct mgmt_cp_pin_code_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 pin_len; __u8 pin_code[16]; } __packed; struct mgmt_rp_pin_code_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; uint8_t status; } __packed; #define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017 struct mgmt_cp_pin_code_neg_reply { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; } __packed; #define MGMT_OP_SET_IO_CAPABILITY 0x0018 @@ -377,7 +377,7 @@ struct mgmt_ev_connect_failed { #define MGMT_EV_PIN_CODE_REQUEST 0x000E struct mgmt_ev_pin_code_request { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 secure; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b0de7194249e..68623401933f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1528,8 +1528,8 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, if (!cmd) return -ENOMEM; - err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr), - &cp->bdaddr); + err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, + sizeof(cp->addr.bdaddr), &cp->addr.bdaddr); if (err < 0) mgmt_pending_remove(cmd); @@ -1541,7 +1541,6 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) struct hci_dev *hdev; struct hci_conn *conn; struct mgmt_cp_pin_code_reply *cp = data; - struct mgmt_cp_pin_code_neg_reply ncp; struct hci_cp_pin_code_reply reply; struct pending_cmd *cmd; int err; @@ -1565,7 +1564,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); if (!conn) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_CONNECTED); @@ -1573,7 +1572,9 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) } if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) { - bacpy(&ncp.bdaddr, &cp->bdaddr); + struct mgmt_cp_pin_code_neg_reply ncp; + + memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr)); BT_ERR("PIN code is not 16 bytes long"); @@ -1592,7 +1593,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - bacpy(&reply.bdaddr, &cp->bdaddr); + bacpy(&reply.bdaddr, &cp->addr.bdaddr); reply.pin_len = cp->pin_len; memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code)); @@ -2945,7 +2946,8 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) { struct mgmt_ev_pin_code_request ev; - bacpy(&ev.bdaddr, bdaddr); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = MGMT_ADDR_BREDR; ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), @@ -2963,7 +2965,8 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return -ENOENT; - bacpy(&rp.bdaddr, bdaddr); + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = MGMT_ADDR_BREDR; rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, @@ -2985,7 +2988,8 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!cmd) return -ENOENT; - bacpy(&rp.bdaddr, bdaddr); + bacpy(&rp.addr.bdaddr, bdaddr); + rp.addr.type = MGMT_ADDR_BREDR; rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, -- cgit v1.2.3 From a198e7b100b26dd6ac0240487ca37bad0f53e3e6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:27:06 +0200 Subject: Bluetooth: mgmt: Add address type to confirm name command The latest mgmt API includes an address type for all messages containing an address. This patch updates the confirm name command to match this. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/mgmt.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index eb584cc287d6..14c1816cac67 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -296,11 +296,11 @@ struct mgmt_cp_start_discovery { #define MGMT_OP_CONFIRM_NAME 0x0025 struct mgmt_cp_confirm_name { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 name_known; } __packed; struct mgmt_rp_confirm_name { - bdaddr_t bdaddr; + struct mgmt_addr_info addr; __u8 status; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 68623401933f..01c8d6239a4b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2299,7 +2299,7 @@ static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr); + e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, MGMT_STATUS_INVALID_PARAMS); -- cgit v1.2.3 From ea585ab51d3fe2eb2d738c91f83e7c309e76b4fe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:50:39 +0200 Subject: Bluetooth: Add Intel copyright to mgmt files This patch adds the appropriate Intel copyright to mgmt files. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 14c1816cac67..ee625a6ad791 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -2,6 +2,7 @@ BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2010 Nokia Corporation + Copyright (C) 2011-2012 Intel Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 01c8d6239a4b..f9f3e4c44150 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1,6 +1,8 @@ /* BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2010 Nokia Corporation + Copyright (C) 2011-2012 Intel Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as -- cgit v1.2.3 From f39799f5047c4827b200acbf33cd0ba076afd7ed Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:35 -0300 Subject: Bluetooth: Prepare start_discovery This patch does some code refactoring in start_discovery function in order to prepare it for interleaved discovery support. MGMT_ADDR_* macros were moved to hci_core.h since they are now used to define discovery type macros. Discovery type macros were defined according to mgmt-api.txt specification: Possible values for the Type parameter are a bit-wise or of the following bits: 1 BR/EDR 2 LE Public 3 LE Random By combining these e.g. the following values are possible: 1 BR/EDR 6 LE (public & random) 7 BR/EDR/LE (interleaved discovery) Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 12 ++++++++++++ include/net/bluetooth/mgmt.h | 5 ----- net/bluetooth/mgmt.c | 15 ++++++++++----- 3 files changed, 22 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 43e0b1eda020..be8da5d54abb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -956,6 +956,18 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, struct sock *skip_sk); /* Management interface */ +#define MGMT_ADDR_BREDR 0x00 +#define MGMT_ADDR_LE_PUBLIC 0x01 +#define MGMT_ADDR_LE_RANDOM 0x02 +#define MGMT_ADDR_INVALID 0xff + +#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) +#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ + BIT(MGMT_ADDR_LE_RANDOM)) +#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \ + BIT(MGMT_ADDR_LE_PUBLIC) | \ + BIT(MGMT_ADDR_LE_RANDOM)) + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_index_added(struct hci_dev *hdev); int mgmt_index_removed(struct hci_dev *hdev); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ee625a6ad791..ad54b5fd634c 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -48,11 +48,6 @@ struct mgmt_hdr { __le16 len; } __packed; -#define MGMT_ADDR_BREDR 0x00 -#define MGMT_ADDR_LE_PUBLIC 0x01 -#define MGMT_ADDR_LE_RANDOM 0x02 -#define MGMT_ADDR_INVALID 0xff - struct mgmt_addr_info { bdaddr_t bdaddr; __u8 type; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f9f3e4c44150..196215c9d424 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2157,7 +2157,6 @@ static int start_discovery(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; - unsigned long discov_type = cp->type; struct pending_cmd *cmd; struct hci_dev *hdev; int err; @@ -2193,14 +2192,20 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } - if (test_bit(MGMT_ADDR_BREDR, &discov_type)) + switch (cp->type) { + case DISCOV_TYPE_BREDR: + case DISCOV_TYPE_INTERLEAVED: err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); - else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) && - test_bit(MGMT_ADDR_LE_RANDOM, &discov_type)) + break; + + case DISCOV_TYPE_LE: err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); - else + break; + + default: err = -EINVAL; + } if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3 From 4aab14e5504e84c42534378f91e836e6f55d0886 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:36 -0300 Subject: Bluetooth: Track discovery type This patch adds to struct discovery_state the field 'type' so that we can track the discovery type the device is performing. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 2 ++ net/bluetooth/mgmt.c | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index be8da5d54abb..d7c79b5335c2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -57,6 +57,7 @@ struct inquiry_entry { }; struct discovery_state { + int type; enum { DISCOVERY_STOPPED, DISCOVERY_STARTING, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index dc31e7d6028e..29a9b01c3b9b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -380,6 +380,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: + hdev->discovery.type = 0; + if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 196215c9d424..9d98382e48c7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2192,7 +2192,9 @@ static int start_discovery(struct sock *sk, u16 index, goto failed; } - switch (cp->type) { + hdev->discovery.type = cp->type; + + switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: case DISCOV_TYPE_INTERLEAVED: err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); -- cgit v1.2.3 From 343f935bfa44189c68527102c409286b0cfc4526 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:37 -0300 Subject: Bluetooth: Merge INQUIRY and LE_SCAN discovery states This patch merges DISCOVERY_INQUIRY and DISCOVERY_LE_SCAN states into a new state called DISCOVERY_FINDING. From the discovery perspective, we are pretty much worried about to know just if we are finding devices than what exactly phase of "finding devices" (inquiry or LE scan) we are currently running. Besides, to know if the controller is performing inquiry or LE scan we should check HCI_INQUIRY or HCI_LE_SCAN bits in hdev flags. Moreover, merging this two states will simplify the discovery state machine and will keep interleaved discovery implementation simpler. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 +-- net/bluetooth/hci_core.c | 6 ++---- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d7c79b5335c2..942de7764278 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -61,8 +61,7 @@ struct discovery_state { enum { DISCOVERY_STOPPED, DISCOVERY_STARTING, - DISCOVERY_INQUIRY, - DISCOVERY_LE_SCAN, + DISCOVERY_FINDING, DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 29a9b01c3b9b..fabca080ae70 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -361,8 +361,7 @@ bool hci_discovery_active(struct hci_dev *hdev) struct discovery_state *discov = &hdev->discovery; switch (discov->state) { - case DISCOVERY_INQUIRY: - case DISCOVERY_LE_SCAN: + case DISCOVERY_FINDING: case DISCOVERY_RESOLVING: return true; @@ -387,8 +386,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) break; case DISCOVERY_STARTING: break; - case DISCOVERY_INQUIRY: - case DISCOVERY_LE_SCAN: + case DISCOVERY_FINDING: mgmt_discovering(hdev, 1); break; case DISCOVERY_RESOLVING: diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 179d127601fc..9aea7b898821 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1080,7 +1080,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, hci_dev_lock(hdev); hci_adv_entries_clear(hdev); - hci_discovery_set_state(hdev, DISCOVERY_LE_SCAN); + hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); break; @@ -1159,7 +1159,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) set_bit(HCI_INQUIRY, &hdev->flags); hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_INQUIRY); + hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); } @@ -1645,7 +1645,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff hci_dev_lock(hdev); - if (discov->state != DISCOVERY_INQUIRY) + if (discov->state != DISCOVERY_FINDING) goto unlock; if (list_empty(&discov->resolve)) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9d98382e48c7..a9cd38dc2cab 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2250,7 +2250,7 @@ static int stop_discovery(struct sock *sk, u16 index) goto unlock; } - if (hdev->discovery.state == DISCOVERY_INQUIRY) { + if (hdev->discovery.state == DISCOVERY_FINDING) { err = hci_cancel_inquiry(hdev); if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3 From 5e0452c00a2e4b04ec1482248c897dacf106f1df Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 17 Feb 2012 20:39:38 -0300 Subject: Bluetooth: Interleaved discovery support This patch adds interleaved discovery support to MGMT Start Discovery command. In case interleaved discovery is not supported (not a dual mode device), we perform BR/EDR or LE-only discovery according to the device capabilities. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_event.c | 13 +++++++---- net/bluetooth/mgmt.c | 47 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 942de7764278..2aafeb3a8793 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -716,6 +716,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) #define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) +#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR)) /* ----- Extended LMP capabilities ----- */ #define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE) @@ -1019,6 +1020,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); +int mgmt_interleaved_discovery(struct hci_dev *hdev); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9aea7b898821..04fb1f02dfcc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1090,11 +1090,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - hci_dev_lock(hdev); - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - hci_dev_unlock(hdev); - schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); + + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) { + mgmt_interleaved_discovery(hdev); + } else { + hci_dev_lock(hdev); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + hci_dev_unlock(hdev); + } + break; default: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a9cd38dc2cab..89754bbcd02b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -108,8 +108,10 @@ static const u16 mgmt_events[] = { #define LE_SCAN_WIN 0x12 #define LE_SCAN_INT 0x12 #define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */ +#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */ #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ +#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */ #define SERVICE_CACHE_TIMEOUT (5 * 1000) @@ -2153,6 +2155,46 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return err; } +static int discovery(struct hci_dev *hdev) +{ + int err; + + if (lmp_host_le_capable(hdev)) { + if (lmp_bredr_capable(hdev)) { + err = hci_le_scan(hdev, LE_SCAN_TYPE, + LE_SCAN_INT, LE_SCAN_WIN, + LE_SCAN_TIMEOUT_BREDR_LE); + } else { + hdev->discovery.type = DISCOV_TYPE_LE; + err = hci_le_scan(hdev, LE_SCAN_TYPE, + LE_SCAN_INT, LE_SCAN_WIN, + LE_SCAN_TIMEOUT_LE_ONLY); + } + } else { + hdev->discovery.type = DISCOV_TYPE_BREDR; + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + } + + return err; +} + +int mgmt_interleaved_discovery(struct hci_dev *hdev) +{ + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE); + if (err < 0) + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + + hci_dev_unlock(hdev); + + return err; +} + static int start_discovery(struct sock *sk, u16 index, void *data, u16 len) { @@ -2196,7 +2238,6 @@ static int start_discovery(struct sock *sk, u16 index, switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: - case DISCOV_TYPE_INTERLEAVED: err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); break; @@ -2205,6 +2246,10 @@ static int start_discovery(struct sock *sk, u16 index, LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); break; + case DISCOV_TYPE_INTERLEAVED: + err = discovery(hdev); + break; + default: err = -EINVAL; } -- cgit v1.2.3 From aee9b218036476b8b659de5bbfada3a4633f635b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 18 Feb 2012 15:07:59 +0200 Subject: Bluetooth: mgmt: Move status parameters into the cmd_complete header Instead of having status paramters part of each individual command response it's simpler to just have the status as part of the command complete header. This patch updates the code to follow this convention and thereby also ensures compliance with the latest mgmt API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 8 +--- net/bluetooth/mgmt.c | 107 ++++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 59 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 36e68b4551af..7e3d38bfaec3 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -184,7 +184,6 @@ struct mgmt_cp_disconnect { } __packed; struct mgmt_rp_disconnect { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_GET_CONNECTIONS 0x0015 @@ -201,7 +200,6 @@ struct mgmt_cp_pin_code_reply { } __packed; struct mgmt_rp_pin_code_reply { struct mgmt_addr_info addr; - uint8_t status; } __packed; #define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017 @@ -221,7 +219,6 @@ struct mgmt_cp_pair_device { } __packed; struct mgmt_rp_pair_device { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A @@ -233,7 +230,6 @@ struct mgmt_cp_unpair_device { } __packed; struct mgmt_rp_unpair_device { struct mgmt_addr_info addr; - __u8 status; }; #define MGMT_OP_USER_CONFIRM_REPLY 0x001C @@ -242,7 +238,6 @@ struct mgmt_cp_user_confirm_reply { } __packed; struct mgmt_rp_user_confirm_reply { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D @@ -257,7 +252,6 @@ struct mgmt_cp_user_passkey_reply { } __packed; struct mgmt_rp_user_passkey_reply { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F @@ -297,7 +291,6 @@ struct mgmt_cp_confirm_name { } __packed; struct mgmt_rp_confirm_name { struct mgmt_addr_info addr; - __u8 status; } __packed; #define MGMT_OP_BLOCK_DEVICE 0x0026 @@ -313,6 +306,7 @@ struct mgmt_cp_unblock_device { #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; + __u8 status; __u8 data[0]; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 89754bbcd02b..61d0250bd77e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -227,8 +227,8 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) return err; } -static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, - size_t rp_len) +static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, + void *rp, size_t rp_len) { struct sk_buff *skb; struct mgmt_hdr *hdr; @@ -249,6 +249,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, ev = (void *) skb_put(skb, sizeof(*ev) + rp_len); put_unaligned_le16(cmd, &ev->opcode); + ev->status = status; if (rp) memcpy(ev->data, rp, rp_len); @@ -269,7 +270,7 @@ static int read_version(struct sock *sk) rp.version = MGMT_VERSION; put_unaligned_le16(MGMT_REVISION, &rp.revision); - return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp, + return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, sizeof(rp)); } @@ -299,7 +300,7 @@ static int read_commands(struct sock *sk) for (i = 0; i < num_events; i++, opcode++) put_unaligned_le16(mgmt_events[i], opcode); - err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp, + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp, rp_size); kfree(rp); @@ -347,7 +348,7 @@ static int read_index_list(struct sock *sk) read_unlock(&hci_dev_list_lock); - err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp, + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp, rp_len); kfree(rp); @@ -637,7 +638,7 @@ static int read_controller_info(struct sock *sk, u16 index) hci_dev_unlock(hdev); hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); + return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp)); } static void mgmt_pending_free(struct pending_cmd *cmd) @@ -717,7 +718,8 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) { __le32 settings = cpu_to_le32(get_current_settings(hdev)); - return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings)); + return cmd_complete(sk, hdev->id, opcode, 0, &settings, + sizeof(settings)); } static int set_powered(struct sock *sk, u16 index, void *data, u16 len) @@ -1124,7 +1126,7 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0); failed: hci_dev_unlock(hdev); @@ -1185,7 +1187,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto unlock; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0); unlock: hci_dev_unlock(hdev); @@ -1226,7 +1228,8 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) err = update_class(hdev); if (err == 0) - err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -1282,7 +1285,7 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) key->type, key->pin_len); } - cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); + cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -1310,6 +1313,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; + u8 status = 0; int err; if (len != sizeof(*cp)) @@ -1333,13 +1337,13 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) err = hci_remove_ltk(hdev, &cp->addr.bdaddr); if (err < 0) { - rp.status = MGMT_STATUS_NOT_PAIRED; + status = MGMT_STATUS_NOT_PAIRED; goto unlock; } if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -1352,8 +1356,8 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) &cp->addr.bdaddr); if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } @@ -1373,8 +1377,8 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) unlock: if (err < 0) - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp, - sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + &rp, sizeof(rp)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -1512,7 +1516,7 @@ static int get_connections(struct sock *sk, u16 index) /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); - err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len); + err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len); unlock: kfree(rp); @@ -1672,7 +1676,7 @@ static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) hci_dev_unlock(hdev); hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); + return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0); } static inline struct pending_cmd *find_pairing(struct hci_conn *conn) @@ -1700,9 +1704,9 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) bacpy(&rp.addr.bdaddr, &conn->dst); rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); - rp.status = status; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp)); + cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status, + &rp, sizeof(rp)); /* So we don't get further callbacks for this connection */ conn->connect_cfm_cb = NULL; @@ -1735,6 +1739,7 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) struct pending_cmd *cmd; u8 sec_level, auth_type; struct hci_conn *conn; + u8 status = 0; int err; BT_DBG(""); @@ -1768,16 +1773,16 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { - rp.status = -PTR_ERR(conn); - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + status = -PTR_ERR(conn); + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); goto unlock; } if (conn->connect_cfm_cb) { hci_conn_put(conn); - rp.status = EBUSY; - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + status = EBUSY; + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); goto unlock; } @@ -1850,7 +1855,7 @@ static int cancel_pair_device(struct sock *sk, u16 index, pairing_complete(cmd, MGMT_STATUS_CANCELLED); - err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr, + err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr, sizeof(*addr)); unlock: hci_dev_unlock(hdev); @@ -2112,8 +2117,8 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_FAILED); else - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, - 0); + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, 0, + NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2147,7 +2152,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, MGMT_STATUS_INVALID_PARAMS); else err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - NULL, 0); + 0, NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2307,7 +2312,8 @@ static int stop_discovery(struct sock *sk, u16 index) e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); if (!e) { mgmt_pending_remove(cmd); - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0, + NULL, 0); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; } @@ -2400,8 +2406,8 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_FAILED); else - err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, - NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, 0, + NULL, 0); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2434,7 +2440,7 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); else - err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, + err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 0, NULL, 0); hci_dev_unlock(hdev); @@ -2490,8 +2496,8 @@ static int set_fast_connectable(struct sock *sk, u16 index, goto done; } - err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0, + NULL, 0); done: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2908,9 +2914,9 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; - rp.status = 0; - cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); + cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp, + sizeof(rp)); *sk = cmd->sk; sock_hold(*sk); @@ -2930,7 +2936,7 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); - cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp)); + cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp)); mgmt_pending_remove(cmd); } @@ -2972,10 +2978,9 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = link_to_mgmt(link_type, addr_type); - rp.status = mgmt_status(status); err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, - &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3021,10 +3026,9 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = MGMT_ADDR_BREDR; - rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, - sizeof(rp)); + err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3044,10 +3048,9 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = MGMT_ADDR_BREDR; - rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, - sizeof(rp)); + err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3099,8 +3102,8 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = link_to_mgmt(link_type, addr_type); - rp.status = mgmt_status(status); - err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); + err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status), + &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3217,7 +3220,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) update_eir(hdev); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev, + err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev, sizeof(ev)); if (err < 0) goto failed; @@ -3256,7 +3259,7 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - &rp, sizeof(rp)); + 0, &rp, sizeof(rp)); } mgmt_pending_remove(cmd); @@ -3365,7 +3368,7 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev); if (cmd != NULL) { - cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0); + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, NULL, 0); mgmt_pending_remove(cmd); } -- cgit v1.2.3 From e211326c0b064e8fe2a8cb51427c3f2044ad84be Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 18 Feb 2012 15:20:03 +0200 Subject: Bluetooth: mgmt: Fix Pair Device response status values This patch fixes the status in Pair Device responses to follow proper mgmt status values. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 61d0250bd77e..79255f536278 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1728,7 +1728,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) if (!cmd) BT_DBG("Unable to find a pending command"); else - pairing_complete(cmd, status); + pairing_complete(cmd, mgmt_status(status)); } static int pair_device(struct sock *sk, u16 index, void *data, u16 len) @@ -1739,7 +1739,6 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) struct pending_cmd *cmd; u8 sec_level, auth_type; struct hci_conn *conn; - u8 status = 0; int err; BT_DBG(""); @@ -1773,17 +1772,16 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { - status = -PTR_ERR(conn); - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, - &rp, sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_CONNECT_FAILED, + &rp, sizeof(rp)); goto unlock; } if (conn->connect_cfm_cb) { hci_conn_put(conn); - status = EBUSY; - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status, - &rp, sizeof(rp)); + err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } -- cgit v1.2.3 From f808e166e7c529a7e706cda916c8c99589d2d95b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 12:52:07 +0200 Subject: Bluetooth: mgmt: Fix Start Discovery return parameters The same address type that was passed to the Start Discovery command should also be returned in the response message. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 79255f536278..258adf444936 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3325,6 +3325,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; + u8 type; int err; hci_discovery_set_state(hdev, DISCOVERY_STOPPED); @@ -3333,7 +3334,10 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) if (!cmd) return -ENOENT; - err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status)); + type = hdev->discovery.type; + + err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), + &type, sizeof(type)); mgmt_pending_remove(cmd); return err; @@ -3366,7 +3370,14 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev); if (cmd != NULL) { - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, NULL, 0); + u8 type = hdev->discovery.type; + + if (discovering) + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, + &type, sizeof(type)); + else + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, + NULL, 0); mgmt_pending_remove(cmd); } -- cgit v1.2.3 From f0eeea8b61d6e8316f6137b372eb3f3ac180508c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 12:58:54 +0200 Subject: Bluetooth: mgmt: Fix (Un)Block Device return parameters The same address as was passed to the (Un)Block Device command should also be returned in the command response message. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 258adf444936..c7e9a450b443 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2384,6 +2384,7 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct mgmt_cp_block_device *cp = data; + u8 status; int err; BT_DBG("hci%u", index); @@ -2394,18 +2395,20 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); if (err < 0) - err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_FAILED); + status = MGMT_STATUS_FAILED; else - err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, 0, - NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2417,6 +2420,7 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct mgmt_cp_unblock_device *cp = data; + u8 status; int err; BT_DBG("hci%u", index); @@ -2427,19 +2431,20 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); - if (err < 0) - err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + status = MGMT_STATUS_INVALID_PARAMS; else - err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 0, - NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From bf1e3541f75a395e1e21b144fe1c387cc71baff1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 13:16:14 +0200 Subject: Bluetooth: mgmt: Fix OOB command response parameters The response to the Add/Remove Out Of Band Data commands should include the same address as was given in the command itself. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c7e9a450b443..952c0a8ca305 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2094,6 +2094,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, { struct hci_dev *hdev; struct mgmt_cp_add_remote_oob_data *cp = data; + u8 status; int err; BT_DBG("hci%u ", index); @@ -2104,19 +2105,21 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) - err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_FAILED); + status = MGMT_STATUS_FAILED; else - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, 0, - NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2129,6 +2132,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, { struct hci_dev *hdev; struct mgmt_cp_remove_remote_oob_data *cp = data; + u8 status; int err; BT_DBG("hci%u ", index); @@ -2139,18 +2143,20 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, hdev = hci_dev_get(index); if (!hdev) - return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); hci_dev_lock(hdev); err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) - err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + status = MGMT_STATUS_INVALID_PARAMS; else - err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - 0, NULL, 0); + status = 0; + + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From 2da9c55c5a4a0b8f0348b7acd70d8b08a6ae4573 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Feb 2012 14:39:28 +0200 Subject: Bluetooth: mgmt: Bump mgmt version This patch bumps the mgmt version to 1 and resets the revision to 0. This is in order to indicate API stability to user space. The mgmt API has reached a point where no major backwards incompatible changes are expected so it makes sense to do this version bump now. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 952c0a8ca305..18d593f23934 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,8 +34,8 @@ #include #include -#define MGMT_VERSION 0 -#define MGMT_REVISION 1 +#define MGMT_VERSION 1 +#define MGMT_REVISION 0 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, -- cgit v1.2.3 From 48c7aba91f372251867d15efc9cf694ceee2de02 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 19 Feb 2012 14:06:48 +0200 Subject: Bluetooth: Fix hci_connect error return values The hci_connect function should either return a valid hci_conn pointer or a ERR_PTR() but never NULL. This patch fixes the two places where hci_conn_add failures would have caused a NULL return. The only reason for failure with hci_conn_add is memory allocation so ENOMEM seems to be a good choice here. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7ee6895c4b0c..8549d04e3313 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -551,7 +551,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 if (!acl) { acl = hci_conn_add(hdev, ACL_LINK, dst); if (!acl) - return NULL; + return ERR_PTR(-ENOMEM); } hci_conn_hold(acl); @@ -571,7 +571,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sco = hci_conn_add(hdev, type, dst); if (!sco) { hci_conn_put(acl); - return NULL; + return ERR_PTR(-ENOMEM); } } -- cgit v1.2.3 From 470fe1b540fb50ba8ce01e0ac985602e8fbb108c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:30 +0100 Subject: Bluetooth: Split sending for HCI raw and control sockets The sending functions for HCI raw and control sockets have nothing in common except that they iterate over the socket list. Split them into two so they can do their job more efficient. In addition the code becomes more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/hci_event.c | 2 +- net/bluetooth/hci_sock.c | 51 ++++++++++++++++++++++++++++++---------- net/bluetooth/mgmt.c | 2 +- 5 files changed, 45 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2aafeb3a8793..9209e4c8a211 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -953,8 +953,8 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); /* ----- HCI Sockets ----- */ -void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, - struct sock *skip_sk); +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); +void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); /* Management interface */ #define MGMT_ADDR_BREDR 0x00 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fabca080ae70..638fa8c393d8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2131,7 +2131,7 @@ static int hci_send_frame(struct sk_buff *skb) /* Time stamp */ __net_timestamp(skb); - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); } /* Get rid of skb owner, prior to sending to the driver. */ @@ -2818,7 +2818,7 @@ static void hci_rx_work(struct work_struct *work) while ((skb = skb_dequeue(&hdev->rx_q))) { if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); } if (test_bit(HCI_RAW, &hdev->flags)) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 04fb1f02dfcc..e69db4a7b3ef 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3571,7 +3571,7 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) bt_cb(skb)->pkt_type = HCI_EVENT_PKT; skb->dev = (void *) hdev; - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); kfree_skb(skb); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 9e854d9fb460..b5b3bc8d2848 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -85,8 +85,7 @@ static struct bt_sock_list hci_sk_list = { }; /* Send frame to RAW socket */ -void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, - struct sock *skip_sk) +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { struct sock *sk; struct hlist_node *node; @@ -94,13 +93,11 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, BT_DBG("hdev %p len %d", hdev, skb->len); read_lock(&hci_sk_list.lock); + sk_for_each(sk, node, &hci_sk_list.head) { struct hci_filter *flt; struct sk_buff *nskb; - if (sk == skip_sk) - continue; - if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) continue; @@ -108,12 +105,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, if (skb->sk == sk) continue; - if (bt_cb(skb)->channel != hci_pi(sk)->channel) + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) continue; - if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL) - goto clone; - /* Apply filter */ flt = &hci_pi(sk)->filter; @@ -137,18 +131,51 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, continue; } -clone: nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) continue; /* Put type byte before the data */ - if (bt_cb(skb)->channel == HCI_CHANNEL_RAW) - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); +} + +/* Send frame to control socket */ +void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) +{ + struct sock *sk; + struct hlist_node *node; + + BT_DBG("len %d", skb->len); + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + /* Skip the original socket */ + if (sk == skip_sk) + continue; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) + continue; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } + read_unlock(&hci_sk_list.lock); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 18d593f23934..1695d04d927d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -924,7 +924,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (data) memcpy(skb_put(skb, data_len), data, data_len); - hci_send_to_sock(NULL, skb, skip_sk); + hci_send_to_control(skb, skip_sk); kfree_skb(skb); return 0; -- cgit v1.2.3 From a6fb08dfe8654e399c9bbca34be914e213560b5e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:31 +0100 Subject: Bluetooth: Remove unneeded bt_cb(skb)->channel variable The bt_cb(skb)->channel was only needed to make hci_send_to_sock() be used for HCI raw and control sockets. Since they have now separate sending functions this is no longer needed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 1 - net/bluetooth/mgmt.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 5ca9219fe940..262ebd1747d4 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -222,7 +222,6 @@ struct bt_skb_cb { __u16 tx_seq; __u8 retries; __u8 sar; - unsigned short channel; __u8 force_active; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1695d04d927d..bc71b45ef4e5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -911,8 +911,6 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (!skb) return -ENOMEM; - bt_cb(skb)->channel = HCI_CHANNEL_CONTROL; - hdr = (void *) skb_put(skb, sizeof(*hdr)); hdr->opcode = cpu_to_le16(event); if (hdev) -- cgit v1.2.3 From 2f39cdb7a270da24532734dfdfd10c490be981c4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:32 +0100 Subject: Bluetooth: Limit HCI raw socket options to actual raw sockets Currently the socket options of HCI sockets can be set on raw and control sockets, but on control sockets they make no sense. So just return EINVAL in that case. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index b5b3bc8d2848..612bc2af05a9 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -601,6 +601,11 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char lock_sock(sk); + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { + err = -EINVAL; + goto done; + } + switch (optname) { case HCI_DATA_DIR: if (get_user(opt, (int __user *)optval)) { @@ -663,6 +668,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char break; } +done: release_sock(sk); return err; } -- cgit v1.2.3 From cedc5469778846ee18c653aaa6d70681961eed93 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:33 +0100 Subject: Bluetooth: Lock socket when reading HCI socket options When reading the HCI raw socket option, the socket was never locked. So lock the socket and in addition return EINVAL on non raw sockets. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 612bc2af05a9..27ec9088508f 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -677,11 +677,20 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char { struct hci_ufilter uf; struct sock *sk = sock->sk; - int len, opt; + int len, opt, err = 0; + + BT_DBG("sk %p, opt %d", sk, optname); if (get_user(len, optlen)) return -EFAULT; + lock_sock(sk); + + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { + err = -EINVAL; + goto done; + } + switch (optname) { case HCI_DATA_DIR: if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR) @@ -690,7 +699,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char opt = 0; if (put_user(opt, optval)) - return -EFAULT; + err = -EFAULT; break; case HCI_TIME_STAMP: @@ -700,7 +709,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char opt = 0; if (put_user(opt, optval)) - return -EFAULT; + err = -EFAULT; break; case HCI_FILTER: @@ -715,15 +724,17 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char len = min_t(unsigned int, len, sizeof(uf)); if (copy_to_user(optval, &uf, len)) - return -EFAULT; + err = -EFAULT; break; default: - return -ENOPROTOOPT; + err = -ENOPROTOOPT; break; } - return 0; +done: + release_sock(sk); + return err; } static const struct proto_ops hci_sock_ops = { -- cgit v1.2.3 From 3a208627f3ac83d3b749608770f7eb631db31a77 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:34 +0100 Subject: Bluetooth: Add HCI CMSG details only to raw sockets The HCI CMSG specific data is for raw sockets only. So only add them to actual raw sockets. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 27ec9088508f..71a02adbaa77 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -488,7 +488,11 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, skb_reset_transport_header(skb); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - hci_sock_cmsg(sk, msg, skb); + switch (hci_pi(sk)->channel) { + case HCI_CHANNEL_RAW: + hci_sock_cmsg(sk, msg, skb); + break; + } skb_free_datagram(sk, skb); -- cgit v1.2.3 From 7cc2ade2cbc6f71090f0f8d0e11cb68886ddc65e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:35 +0100 Subject: Bluetooth: Simplify HCI socket bind handling The HCI socket bind handling checks a few too many times the channel we are binding. So centralize this and make the function easier to read. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 71a02adbaa77..4dda4574db3e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -367,34 +367,49 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le if (haddr.hci_family != AF_BLUETOOTH) return -EINVAL; - if (haddr.hci_channel > HCI_CHANNEL_CONTROL) - return -EINVAL; - - if (haddr.hci_channel == HCI_CHANNEL_CONTROL) { - if (!enable_mgmt) - return -EINVAL; - set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); - } - lock_sock(sk); - if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { + if (sk->sk_state == BT_BOUND) { err = -EALREADY; goto done; } - if (haddr.hci_dev != HCI_DEV_NONE) { - hdev = hci_dev_get(haddr.hci_dev); - if (!hdev) { - err = -ENODEV; + switch (haddr.hci_channel) { + case HCI_CHANNEL_RAW: + if (hci_pi(sk)->hdev) { + err = -EALREADY; goto done; } - atomic_inc(&hdev->promisc); + if (haddr.hci_dev != HCI_DEV_NONE) { + hdev = hci_dev_get(haddr.hci_dev); + if (!hdev) { + err = -ENODEV; + goto done; + } + + atomic_inc(&hdev->promisc); + } + + hci_pi(sk)->hdev = hdev; + break; + + case HCI_CHANNEL_CONTROL: + if (haddr.hci_dev != HCI_DEV_NONE || !enable_mgmt) { + err = -EINVAL; + goto done; + } + + set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); + break; + + default: + err = -EINVAL; + goto done; } + hci_pi(sk)->channel = haddr.hci_channel; - hci_pi(sk)->hdev = hdev; sk->sk_state = BT_BOUND; done: -- cgit v1.2.3 From e0edf3733fb62f91bbb8ec3fab4a90b0ac2dd037 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:36 +0100 Subject: Bluetooth: Fix issue with shared SKB between HCI raw socket and driver Any HCI raw socket gets a copy of each SKB that is either received or send via the Bluetooth subsystem. The raw socket uses SKB clones to send out data, but the problem is that it needs to add an extra packet type byte in front of it. And some drivers need to also add an extra header before submitting the packet. So far this all worked magically fine since all of the drivers and the raw sockets are adding the same byte at the same location. But that is by pure coincidence. Since the data of cloned SKBs is shared, this means that the raw socket and driver kept writing into the shared data area. To fix this the only safe way is if the HCI raw socket creates a copy of the SKB before sending it out. To not always copy all SKBs around, the copy is only created once and only after any of the HCI filter checks succeeded. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4dda4574db3e..cf940bd7a2b0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -89,6 +89,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { struct sock *sk; struct hlist_node *node; + struct sk_buff *skb_copy = NULL; BT_DBG("hdev %p len %d", hdev, skb->len); @@ -131,18 +132,27 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) continue; } - nskb = skb_clone(skb, GFP_ATOMIC); + if (!skb_copy) { + /* Create a private copy with headroom */ + skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC); + if (!skb_copy) + continue; + + /* Put type byte before the data */ + memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1); + } + + nskb = skb_clone(skb_copy, GFP_ATOMIC); if (!nskb) continue; - /* Put type byte before the data */ - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); - if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } read_unlock(&hci_sk_list.lock); + + kfree_skb(skb_copy); } /* Send frame to control socket */ -- cgit v1.2.3 From 040030ef7d907107e6489b39da518bdf94136d68 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:37 +0100 Subject: Bluetooth: Remove HCI notifier handling The HCI notifier handling was never used outside of Bluetooth core layer and thus remove it and replace it with direct function calls. Also move the stack internal event generation into the HCI socket layer. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 7 +-- net/bluetooth/hci_conn.c | 1 - net/bluetooth/hci_core.c | 16 +----- net/bluetooth/hci_event.c | 29 ----------- net/bluetooth/hci_sock.c | 105 +++++++++++++++++++++++---------------- 5 files changed, 64 insertions(+), 94 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9209e4c8a211..41adae509e9c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -941,21 +941,18 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); -int hci_register_notifier(struct notifier_block *nb); -int hci_unregister_notifier(struct notifier_block *nb); - int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); -void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); - /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_sock_dev_event(struct hci_dev *hdev, int event); + /* Management interface */ #define MGMT_ADDR_BREDR 0x00 #define MGMT_ADDR_LE_PUBLIC 0x01 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8549d04e3313..3c68e606d5e5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 638fa8c393d8..47217281d9ac 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -69,24 +68,11 @@ DEFINE_RWLOCK(hci_dev_list_lock); LIST_HEAD(hci_cb_list); DEFINE_RWLOCK(hci_cb_list_lock); -/* HCI notifiers list */ -static ATOMIC_NOTIFIER_HEAD(hci_notifier); - /* ---- HCI notifications ---- */ -int hci_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&hci_notifier, nb); -} - -int hci_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&hci_notifier, nb); -} - static void hci_notify(struct hci_dev *hdev, int event) { - atomic_notifier_call_chain(&hci_notifier, event, hdev); + hci_sock_dev_event(hdev, event); } /* ---- HCI requests ---- */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e69db4a7b3ef..f00faf0ac32f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -3547,33 +3546,5 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hdev->stat.evt_rx++; } -/* Generate internal stack event */ -void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) -{ - struct hci_event_hdr *hdr; - struct hci_ev_stack_internal *ev; - struct sk_buff *skb; - - skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); - if (!skb) - return; - - hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); - hdr->evt = HCI_EV_STACK_INTERNAL; - hdr->plen = sizeof(*ev) + dlen; - - ev = (void *) skb_put(skb, sizeof(*ev) + dlen); - ev->type = type; - memcpy(ev->data, data, dlen); - - bt_cb(skb)->incoming = 1; - __net_timestamp(skb); - - bt_cb(skb)->pkt_type = HCI_EVENT_PKT; - skb->dev = (void *) hdev; - hci_send_to_sock(hdev, skb); - kfree_skb(skb); -} - module_param(enable_le, bool, 0644); MODULE_PARM_DESC(enable_le, "Enable LE support"); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index cf940bd7a2b0..14727cb43f63 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -189,6 +189,67 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) read_unlock(&hci_sk_list.lock); } +/* Generate internal stack event */ +static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) +{ + struct hci_event_hdr *hdr; + struct hci_ev_stack_internal *ev; + struct sk_buff *skb; + + skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); + if (!skb) + return; + + hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); + hdr->evt = HCI_EV_STACK_INTERNAL; + hdr->plen = sizeof(*ev) + dlen; + + ev = (void *) skb_put(skb, sizeof(*ev) + dlen); + ev->type = type; + memcpy(ev->data, data, dlen); + + bt_cb(skb)->incoming = 1; + __net_timestamp(skb); + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + skb->dev = (void *) hdev; + hci_send_to_sock(hdev, skb); + kfree_skb(skb); +} + +void hci_sock_dev_event(struct hci_dev *hdev, int event) +{ + struct hci_ev_si_device ev; + + BT_DBG("hdev %s event %d", hdev->name, event); + + /* Send event to sockets */ + ev.event = event; + ev.dev_id = hdev->id; + hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); + + if (event == HCI_DEV_UNREG) { + struct sock *sk; + struct hlist_node *node; + + /* Detach sockets from device */ + read_lock(&hci_sk_list.lock); + sk_for_each(sk, node, &hci_sk_list.head) { + bh_lock_sock_nested(sk); + if (hci_pi(sk)->hdev == hdev) { + hci_pi(sk)->hdev = NULL; + sk->sk_err = EPIPE; + sk->sk_state = BT_OPEN; + sk->sk_state_change(sk); + + hci_dev_put(hdev); + } + bh_unlock_sock(sk); + } + read_unlock(&hci_sk_list.lock); + } +} + static int hci_sock_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -821,52 +882,12 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } -static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct hci_dev *hdev = (struct hci_dev *) ptr; - struct hci_ev_si_device ev; - - BT_DBG("hdev %s event %ld", hdev->name, event); - - /* Send event to sockets */ - ev.event = event; - ev.dev_id = hdev->id; - hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); - - if (event == HCI_DEV_UNREG) { - struct sock *sk; - struct hlist_node *node; - - /* Detach sockets from device */ - read_lock(&hci_sk_list.lock); - sk_for_each(sk, node, &hci_sk_list.head) { - bh_lock_sock_nested(sk); - if (hci_pi(sk)->hdev == hdev) { - hci_pi(sk)->hdev = NULL; - sk->sk_err = EPIPE; - sk->sk_state = BT_OPEN; - sk->sk_state_change(sk); - - hci_dev_put(hdev); - } - bh_unlock_sock(sk); - } - read_unlock(&hci_sk_list.lock); - } - - return NOTIFY_DONE; -} - static const struct net_proto_family hci_sock_family_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .create = hci_sock_create, }; -static struct notifier_block hci_sock_nblock = { - .notifier_call = hci_sock_dev_event -}; - int __init hci_sock_init(void) { int err; @@ -879,8 +900,6 @@ int __init hci_sock_init(void) if (err < 0) goto error; - hci_register_notifier(&hci_sock_nblock); - BT_INFO("HCI socket layer initialized"); return 0; @@ -896,8 +915,6 @@ void hci_sock_cleanup(void) if (bt_sock_unregister(BTPROTO_HCI) < 0) BT_ERR("HCI socket unregistration failed"); - hci_unregister_notifier(&hci_sock_nblock); - proto_unregister(&hci_sk_proto); } -- cgit v1.2.3 From cd82e61c110a36e398323e422896fcfe05879fed Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 20:34:38 +0100 Subject: Bluetooth: Add support for HCI monitor channel The HCI monitor channel can be used to monitor all packets and events from the Bluetooth subsystem. The monitor is not bound to any specific HCI device and allows even capturing multiple devices at the same time. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/hci_mon.h | 51 ++++++++++ net/bluetooth/hci_core.c | 13 ++- net/bluetooth/hci_sock.c | 207 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 include/net/bluetooth/hci_mon.h (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1b634e126878..60a4727be935 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1320,6 +1320,7 @@ struct sockaddr_hci { #define HCI_CHANNEL_RAW 0 #define HCI_CHANNEL_CONTROL 1 +#define HCI_CHANNEL_MONITOR 2 struct hci_filter { unsigned long type_mask; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 41adae509e9c..094b5dbdb130 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -950,6 +950,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h new file mode 100644 index 000000000000..07a25c92502c --- /dev/null +++ b/include/net/bluetooth/hci_mon.h @@ -0,0 +1,51 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + + Copyright (C) 2011-2012 Intel Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_MON_H +#define __HCI_MON_H + +struct hci_mon_hdr { + __le16 opcode; + __le16 index; + __le16 len; +} __packed; +#define HCI_MON_HDR_SIZE 6 + +#define HCI_MON_NEW_INDEX 0 +#define HCI_MON_DEL_INDEX 1 +#define HCI_MON_COMMAND_PKT 2 +#define HCI_MON_EVENT_PKT 3 +#define HCI_MON_ACL_TX_PKT 4 +#define HCI_MON_ACL_RX_PKT 5 +#define HCI_MON_SCO_TX_PKT 6 +#define HCI_MON_SCO_RX_PKT 7 + +struct hci_mon_new_index { + __u8 type; + __u8 bus; + bdaddr_t bdaddr; + char name[8]; +} __packed; +#define HCI_MON_NEW_INDEX_SIZE 16 + +#endif /* __HCI_MON_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 47217281d9ac..87ff7ffdb367 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2113,10 +2113,14 @@ static int hci_send_frame(struct sk_buff *skb) BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); - if (atomic_read(&hdev->promisc)) { - /* Time stamp */ - __net_timestamp(skb); + /* Time stamp */ + __net_timestamp(skb); + /* Send copy to monitor */ + hci_send_to_monitor(hdev, skb); + + if (atomic_read(&hdev->promisc)) { + /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); } @@ -2802,6 +2806,9 @@ static void hci_rx_work(struct work_struct *work) BT_DBG("%s", hdev->name); while ((skb = skb_dequeue(&hdev->rx_q))) { + /* Send copy to monitor */ + hci_send_to_monitor(hdev, skb); + if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 14727cb43f63..213697d23771 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -48,9 +48,12 @@ #include #include +#include static bool enable_mgmt; +static atomic_t monitor_promisc = ATOMIC_INIT(0); + /* ----- HCI socket interface ----- */ static inline int hci_test_bit(int nr, void *addr) @@ -189,6 +192,174 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) read_unlock(&hci_sk_list.lock); } +/* Send frame to monitor socket */ +void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + struct sk_buff *skb_copy = NULL; + __le16 opcode; + + if (!atomic_read(&monitor_promisc)) + return; + + BT_DBG("hdev %p len %d", hdev, skb->len); + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT); + break; + case HCI_EVENT_PKT: + opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT); + break; + case HCI_ACLDATA_PKT: + if (bt_cb(skb)->incoming) + opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT); + else + opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT); + break; + case HCI_SCODATA_PKT: + if (bt_cb(skb)->incoming) + opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT); + else + opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT); + break; + default: + return; + } + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR) + continue; + + if (!skb_copy) { + struct hci_mon_hdr *hdr; + + /* Create a private copy with headroom */ + skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC); + if (!skb_copy) + continue; + + /* Put header before the data */ + hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE); + hdr->opcode = opcode; + hdr->index = cpu_to_le16(hdev->id); + hdr->len = cpu_to_le16(skb->len); + } + + nskb = skb_clone(skb_copy, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); + + kfree_skb(skb_copy); +} + +static void send_monitor_event(struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + + BT_DBG("len %d", skb->len); + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR) + continue; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); +} + +static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) +{ + struct hci_mon_hdr *hdr; + struct hci_mon_new_index *ni; + struct sk_buff *skb; + __le16 opcode; + + switch (event) { + case HCI_DEV_REG: + skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC); + if (!skb) + return NULL; + + ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE); + ni->type = hdev->dev_type; + ni->bus = hdev->bus; + bacpy(&ni->bdaddr, &hdev->bdaddr); + memcpy(ni->name, hdev->name, 8); + + opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX); + break; + + case HCI_DEV_UNREG: + skb = bt_skb_alloc(0, GFP_ATOMIC); + if (!skb) + return NULL; + + opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX); + break; + + default: + return NULL; + } + + __net_timestamp(skb); + + hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE); + hdr->opcode = opcode; + hdr->index = cpu_to_le16(hdev->id); + hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); + + return skb; +} + +static void send_monitor_replay(struct sock *sk) +{ + struct hci_dev *hdev; + + read_lock(&hci_dev_list_lock); + + list_for_each_entry(hdev, &hci_dev_list, list) { + struct sk_buff *skb; + + skb = create_monitor_event(hdev, HCI_DEV_REG); + if (!skb) + continue; + + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); + } + + read_unlock(&hci_dev_list_lock); +} + /* Generate internal stack event */ static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) { @@ -223,6 +394,17 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) BT_DBG("hdev %s event %d", hdev->name, event); + /* Send event to monitor */ + if (atomic_read(&monitor_promisc)) { + struct sk_buff *skb; + + skb = create_monitor_event(hdev, event); + if (skb) { + send_monitor_event(skb); + kfree_skb(skb); + } + } + /* Send event to sockets */ ev.event = event; ev.dev_id = hdev->id; @@ -262,6 +444,9 @@ static int hci_sock_release(struct socket *sock) hdev = hci_pi(sk)->hdev; + if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR) + atomic_dec(&monitor_promisc); + bt_sock_unlink(&hci_sk_list, sk); if (hdev) { @@ -474,6 +659,22 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; + case HCI_CHANNEL_MONITOR: + if (haddr.hci_dev != HCI_DEV_NONE) { + err = -EINVAL; + goto done; + } + + if (!capable(CAP_NET_RAW)) { + err = -EPERM; + goto done; + } + + send_monitor_replay(sk); + + atomic_inc(&monitor_promisc); + break; + default: err = -EINVAL; goto done; @@ -578,6 +779,9 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_RAW: hci_sock_cmsg(sk, msg, skb); break; + case HCI_CHANNEL_MONITOR: + sock_recv_timestamp(msg, sk, skb); + break; } skb_free_datagram(sk, skb); @@ -612,6 +816,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_CONTROL: err = mgmt_control(sk, msg, len); goto done; + case HCI_CHANNEL_MONITOR: + err = -EOPNOTSUPP; + goto done; default: err = -EINVAL; goto done; -- cgit v1.2.3 From 801f13bd8ecc58f2cf42ec602a2b5db10fc5a132 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 20:54:10 +0100 Subject: Bluetooth: Restrict access to management interface The management interface on the HCI control channel should be restricted to applications with CAP_NET_ADMIN permission. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 213697d23771..8c429a179aa4 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -656,6 +656,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } + if (!capable(CAP_NET_ADMIN)) { + err = -EPERM; + goto done; + } + set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; -- cgit v1.2.3 From d7b7e79688c07b445bc52adfedf9a176be156f4b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 21:47:49 +0100 Subject: Bluetooth: Set supported settings based on enabled HS and/or LE Since neither High Speed (HS) nor Low Energy (LE) are fully implemented yet, only expose them in supported settings when enabled. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 5 ----- net/bluetooth/hci_event.c | 5 ----- net/bluetooth/mgmt.c | 18 ++++++++++++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 60a4727be935..ad5e94c757e7 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1422,5 +1422,6 @@ struct hci_inquiry_req { #define IREQ_CACHE_FLUSH 0x0001 extern bool enable_hs; +extern bool enable_le; #endif /* __HCI_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 87ff7ffdb367..cc52e037440e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -54,8 +54,6 @@ #define AUTO_OFF_TIMEOUT 2000 -bool enable_hs; - static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); @@ -2913,6 +2911,3 @@ int hci_cancel_inquiry(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); } - -module_param(enable_hs, bool, 0644); -MODULE_PARM_DESC(enable_hs, "Enable High Speed"); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f00faf0ac32f..5d0f92a948c2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -44,8 +44,6 @@ #include #include -static bool enable_le; - /* Handle HCI Event packets */ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) @@ -3545,6 +3543,3 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb); hdev->stat.evt_rx++; } - -module_param(enable_le, bool, 0644); -MODULE_PARM_DESC(enable_le, "Enable LE support"); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc71b45ef4e5..f7c2969d8829 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,6 +34,9 @@ #include #include +bool enable_hs; +bool enable_le; + #define MGMT_VERSION 1 #define MGMT_REVISION 0 @@ -374,8 +377,13 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_LINK_SECURITY; } - if (hdev->features[4] & LMP_LE) - settings |= MGMT_SETTING_LE; + if (enable_hs) + settings |= MGMT_SETTING_HS; + + if (enable_le) { + if (hdev->features[4] & LMP_LE) + settings |= MGMT_SETTING_LE; + } return settings; } @@ -3421,3 +3429,9 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); } + +module_param(enable_hs, bool, 0644); +MODULE_PARM_DESC(enable_hs, "Enable High Speed support"); + +module_param(enable_le, bool, 0644); +MODULE_PARM_DESC(enable_le, "Enable Low Energy support"); -- cgit v1.2.3 From 4b95a24ce12c4545fd7d2e3075841dc3119d1d71 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 21:24:37 +0100 Subject: Bluetooth: Always enable management interface The management interface API has reached stable version 1.0 and thus it can now be always enabled. All future changes will be made backwards compatible. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 8c429a179aa4..dd5635064145 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -50,8 +50,6 @@ #include #include -static bool enable_mgmt; - static atomic_t monitor_promisc = ATOMIC_INIT(0); /* ----- HCI socket interface ----- */ @@ -651,7 +649,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le break; case HCI_CHANNEL_CONTROL: - if (haddr.hci_dev != HCI_DEV_NONE || !enable_mgmt) { + if (haddr.hci_dev != HCI_DEV_NONE) { err = -EINVAL; goto done; } @@ -1129,6 +1127,3 @@ void hci_sock_cleanup(void) proto_unregister(&hci_sk_proto); } - -module_param(enable_mgmt, bool, 0644); -MODULE_PARM_DESC(enable_mgmt, "Enable Management interface"); -- cgit v1.2.3 From d930650b59be72342bc373ef52006ca99c1dd09e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:25:18 +0200 Subject: Bluetooth: mgmt: Add address type parameter to Stop Discovery command This patch adds an address type parameter to the Stop Discovery command which should match the value given to Start Discovery. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 3 +++ net/bluetooth/mgmt.c | 33 ++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 7e3d38bfaec3..870a3deab6ea 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -283,6 +283,9 @@ struct mgmt_cp_start_discovery { } __packed; #define MGMT_OP_STOP_DISCOVERY 0x0024 +struct mgmt_cp_stop_discovery { + __u8 type; +} __packed; #define MGMT_OP_CONFIRM_NAME 0x0025 struct mgmt_cp_confirm_name { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7c2969d8829..3db8525b0293 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2281,8 +2281,9 @@ failed: return err; } -static int stop_discovery(struct sock *sk, u16 index) +static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) { + struct mgmt_cp_stop_discovery *mgmt_cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; struct hci_cp_remote_name_req_cancel cp; @@ -2291,6 +2292,10 @@ static int stop_discovery(struct sock *sk, u16 index) BT_DBG("hci%u", index); + if (len != sizeof(*mgmt_cp)) + return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_INVALID_PARAMS); + hdev = hci_dev_get(index); if (!hdev) return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, @@ -2299,8 +2304,16 @@ static int stop_discovery(struct sock *sk, u16 index) hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_REJECTED); + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_REJECTED, + &mgmt_cp->type, sizeof(mgmt_cp->type)); + goto unlock; + } + + if (hdev->discovery.type != mgmt_cp->type) { + err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + MGMT_STATUS_INVALID_PARAMS, + &mgmt_cp->type, sizeof(mgmt_cp->type)); goto unlock; } @@ -2323,7 +2336,7 @@ static int stop_discovery(struct sock *sk, u16 index) if (!e) { mgmt_pending_remove(cmd); err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0, - NULL, 0); + &mgmt_cp->type, sizeof(mgmt_cp->type)); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; } @@ -2706,7 +2719,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = start_discovery(sk, index, cp, len); break; case MGMT_OP_STOP_DISCOVERY: - err = stop_discovery(sk, index); + err = stop_discovery(sk, index, cp, len); break; case MGMT_OP_CONFIRM_NAME: err = confirm_name(sk, index, cp, len); @@ -3369,7 +3382,9 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) if (!cmd) return -ENOENT; - err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status)); + err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), + &hdev->discovery.type, + sizeof(hdev->discovery.type)); mgmt_pending_remove(cmd); return err; @@ -3389,12 +3404,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) if (cmd != NULL) { u8 type = hdev->discovery.type; - if (discovering) - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type, sizeof(type)); - else - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, - NULL, 0); mgmt_pending_remove(cmd); } -- cgit v1.2.3 From f963e8e9d3652f4a8065d969206707a1c21ff9b0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:30:44 +0200 Subject: Bluetooth: mgmt: Add address type parameter to Discovering event This patch adds an address type parameter to the Discovering event. The value matches that given to Start/Stop Discovery. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++++ net/bluetooth/hci_core.c | 3 +-- net/bluetooth/mgmt.c | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 870a3deab6ea..1dbadbe14785 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -402,6 +402,10 @@ struct mgmt_ev_device_found { } __packed; #define MGMT_EV_DISCOVERING 0x0013 +struct mgmt_ev_discovering { + __u8 type; + __u8 discovering; +} __packed; #define MGMT_EV_DEVICE_BLOCKED 0x0014 struct mgmt_ev_device_blocked { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cc52e037440e..a7439aeb1f9b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -363,10 +363,9 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: - hdev->discovery.type = 0; - if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); + hdev->discovery.type = 0; break; case DISCOVERY_STARTING: break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3db8525b0293..86148b182891 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3392,6 +3392,7 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) int mgmt_discovering(struct hci_dev *hdev, u8 discovering) { + struct mgmt_ev_discovering ev; struct pending_cmd *cmd; BT_DBG("%s discovering %u", hdev->name, discovering); @@ -3409,8 +3410,11 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) mgmt_pending_remove(cmd); } - return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering, - sizeof(discovering), NULL); + memset(&ev, 0, sizeof(ev)); + ev.type = hdev->discovery.type; + ev.discovering = discovering; + + return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); } int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) -- cgit v1.2.3 From 6d80dfd094a7b286e95cdcac79efeb7bbb4e226f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:50:38 +0200 Subject: Bluetooth: mgmt: Add basic support for Set High Speed command This patch adds rudimentary support for the Set High Speed command in the form of a new HCI dev flag (HCI_HS_ENABLED). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ad5e94c757e7..ec370494e568 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -95,6 +95,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, + HCI_HS_ENABLED, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 86148b182891..edf84c3e6a2b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -418,6 +418,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SSP; + if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags)) + settings |= MGMT_SETTING_HS; + return settings; } @@ -1093,6 +1096,41 @@ failed: return err; } +static int set_hs(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct hci_dev *hdev; + int err; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_HS, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_HS, + MGMT_STATUS_INVALID_PARAMS); + + if (!enable_hs) { + err = cmd_status(sk, index, MGMT_OP_SET_HS, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + + if (cp->val) + set_bit(HCI_HS_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_HS_ENABLED, &hdev->dev_flags); + + err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); + +failed: + hci_dev_put(hdev); + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2655,6 +2693,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_SSP: err = set_ssp(sk, index, cp, len); break; + case MGMT_OP_SET_HS: + err = set_hs(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; -- cgit v1.2.3 From 1e16357480fdeaeff7c5572f1afba7835473fcb6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 20 Feb 2012 23:53:46 +0200 Subject: Bluetooth: mgmt: Fix Set SSP check for supported feature If the local controller doesn't support SSP we should always return an error for the Set SSP command. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index edf84c3e6a2b..aa0d64040fac 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1065,6 +1065,12 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) goto failed; } + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); goto failed; -- cgit v1.2.3 From cacaf52f51697f832a26e8fdaa7b8e85785085da Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 00:52:42 +0200 Subject: Bluetooth: mgmt: Clear EIR data when disabling SSP EIR shouldn't be enabled if SSP isn't enabled. This patch adds the clearing of EIR data when disabling SSP and restores the data when SSP is re-enabled. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index aa0d64040fac..a5a2a6844aea 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3250,6 +3250,18 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) return err; } +static int clear_eir(struct hci_dev *hdev) +{ + struct hci_cp_write_eir cp; + + if (!(hdev->features[6] & LMP_EXT_INQ)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); +} + int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; @@ -3268,9 +3280,15 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) ev = cpu_to_le32(get_current_settings(hdev)); err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); - if (match.sk) + if (match.sk) { sock_put(match.sk); + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + update_eir(hdev); + else + clear_eir(hdev); + } + return err; } -- cgit v1.2.3 From f0d4b78a68c4fe3b0d45de9a50e8d29419177b83 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 21 Feb 2012 12:14:25 +0100 Subject: Bluetooth: Only keep controller up after init if powered on When a new controller gets added to the system, it needs to be brought up briefly to read basic information like features, BD_ADDR etc. and after a timeout it will be brought back down. The only command that should overwrite this timeout is the set power command from the management interface. Just reading the controller list or information is not a good reason to keep the controller up. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a5a2a6844aea..c25cb648059e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -339,9 +339,6 @@ static int read_index_list(struct sock *sk) i = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags)) - cancel_delayed_work(&d->power_off); - if (test_bit(HCI_SETUP, &d->dev_flags)) continue; @@ -392,11 +389,12 @@ static u32 get_current_settings(struct hci_dev *hdev) { u32 settings = 0; - if (test_bit(HCI_UP, &hdev->flags)) - settings |= MGMT_SETTING_POWERED; - else + if (!test_bit(HCI_UP, &hdev->flags)) return settings; + if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + settings |= MGMT_SETTING_POWERED; + if (test_bit(HCI_PSCAN, &hdev->flags)) settings |= MGMT_SETTING_CONNECTABLE; @@ -623,9 +621,6 @@ static int read_controller_info(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_INFO, MGMT_STATUS_INVALID_PARAMS); - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work_sync(&hdev->power_off); - hci_dev_lock(hdev); if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) @@ -753,6 +748,16 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { + cancel_delayed_work(&hdev->power_off); + + if (cp->val) { + err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); + mgmt_powered(hdev, 1); + goto failed; + } + } + up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); -- cgit v1.2.3 From 8ee5654034c85b3915d078147a9d1064cac1852e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 21 Feb 2012 12:33:48 +0100 Subject: Bluetooth: Don't send New Settings event during setup power down When the controller gets brought up for initial setup, it will be brought back down after a timeout. In that case, don't send a New Settings event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a7439aeb1f9b..a787c9c9d4cd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -739,9 +739,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->discov_timeout = 0; } - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work(&hdev->power_off); - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) cancel_delayed_work(&hdev->service_cache); @@ -787,9 +784,11 @@ static int hci_dev_do_close(struct hci_dev *hdev) * and no tasks are scheduled. */ hdev->close(hdev); - hci_dev_lock(hdev); - mgmt_powered(hdev, 0); - hci_dev_unlock(hdev); + if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { + hci_dev_lock(hdev); + mgmt_powered(hdev, 0); + hci_dev_unlock(hdev); + } /* Clear flags */ hdev->flags = 0; @@ -808,7 +807,12 @@ int hci_dev_close(__u16 dev) hdev = hci_dev_get(dev); if (!hdev) return -ENODEV; + + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + cancel_delayed_work(&hdev->power_off); + err = hci_dev_do_close(hdev); + hci_dev_put(hdev); return err; } @@ -1102,9 +1106,7 @@ static void hci_power_off(struct work_struct *work) BT_DBG("%s", hdev->name); - clear_bit(HCI_AUTO_OFF, &hdev->dev_flags); - - hci_dev_close(hdev->id); + hci_dev_do_close(hdev); } static void hci_discov_off(struct work_struct *work) -- cgit v1.2.3 From 4b34ee782164fbaf29b2e7c0e8cb3a898c0986ca Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 14:13:02 +0200 Subject: Bluetooth: mgmt: Fix powered checks for commands Having the HCI_AUTO_OFF flag set means that from a mgmt interface perspective we're still not powered, so all tests for HCI_UP should also include a test for HCI_AUTO_OFF. This patch adds a convenience macro for it. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c25cb648059e..c27481c3c95d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -118,6 +118,9 @@ static const u16 mgmt_events[] = { #define SERVICE_CACHE_TIMEOUT (5 * 1000) +#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ + !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + struct pending_cmd { struct list_head list; u16 opcode; @@ -733,7 +736,7 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_mode *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; - int err, up; + int err; BT_DBG("request for hci%u", index); @@ -758,8 +761,7 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) } } - up = test_bit(HCI_UP, &hdev->flags); - if ((cp->val && up) || (!cp->val && !up)) { + if (!!cp->val == hdev_is_powered(hdev)) { err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); goto failed; } @@ -810,7 +812,7 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_POWERED); goto failed; @@ -877,7 +879,7 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1005,7 +1007,7 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1064,7 +1066,7 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1621,7 +1623,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1690,7 +1692,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; @@ -1933,7 +1935,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); goto done; } @@ -2109,7 +2111,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_NOT_POWERED); goto unlock; @@ -2280,7 +2282,7 @@ static int start_discovery(struct sock *sk, u16 index, hci_dev_lock(hdev); - if (!test_bit(HCI_UP, &hdev->flags)) { + if (!hdev_is_powered(hdev)) { err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, MGMT_STATUS_NOT_POWERED); goto failed; -- cgit v1.2.3 From b5235a65ad19f47c5995f054d3dcce90570d1a1c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 14:32:24 +0200 Subject: Bluetooth: mgmt: Fix set_local_name and set_dev_class powered checks Both the Set Local Name and the Set Device Class commands should fail if the adapter is not powered on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c27481c3c95d..03a13843cd16 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1272,6 +1272,12 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -1288,6 +1294,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, NULL, 0); +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2076,6 +2083,12 @@ static int set_local_name(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, + MGMT_STATUS_NOT_POWERED); + goto failed; + } + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); if (!cmd) { -- cgit v1.2.3 From 5400c044f3fac38f521362d76711e4c170f78b89 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 16:40:33 +0200 Subject: Bluetooth: mgmt: Fix set_fast_connectable error return This patch ensures that Set Fast Connectable fails apropriately if we are not already in a connectable state (which is a pre-requisite for fast connectable). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 03a13843cd16..563190c9f7b0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2560,6 +2560,13 @@ static int set_fast_connectable(struct sock *sk, u16 index, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); + if (!hdev_is_powered(hdev)) + return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_NOT_POWERED); + + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_REJECTED); hci_dev_lock(hdev); -- cgit v1.2.3 From 0cbf4ed6e6f43ac399afefdd14a1ee86db8de7d0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 17:25:22 +0200 Subject: Bluetooth: mgmt: Fix pairable setting upon initialization When mgmt is not in use the HCI_PAIRABLE flag will get implicitly set so that pairing still works with old user space versions. However, as soon as mgmt comes into play we should clear this flag so that it can be properly set through the set_pairable command by user space. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 563190c9f7b0..0f87030f9c30 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -604,9 +604,17 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct hci_dev *hdev) { - if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) + if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + /* Non-mgmt controlled devices get this bit set + * implicitly so that pairing works for them, however + * for mgmt we require user-space to explicitly enable + * it + */ + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); + } + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) schedule_delayed_work(&hdev->service_cache, msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); -- cgit v1.2.3 From 5e5282bbfde9ca6157dba913d90cbab859a837e2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 16:01:30 +0200 Subject: Bluetooth: mgmt: Allow connectable/discoverable changes in off state This patch makes it possible to toggle the connectable & discoverable settings when powered off. Two new hdev->dev_flags flags are added to track what the scan mode should be when the device is finally powered on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 2 + net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 91 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 76 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ec370494e568..169d2f8cc4ee 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -96,6 +96,8 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_HS_ENABLED, + HCI_CONNECTABLE, + HCI_DISCOVERABLE, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a787c9c9d4cd..9d199494bd65 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -737,6 +737,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (hdev->discov_timeout > 0) { cancel_delayed_work(&hdev->discov_off); hdev->discov_timeout = 0; + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0f87030f9c30..6311be775ff2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -398,10 +398,10 @@ static u32 get_current_settings(struct hci_dev *hdev) if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) settings |= MGMT_SETTING_POWERED; - if (test_bit(HCI_PSCAN, &hdev->flags)) + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_CONNECTABLE; - if (test_bit(HCI_ISCAN, &hdev->flags)) + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_DISCOVERABLE; if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) @@ -804,6 +804,7 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_cp_set_discoverable *cp = data; struct hci_dev *hdev; struct pending_cmd *cmd; + u16 timeout; u8 scan; int err; @@ -818,9 +819,11 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); + timeout = get_unaligned_le16(&cp->timeout); + hci_dev_lock(hdev); - if (!hdev_is_powered(hdev)) { + if (!hdev_is_powered(hdev) && timeout > 0) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_POWERED); goto failed; @@ -833,8 +836,22 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) && - test_bit(HCI_PSCAN, &hdev->flags)) { + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + MGMT_STATUS_REJECTED); + goto failed; + } + + if (!hdev_is_powered(hdev)) { + if (cp->val) + set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + else + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); + goto failed; + } + + if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); goto failed; } @@ -857,7 +874,7 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) mgmt_pending_remove(cmd); if (cp->val) - hdev->discov_timeout = get_unaligned_le16(&cp->timeout); + hdev->discov_timeout = timeout; failed: hci_dev_unlock(hdev); @@ -888,8 +905,13 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_NOT_POWERED); + if (cp->val) + set_bit(HCI_CONNECTABLE, &hdev->dev_flags); + else { + clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + } + err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); goto failed; } @@ -900,7 +922,7 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { + if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); goto failed; } @@ -2881,9 +2903,22 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) __le32 ev; int err; + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + return 0; + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); - if (!powered) { + if (powered) { + u8 scan = 0; + + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + scan |= SCAN_PAGE; + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + scan |= SCAN_INQUIRY; + + if (scan) + hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + } else { u8 status = ENETDOWN; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } @@ -2902,15 +2937,25 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; - int err; + bool changed = false; + int err = 0; mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); + if (discoverable) { + if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + changed = true; + } - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + if (changed) { + __le32 ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + } + if (match.sk) sock_put(match.sk); @@ -2919,16 +2964,26 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { - __le32 ev; struct cmd_lookup match = { NULL, hdev }; - int err; + bool changed = false; + int err = 0; mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); + if (connectable) { + if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + changed = true; + } - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + if (changed) { + __le32 ev = cpu_to_le32(get_current_settings(hdev)); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + match.sk); + } if (match.sk) sock_put(match.sk); -- cgit v1.2.3 From df2c6c5ed5c0bc13b78e855d3e5d9aa3472567ba Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 19:15:49 +0200 Subject: Bluetooth: mgmt: Fix Removing discoverable timeout in set_connectable When switching connectable mode off any pending discoverable timeout must also be disabled to avoid duplicate write_scan_enable commands. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6311be775ff2..eec70a4ba36c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -935,9 +935,14 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) if (cp->val) scan = SCAN_PAGE; - else + else { scan = 0; + if (test_bit(HCI_ISCAN, &hdev->flags) && + hdev->discov_timeout > 0) + cancel_delayed_work(&hdev->discov_off); + } + err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3 From f1f0eb02213a3003ecb10b9c61694e588267b824 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 17:15:41 +0200 Subject: Bluetooth: mgmt: Fix current settings values when powered off We should not stop iterating through the various settings if powered off since most may still be set even then. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index eec70a4ba36c..86e63a707f5a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -392,10 +392,7 @@ static u32 get_current_settings(struct hci_dev *hdev) { u32 settings = 0; - if (!test_bit(HCI_UP, &hdev->flags)) - return settings; - - if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + if (hdev_is_powered(hdev)) settings |= MGMT_SETTING_POWERED; if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) -- cgit v1.2.3 From beadb2bddce5810dc668da156b4c2ca457940250 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 16:55:31 +0200 Subject: Bluetooth: mgmt: Add convenience function for sending New Settings The New Settings event needs to be sent from quite many places so it makes sense to have a convenience function for it to simplify the code. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 96 ++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 52 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 86e63a707f5a..439ec786ff8c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -796,6 +796,42 @@ failed: return err; } +static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, + u16 data_len, struct sock *skip_sk) +{ + struct sk_buff *skb; + struct mgmt_hdr *hdr; + + skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (void *) skb_put(skb, sizeof(*hdr)); + hdr->opcode = cpu_to_le16(event); + if (hdev) + hdr->index = cpu_to_le16(hdev->id); + else + hdr->index = cpu_to_le16(MGMT_INDEX_NONE); + hdr->len = cpu_to_le16(data_len); + + if (data) + memcpy(skb_put(skb, data_len), data, data_len); + + hci_send_to_control(skb, skip_sk); + kfree_skb(skb); + + return 0; +} + +static int new_settings(struct hci_dev *hdev, struct sock *skip) +{ + __le32 ev; + + ev = cpu_to_le32(get_current_settings(hdev)); + + return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); +} + static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_set_discoverable *cp = data; @@ -951,38 +987,10 @@ failed: return err; } -static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, - u16 data_len, struct sock *skip_sk) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - - skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(event); - if (hdev) - hdr->index = cpu_to_le16(hdev->id); - else - hdr->index = cpu_to_le16(MGMT_INDEX_NONE); - hdr->len = cpu_to_le16(data_len); - - if (data) - memcpy(skb_put(skb, data_len), data, data_len); - - hci_send_to_control(skb, skip_sk); - kfree_skb(skb); - - return 0; -} - static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_mode *cp = data; struct hci_dev *hdev; - __le32 ev; int err; BT_DBG("request for hci%u", index); @@ -1007,9 +1015,7 @@ static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - ev = cpu_to_le32(get_current_settings(hdev)); - - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk); + err = new_settings(hdev, sk); failed: hci_dev_unlock(hdev); @@ -2902,7 +2908,6 @@ static void settings_rsp(struct pending_cmd *cmd, void *data) int mgmt_powered(struct hci_dev *hdev, u8 powered) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; int err; if (!test_bit(HCI_MGMT, &hdev->dev_flags)) @@ -2925,10 +2930,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } - ev = cpu_to_le32(get_current_settings(hdev)); - - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), - match.sk); + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -2952,11 +2954,8 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) changed = true; } - if (changed) { - __le32 ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), - match.sk); - } + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -2981,11 +2980,8 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) changed = true; } - if (changed) { - __le32 ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), - match.sk); - } + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -3320,7 +3316,6 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; int err; if (status) { @@ -3333,8 +3328,7 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); @@ -3357,7 +3351,6 @@ static int clear_eir(struct hci_dev *hdev) int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; - __le32 ev; int err; if (status) { @@ -3369,8 +3362,7 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); - ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); + err = new_settings(hdev, match.sk); if (match.sk) { sock_put(match.sk); -- cgit v1.2.3 From 0224d2fafbbed4ac0cb05d08d3adab506a398451 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 19:40:05 +0200 Subject: Bluetooth: mgmt: Fix New Settings event for connectable/discoverable When powered off and doing changes to the Connectable or Discoverable setting we should also send an appropriate New Settings event in addition to the command response. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 439ec786ff8c..08b867a4d0e6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -876,11 +876,20 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) } if (!hdev_is_powered(hdev)) { - if (cp->val) - set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - else - clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + bool changed = false; + + if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { + change_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + changed = true; + } + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } @@ -938,13 +947,25 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { + bool changed = false; + + if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + changed = true; + if (cp->val) set_bit(HCI_CONNECTABLE, &hdev->dev_flags); else { clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } + err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } -- cgit v1.2.3 From a297e97cf7228467a8c5c76216945ccf029ae2a4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 17:55:47 +0200 Subject: Bluetooth: Fix clearing of persistent dev_flags Now that most flags are persistent, only the LE_SCAN flag should be cleared after a reset. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5d0f92a948c2..2a5d05c05e35 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -192,9 +192,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); - /* Reset all flags, except persistent ones */ - hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF) | - BIT(HCI_LINK_KEYS) | BIT(HCI_DEBUG_KEYS); + /* Reset all non-persistent flags */ + hdev->dev_flags &= ~(BIT(HCI_LE_SCAN)); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From ed9b5f2fa053adce8dac88a385d2225a8ac5f0b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 21 Feb 2012 20:47:06 +0200 Subject: Bluetooth: mgmt: Fix connectable/discoverable response values The connectable/discoverable flags need to be changed before sending the response since otherwise the settings value will be incorrect. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08b867a4d0e6..e8f890d7256a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2965,8 +2965,6 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) bool changed = false; int err = 0; - mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); - if (discoverable) { if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) changed = true; @@ -2975,6 +2973,9 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) changed = true; } + mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, + &match); + if (changed) err = new_settings(hdev, match.sk); @@ -2990,9 +2991,6 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) bool changed = false; int err = 0; - mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, - &match); - if (connectable) { if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags)) changed = true; @@ -3001,6 +2999,9 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) changed = true; } + mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, + &match); + if (changed) err = new_settings(hdev, match.sk); -- cgit v1.2.3 From 1b009c982482ee0e4cbabcd9bdae690a29119ede Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:54 +0200 Subject: Bluetooth: trivial: Fix long line Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 37736c6603fc..63539f940572 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2720,7 +2720,8 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd result = __le16_to_cpu(rsp->result); status = __le16_to_cpu(rsp->status); - BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", + dcid, scid, result, status); if (scid) { chan = l2cap_get_chan_by_scid(conn, scid); -- cgit v1.2.3 From 3df91ea20e744344100b10ae69a17211fcf5b207 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:55 +0200 Subject: Bluetooth: Revert to mutexes from RCU list Usage of RCU list looks not reasonalbe for a number of reasons: our code sleep and we had to use socket spinlocks. Most parts of code are updaters thus there is little sense to use RCU. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 166 +++++++++++++++++++++++++++------------------ net/bluetooth/l2cap_sock.c | 10 +++ 2 files changed, 109 insertions(+), 67 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 63539f940572..8e8e9e93fb34 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -77,36 +77,24 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->dcid == cid) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->dcid == cid) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->scid == cid) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->scid == cid) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } /* Find channel with given SCID. @@ -115,36 +103,32 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci { struct l2cap_chan *c; + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); - if (c) - lock_sock(c->sk); + mutex_unlock(&conn->chan_lock); + return c; } static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { - struct l2cap_chan *c, *r = NULL; - - rcu_read_lock(); + struct l2cap_chan *c; - list_for_each_entry_rcu(c, &conn->chan_l, list) { - if (c->ident == ident) { - r = c; - break; - } + list_for_each_entry(c, &conn->chan_l, list) { + if (c->ident == ident) + return c; } - - rcu_read_unlock(); - return r; + return NULL; } static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); - if (c) - lock_sock(c->sk); + mutex_unlock(&conn->chan_lock); + return c; } @@ -228,11 +212,13 @@ static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, chan_timer.work); + struct l2cap_conn *conn = chan->conn; struct sock *sk = chan->sk; int reason; BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); + mutex_lock(&conn->chan_lock); lock_sock(sk); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) @@ -248,6 +234,8 @@ static void l2cap_chan_timeout(struct work_struct *work) release_sock(sk); chan->ops->close(chan->data); + mutex_unlock(&conn->chan_lock); + l2cap_chan_put(chan); } @@ -331,7 +319,9 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_chan_hold(chan); - list_add_rcu(&chan->list, &conn->chan_l); + mutex_lock(&conn->chan_lock); + list_add(&chan->list, &conn->chan_l); + mutex_unlock(&conn->chan_lock); } /* Delete channel. @@ -348,8 +338,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - list_del_rcu(&chan->list); - synchronize_rcu(); + list_del(&chan->list); l2cap_chan_put(chan); @@ -400,10 +389,12 @@ static void l2cap_chan_cleanup_listen(struct sock *parent) /* Close not yet accepted channels */ while ((sk = bt_accept_dequeue(parent, NULL))) { struct l2cap_chan *chan = l2cap_pi(sk)->chan; + __clear_chan_timer(chan); lock_sock(sk); l2cap_chan_close(chan, ECONNRESET); release_sock(sk); + chan->ops->close(chan->data); } } @@ -718,13 +709,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan *chan; + struct l2cap_chan *chan, *tmp; BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -804,7 +795,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* Find socket with cid and source bdaddr. @@ -916,9 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -938,7 +929,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -948,16 +939,16 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) sk->sk_err = err; } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } static void l2cap_info_timeout(struct work_struct *work) @@ -984,6 +975,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); + mutex_lock(&conn->chan_lock); + /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { sk = chan->sk; @@ -993,6 +986,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) chan->ops->close(chan->data); } + mutex_unlock(&conn->chan_lock); + hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) @@ -1050,6 +1045,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); + mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1792,9 +1788,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) continue; @@ -1810,7 +1806,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) kfree_skb(nskb); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -2600,6 +2596,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd parent = pchan->sk; + mutex_lock(&conn->chan_lock); lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ @@ -2673,6 +2670,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd response: release_sock(parent); + mutex_unlock(&conn->chan_lock); sendresp: rsp.scid = cpu_to_le16(scid); @@ -2714,6 +2712,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_chan *chan; struct sock *sk; u8 req[128]; + int err; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); @@ -2723,17 +2722,26 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); + mutex_lock(&conn->chan_lock); + if (scid) { - chan = l2cap_get_chan_by_scid(conn, scid); - if (!chan) - return -EFAULT; + chan = __l2cap_get_chan_by_scid(conn, scid); + if (!chan) { + err = -EFAULT; + goto unlock; + } } else { - chan = l2cap_get_chan_by_ident(conn, cmd->ident); - if (!chan) - return -EFAULT; + chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + if (!chan) { + err = -EFAULT; + goto unlock; + } } + err = 0; + sk = chan->sk; + lock_sock(sk); switch (result) { case L2CAP_CR_SUCCESS: @@ -2760,7 +2768,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd } release_sock(sk); - return 0; + +unlock: + mutex_unlock(&conn->chan_lock); + + return err; } static inline void set_default_fcs(struct l2cap_chan *chan) @@ -2793,6 +2805,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr return -ENOENT; sk = chan->sk; + lock_sock(sk); if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -2905,6 +2918,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr return 0; sk = chan->sk; + lock_sock(sk); switch (result) { case L2CAP_CONF_SUCCESS: @@ -3006,11 +3020,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - chan = l2cap_get_chan_by_scid(conn, dcid); - if (!chan) + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_scid(conn, dcid); + if (!chan) { + mutex_unlock(&conn->chan_lock); return 0; + } sk = chan->sk; + lock_sock(sk); rsp.dcid = cpu_to_le16(chan->scid); rsp.scid = cpu_to_le16(chan->dcid); @@ -3022,6 +3041,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd release_sock(sk); chan->ops->close(chan->data); + + mutex_unlock(&conn->chan_lock); + return 0; } @@ -3037,16 +3059,24 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - chan = l2cap_get_chan_by_scid(conn, scid); - if (!chan) + mutex_lock(&conn->chan_lock); + + chan = __l2cap_get_chan_by_scid(conn, scid); + if (!chan) { + mutex_unlock(&conn->chan_lock); return 0; + } sk = chan->sk; + lock_sock(sk); l2cap_chan_del(chan, 0); release_sock(sk); chan->ops->close(chan->data); + + mutex_unlock(&conn->chan_lock); + return 0; } @@ -4205,6 +4235,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk } sk = chan->sk; + lock_sock(sk); BT_DBG("chan %p, len %d", chan, skb->len); @@ -4492,9 +4523,9 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) cancel_delayed_work(&conn->security_timer); } - rcu_read_lock(); + mutex_lock(&conn->chan_lock); - list_for_each_entry_rcu(chan, &conn->chan_l, list) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -4574,7 +4605,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - rcu_read_unlock(); + mutex_unlock(&conn->chan_lock); return 0; } @@ -4635,6 +4666,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (chan && chan->sk) { struct sock *sk = chan->sk; + lock_sock(sk); if (chan->imtu < len - L2CAP_HDR_SIZE) { BT_ERR("Frame exceeding recv MTU (len %d, " diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b48d6c1b9db6..1273fcbeec28 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -796,6 +796,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; struct l2cap_chan *chan; + struct l2cap_conn *conn; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -804,6 +805,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) return 0; chan = l2cap_pi(sk)->chan; + conn = chan->conn; + + if (conn) + mutex_lock(&conn->chan_lock); lock_sock(sk); if (!sk->sk_shutdown) { @@ -811,6 +816,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; + l2cap_chan_close(chan, 0); if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) @@ -822,6 +828,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = -sk->sk_err; release_sock(sk); + + if (conn) + mutex_unlock(&conn->chan_lock); + return err; } -- cgit v1.2.3 From c03b355ea2938495bbdf25a4645be545be8890f4 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:56 +0200 Subject: Bluetooth: Add l2cap_chan_lock Channel lock will be used to lock L2CAP channels which are locked currently by socket locks. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 11 +++++++++++ net/bluetooth/l2cap_core.c | 2 ++ 2 files changed, 13 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bbb0e214e51d..d6d8ec8eb8cf 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -497,6 +497,7 @@ struct l2cap_chan { void *data; struct l2cap_ops *ops; + struct mutex lock; }; struct l2cap_ops { @@ -609,6 +610,16 @@ static inline void l2cap_chan_put(struct l2cap_chan *c) kfree(c); } +static inline void l2cap_chan_lock(struct l2cap_chan *chan) +{ + mutex_lock(&chan->lock); +} + +static inline void l2cap_chan_unlock(struct l2cap_chan *chan) +{ + mutex_unlock(&chan->lock); +} + static inline void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8e8e9e93fb34..e39eba1ac4da 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -247,6 +247,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) if (!chan) return NULL; + mutex_init(&chan->lock); + chan->sk = sk; write_lock(&chan_list_lock); -- cgit v1.2.3 From 0e587be728a522fd8e522ad905b02f2892b61712 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:57 +0200 Subject: Bluetooth: Add locked and unlocked state_change Split to locked and unlocked versions of l2cap_state_change helping to remove socket locks from l2cap code. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e39eba1ac4da..4638dbbaa4b2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -199,7 +199,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static void l2cap_state_change(struct l2cap_chan *chan, int state) +static void __l2cap_state_change(struct l2cap_chan *chan, int state) { BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), state_to_string(state)); @@ -208,6 +208,15 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) chan->ops->state_change(chan->data, state); } +static void l2cap_state_change(struct l2cap_chan *chan, int state) +{ + struct sock *sk = chan->sk; + + lock_sock(sk); + __l2cap_state_change(chan, state); + release_sock(sk); +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -348,7 +357,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) hci_conn_put(conn->hcon); } - l2cap_state_change(chan, BT_CLOSED); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); if (err) @@ -413,7 +422,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_LISTEN: l2cap_chan_cleanup_listen(sk); - l2cap_state_change(chan, BT_CLOSED); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); break; @@ -704,7 +713,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); - l2cap_state_change(chan, BT_DISCONN); + __l2cap_state_change(chan, BT_DISCONN); sk->sk_err = err; } @@ -770,7 +779,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } @@ -873,7 +882,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) __set_chan_timer(chan, sk->sk_sndtimeo); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); clean: @@ -890,7 +899,7 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) chan->conf_state = 0; __clear_chan_timer(chan); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); if (parent) @@ -922,7 +931,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); } else if (chan->state == BT_CONNECT) @@ -1196,14 +1205,14 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d l2cap_chan_add(conn, chan); - l2cap_state_change(chan, BT_CONNECT); + __l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); if (l2cap_chan_check_security(chan)) - l2cap_state_change(chan, BT_CONNECTED); + __l2cap_state_change(chan, BT_CONNECTED); } else l2cap_do_start(chan); } @@ -2650,22 +2659,22 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_chan_check_security(chan)) { if (bt_sk(sk)->defer_setup) { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHOR_PEND; parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); result = L2CAP_CR_SUCCESS; status = L2CAP_CS_NO_INFO; } } else { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHEN_PEND; } } else { - l2cap_state_change(chan, BT_CONNECT2); + __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_NO_INFO; } @@ -4584,12 +4593,12 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (parent) parent->sk_data_ready(parent, 0); } else { - l2cap_state_change(chan, BT_CONFIG); + __l2cap_state_change(chan, BT_CONFIG); res = L2CAP_CR_SUCCESS; stat = L2CAP_CS_NO_INFO; } } else { - l2cap_state_change(chan, BT_DISCONN); + __l2cap_state_change(chan, BT_DISCONN); __set_chan_timer(chan, msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); res = L2CAP_CR_SEC_BLOCK; -- cgit v1.2.3 From 2e0052e4cf78e3e205e92d82ee572ed726e315d6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 21 Feb 2012 12:54:58 +0200 Subject: Bluetooth: Add socket error function Use locked and unlocked versions to help removing socket locks from l2cap core functions. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4638dbbaa4b2..c0640b73c628 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -217,6 +217,22 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) release_sock(sk); } +static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err) +{ + struct sock *sk = chan->sk; + + sk->sk_err = err; +} + +static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) +{ + struct sock *sk = chan->sk; + + lock_sock(sk); + __l2cap_chan_set_err(chan, err); + release_sock(sk); +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -361,7 +377,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) sock_set_flag(sk, SOCK_ZAPPED); if (err) - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); if (parent) { bt_accept_unlink(sk); @@ -694,14 +710,11 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { - struct sock *sk; struct l2cap_disconn_req req; if (!conn) return; - sk = chan->sk; - if (chan->mode == L2CAP_MODE_ERTM) { __clear_retrans_timer(chan); __clear_monitor_timer(chan); @@ -714,7 +727,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c L2CAP_DISCONN_REQ, sizeof(req), &req); __l2cap_state_change(chan, BT_DISCONN); - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); } /* ---- L2CAP connections ---- */ @@ -953,10 +966,8 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; - if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) - sk->sk_err = err; + __l2cap_chan_set_err(chan, err); } mutex_unlock(&conn->chan_lock); @@ -2988,7 +2999,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } default: - sk->sk_err = ECONNRESET; + __l2cap_chan_set_err(chan, ECONNRESET); + __set_chan_timer(chan, msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); l2cap_send_disconn_req(conn, chan, ECONNRESET); -- cgit v1.2.3 From 47990ea09d393da8fb6cf284f4dba704c3661973 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 11:58:37 +0200 Subject: Bluetooth: mgmt: Make Set Link Security callable while powered off This patch makes it possible to change the Link Security setting while powered off and have it automatically enabled when powering on a device. To track the desired state once powered on a new HCI_LINK_SECURITY flag is added. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_event.c | 6 ++++++ net/bluetooth/mgmt.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 169d2f8cc4ee..806eb4120797 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -98,6 +98,7 @@ enum { HCI_HS_ENABLED, HCI_CONNECTABLE, HCI_DISCOVERABLE, + HCI_LINK_SECURITY, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2a5d05c05e35..5fb1ee516d3a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -594,6 +594,12 @@ static void hci_setup(struct hci_dev *hdev) sizeof(cp), &cp); } + if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) { + u8 enable = 1; + hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, + sizeof(enable), &enable); + } + if (hdev->features[4] & LMP_LE) hci_set_le_support(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e8f890d7256a..69d4e1a699a3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -410,7 +410,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (hdev->host_features[0] & LMP_HOST_LE) settings |= MGMT_SETTING_LE; - if (test_bit(HCI_AUTH, &hdev->flags)) + if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) settings |= MGMT_SETTING_LINK_SECURITY; if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) @@ -1067,8 +1067,21 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_NOT_POWERED); + bool changed = false; + + if (!!cp->val != test_bit(HCI_LINK_SECURITY, + &hdev->dev_flags)) { + change_bit(HCI_LINK_SECURITY, &hdev->dev_flags); + changed = true; + } + + err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } @@ -3338,7 +3351,8 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; - int err; + bool changed = false; + int err = 0; if (status) { u8 mgmt_err = mgmt_status(status); @@ -3347,10 +3361,19 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) return 0; } + if (test_bit(HCI_AUTH, &hdev->flags)) { + if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) + changed = true; + } + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, &match); - err = new_settings(hdev, match.sk); + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) sock_put(match.sk); -- cgit v1.2.3 From 2e99b0afc7445769bb886dc14a31aaa0dc17c4b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 12:28:39 +0200 Subject: Bluetooth: Remove unneeded hci_cc_read_ssp_mode function The kernel has no need to track the hci_read_ssp_mode command since it has the hci_sent_cmd_data function to check what value was set when hci_write_ssp_mode completes. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5fb1ee516d3a..1b1c3480a24d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -420,21 +420,6 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status); } -static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct hci_rp_read_ssp_mode *rp = (void *) skb->data; - - BT_DBG("%s status 0x%x", hdev->name, rp->status); - - if (rp->status) - return; - - if (rp->mode) - set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); - else - clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); -} - static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2201,10 +2186,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_host_buffer_size(hdev, skb); break; - case HCI_OP_READ_SSP_MODE: - hci_cc_read_ssp_mode(hdev, skb); - break; - case HCI_OP_WRITE_SSP_MODE: hci_cc_write_ssp_mode(hdev, skb); break; -- cgit v1.2.3 From c0ecddc2507da980af307aae40d6bcdea4c195dc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 12:38:31 +0200 Subject: Bluetooth: mgmt: Make Set SSP command callable while powered off This patch makes it possible to enable SSP through mgmt even when powered off. The setting will then get automatically actiated when powering on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_event.c | 20 ++++++++---------- net/bluetooth/mgmt.c | 44 ++++++++++++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 20 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 094b5dbdb130..6ba3a4b1078e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1006,7 +1006,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); -int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status); +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); 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); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1b1c3480a24d..240dc1640c04 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -427,21 +427,18 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - goto done; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); if (!sent) return; - if (*((u8 *) sent)) - set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); - else - clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); - -done: if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_ssp_enable_complete(hdev, status); + mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status); + else if (!status) { + if (*((u8 *) sent)) + set_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + } } static u8 hci_get_inquiry_mode(struct hci_dev *hdev) @@ -560,7 +557,8 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (hdev->features[6] & LMP_SIMPLE_PAIR) { + if (hdev->features[6] & LMP_SIMPLE_PAIR && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 69d4e1a699a3..eefd08468002 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1138,9 +1138,23 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + val = !!cp->val; + if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_POWERED); + bool changed = false; + + if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + change_bit(HCI_SSP_ENABLED, &hdev->dev_flags); + changed = true; + } + + err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + goto failed; } @@ -1155,8 +1169,6 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - val = !!cp->val; - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) { err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); goto failed; @@ -3393,21 +3405,37 @@ static int clear_eir(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); } -int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) +int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) { struct cmd_lookup match = { NULL, hdev }; - int err; + bool changed = false; + int err = 0; if (status) { u8 mgmt_err = mgmt_status(status); + + if (enable && test_and_clear_bit(HCI_SSP_ENABLED, + &hdev->dev_flags)) + err = new_settings(hdev, NULL); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, &mgmt_err); - return 0; + + return err; + } + + if (enable) { + if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + changed = true; } mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); - err = new_settings(hdev, match.sk); + if (changed) + err = new_settings(hdev, match.sk); if (match.sk) { sock_put(match.sk); -- cgit v1.2.3 From e5f0e151426bd83e4852a7a150fc6ad8ee349e69 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 11:59:01 +0100 Subject: Bluetooth: Fix two minor style issues in management code WARNING: Statements terminations use 1 semicolon + return err;; WARNING: space prohibited between function name and open parenthesis '(' + err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index eefd08468002..3f4c50eebbea 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -264,7 +264,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, if (err < 0) kfree_skb(skb); - return err;; + return err; } static int read_version(struct sock *sk) @@ -2532,7 +2532,7 @@ static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { - err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME, + err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, MGMT_STATUS_INVALID_PARAMS); goto failed; } -- cgit v1.2.3 From 70c1f20b00495fd25b81be14b263d32648a3d629 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 12:06:43 +0100 Subject: Bluetooth: Fix two minor style issues in HCI code WARNING: min() should probably be min_t(__u16, scb->expect, count) + len = min(scb->expect, (__u16)count); WARNING: Statements terminations use 1 semicolon + INIT_LIST_HEAD(&conn->chan_list);; Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3c68e606d5e5..947172bf1621 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -402,7 +402,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) skb_queue_head_init(&conn->data_q); - INIT_LIST_HEAD(&conn->chan_list);; + INIT_LIST_HEAD(&conn->chan_list); INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9d199494bd65..e1dadeea4c2f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1957,7 +1957,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, while (count) { scb = (void *) skb->cb; - len = min(scb->expect, (__u16)count); + len = min_t(__u16, scb->expect, count); memcpy(skb_put(skb, len), data, len); -- cgit v1.2.3 From 6bf0e4699d1dd56f7f8c12cf332ebffaf1c5e83e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 13:21:16 +0200 Subject: Bluetooth: Fix coding style issues in mgmt code In this case we need to use braces in both branches. Signed-off-by: Andrei Emeltchenko Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3f4c50eebbea..9fb44900f7d6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -952,9 +952,9 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) changed = true; - if (cp->val) + if (cp->val) { set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else { + } else { clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } @@ -987,9 +987,9 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (cp->val) + if (cp->val) { scan = SCAN_PAGE; - else { + } else { scan = 0; if (test_bit(HCI_ISCAN, &hdev->flags) && -- cgit v1.2.3 From 5fc6ebb102fdf6f589242ebfe3a07d112d60c7d5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 15:10:59 +0200 Subject: Bluetooth: mgmt: Fix EIR toggling with SSP This patch fixes setting the EIR properly when the SSP flag has been set when powered off (in such a case there is no pending Set_SSP command). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9fb44900f7d6..bdaadb278ce7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3437,14 +3437,13 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (changed) err = new_settings(hdev, match.sk); - if (match.sk) { + if (match.sk) sock_put(match.sk); - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) - update_eir(hdev); - else - clear_eir(hdev); - } + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + update_eir(hdev); + else + clear_eir(hdev); return err; } -- cgit v1.2.3 From c80da27e868f6ffbe1c6588937aa4e7aeab21dec Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 15:38:48 +0200 Subject: Bluetooth: mgmt: Fix clearing of hdev->eir The hdev->eir buffer needs to be cleared when clearing the EIR data. Otherwise subsequent attempts at setting the EIR to something valid again may fail because the code thinks that the EIR hasn't changed. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bdaadb278ce7..08c657df7f8c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3400,6 +3400,8 @@ static int clear_eir(struct hci_dev *hdev) if (!(hdev->features[6] & LMP_EXT_INQ)) return 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(&cp, 0, sizeof(cp)); return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); -- cgit v1.2.3 From 54d04dbbb933e8a49429d602b847e367782267e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 15:47:48 +0200 Subject: Bluetooth: Explicitly clear EIR data upon hci_dev setup Some controllers preserve their EIR data even after a reset so we need to explicitly clear this during the device setup procedure. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 240dc1640c04..3476d5c7b02d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -557,10 +557,19 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (hdev->features[6] & LMP_SIMPLE_PAIR && - test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { - u8 mode = 0x01; - hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); + if (hdev->features[6] & LMP_SIMPLE_PAIR) { + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + u8 mode = 0x01; + hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, + sizeof(mode), &mode); + } else { + struct hci_cp_write_eir cp; + + memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(&cp, 0, sizeof(cp)); + + hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); + } } if (hdev->features[3] & LMP_RSSI_INQ) -- cgit v1.2.3 From 97e0bdeb93cc9bd014c21d5400af4fa7f2fe2f91 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 13:49:28 +0100 Subject: Bluetooth: Enable timestamps for control channel The control channel can be also monitored, so include timestamps here as well. And make sure management events get their timestamp when they are created. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 1 + net/bluetooth/mgmt.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index dd5635064145..8a814bca00d7 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -782,6 +782,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_RAW: hci_sock_cmsg(sk, msg, skb); break; + case HCI_CHANNEL_CONTROL: case HCI_CHANNEL_MONITOR: sock_recv_timestamp(msg, sk, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08c657df7f8c..8b4df0473ec3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -817,6 +817,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (data) memcpy(skb_put(skb, data_len), data, data_len); + /* Time stamp */ + __net_timestamp(skb); + hci_send_to_control(skb, skip_sk); kfree_skb(skb); -- cgit v1.2.3 From 6c8f12c143fe83485afa530320e6f70dfc1aad54 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 16:35:26 +0200 Subject: Bluetooth: mgmt: Fix Set SSP supported check The test for SSP support needs to be earlier in the set_ssp function so that we return an error when SSP is not supported even when the device is powered off. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8b4df0473ec3..ac8ba839a78b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1141,6 +1141,12 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_SET_SSP, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + val = !!cp->val; if (!hdev_is_powered(hdev)) { @@ -1161,12 +1167,6 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_SUPPORTED); - goto failed; - } - if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); goto failed; -- cgit v1.2.3 From 06199cf86a84206cfdc96b8dc02d5c27efa8c60f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 16:37:11 +0200 Subject: Bluetooth: mgmt: Implement Set LE command This patch implements support for the Set LE mgmt command. Now, in addition to the enable_le module parameter user space needs to send an explicit Enable LE command to enable LE support. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 7 ++- net/bluetooth/mgmt.c | 119 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 126 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 806eb4120797..c97cf0872ac9 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -96,6 +96,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_HS_ENABLED, + HCI_LE_ENABLED, HCI_CONNECTABLE, HCI_DISCOVERABLE, HCI_LINK_SECURITY, diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6ba3a4b1078e..abdaa7900edb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1010,6 +1010,7 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); 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_le_enable_complete(struct hci_dev *hdev, u8 enable, 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 cfm_name, u8 *eir, u16 eir_len); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3476d5c7b02d..498b71a0579a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -539,7 +539,7 @@ static void hci_set_le_support(struct hci_dev *hdev) memset(&cp, 0, sizeof(cp)); - if (enable_le) { + if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } @@ -1130,10 +1130,15 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_cp_read_local_ext_features cp; + struct hci_cp_write_le_host_supported *sent; __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); + if (sent && test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_le_enable_complete(hdev, sent->le, status); + if (status) return; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ac8ba839a78b..8bc6a7a48732 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -407,7 +407,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (!(hdev->features[4] & LMP_NO_BREDR)) settings |= MGMT_SETTING_BREDR; - if (hdev->host_features[0] & LMP_HOST_LE) + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_LE; if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) @@ -1231,6 +1231,82 @@ failed: return err; } +static int set_le(struct sock *sk, u16 index, void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct hci_cp_write_le_host_supported hci_cp; + struct pending_cmd *cmd; + struct hci_dev *hdev; + int err; + u8 val; + + BT_DBG("request for hci%u", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_SET_LE, + MGMT_STATUS_INVALID_PARAMS); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LE, + MGMT_STATUS_INVALID_PARAMS); + + if (!enable_le || !(hdev->features[4] & LMP_LE)) { + err = cmd_status(sk, index, MGMT_OP_SET_LE, + MGMT_STATUS_NOT_SUPPORTED); + goto failed; + } + + val = !!cp->val; + + if (!hdev_is_powered(hdev)) { + bool changed = false; + + if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + change_bit(HCI_LE_ENABLED, &hdev->dev_flags); + changed = true; + } + + err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { + err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memset(&hci_cp, 0, sizeof(hci_cp)); + + if (val) { + hci_cp.le = val; + hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(hci_cp), &hci_cp); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_put(hdev); + return err; +} + static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; @@ -2816,6 +2892,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_HS: err = set_hs(sk, index, cp, len); break; + case MGMT_OP_SET_LE: + err = set_le(sk, index, cp, len); + break; case MGMT_OP_ADD_UUID: err = add_uuid(sk, index, cp, len); break; @@ -3521,6 +3600,44 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, return err; } +int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + bool changed = false; + int err = 0; + + if (status) { + u8 mgmt_err = mgmt_status(status); + + if (enable && test_and_clear_bit(HCI_LE_ENABLED, + &hdev->dev_flags)) + err = new_settings(hdev, NULL); + + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, + cmd_status_rsp, &mgmt_err); + + return err; + } + + if (enable) { + if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + changed = true; + } else { + if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + changed = true; + } + + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); + + if (changed) + err = new_settings(hdev, match.sk); + + if (match.sk) + sock_put(match.sk); + + return err; +} + int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 *eir, u16 eir_len) -- cgit v1.2.3 From e59fda8dc14c173b74b5e9d5c8d72849d2ff6b5f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 18:11:53 +0200 Subject: Bluetooth: Fix EIR data clearing when powering off When powering off we should assume that the EIR data isn't valid anymore. This patch makes sure it gets cleared in hci_dev_do_close and thereby ensures that a correct new EIR is recreated when powering on again. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e1dadeea4c2f..2d75ffb42f7d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -794,6 +794,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Clear flags */ hdev->flags = 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); + hci_req_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From f51d5b248981d05269e4f83ab8f8ed7ed494fe33 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 18:17:32 +0200 Subject: Bluetooth: mgmt: Fix updating EIR when updating the name Whenever we update the local device name the EIR data also needs to be updated to reflect this. The update_eir() function in mgmt.c depends on hdev->dev_name to be up to date so the patch also makes sure that the mgmt function is called from hci_event.c after the update has happened. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/mgmt.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 498b71a0579a..e44e3fd68628 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -209,12 +209,12 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_set_local_name_complete(hdev, sent, status); - if (status == 0) memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_set_local_name_complete(hdev, sent, status); + hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8bc6a7a48732..d756644163bc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3561,6 +3561,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) send_event: err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); + update_eir(hdev); failed: if (cmd) -- cgit v1.2.3 From 24c54a90527ca5b85e7feedde2c779dc056ffddb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 18:06:34 +0100 Subject: Bluetooth: Disabling discoverable with timeout is invalid Add one extra sanity check to ensure that the supplied timeout value is actually valid in this context. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d756644163bc..6df4af6e99cc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -850,13 +850,16 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); + timeout = get_unaligned_le16(&cp->timeout); + if (!cp->val && timeout > 0) + return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + MGMT_STATUS_INVALID_PARAMS); + hdev = hci_dev_get(index); if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); - timeout = get_unaligned_le16(&cp->timeout); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev) && timeout > 0) { -- cgit v1.2.3 From 955638ecec9431788e291fc99f34c42124071abe Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 18:21:00 +0100 Subject: Bluetooth: Fix handling of discoverable setting with timeout The current handling of the discoverable timeout was missing the proper handling of the timeout when the mode was already set. Now the command can be used to expire or retrigger the timeout. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6df4af6e99cc..f7e111f30434 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -900,6 +900,17 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) } if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { + if (hdev->discov_timeout > 0) { + cancel_delayed_work(&hdev->discov_off); + hdev->discov_timeout = 0; + } + + if (cp->val && timeout > 0) { + hdev->discov_timeout = timeout; + queue_delayed_work(hdev->workqueue, &hdev->discov_off, + msecs_to_jiffies(hdev->discov_timeout * 1000)); + } + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); goto failed; } -- cgit v1.2.3 From 7f9a903c57bb42b9f7ad8fb7867859d3252229ab Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 18:38:01 +0100 Subject: Bluetooth: Send management event for class of device changes Currently there are no events to other management sockets if the class of device got changed. So make sure they are sent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_event.c | 13 +++++++++---- net/bluetooth/mgmt.c | 10 ++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index abdaa7900edb..24dd770d442b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1007,6 +1007,8 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); +int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, + u8 status); 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); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e44e3fd68628..c79ffb955554 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -350,14 +350,19 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV); if (!sent) return; - memcpy(hdev->dev_class, sent, 3); + hci_dev_lock(hdev); + + if (status == 0) + memcpy(hdev->dev_class, sent, 3); + + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_set_class_of_dev_complete(hdev, sent, status); + + hci_dev_unlock(hdev); } static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7e111f30434..16bddd22713f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3546,6 +3546,16 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) return err; } +int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, + u8 status) +{ + int err; + + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); + + return err; +} + int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; -- cgit v1.2.3 From 490c5baba7a5ad80782d5eb778638d1cfc8d70ce Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 19:19:09 +0200 Subject: Bluetooth: Add hdev->short_name for EIR generation It's possible to provide a short name through the mgmt interface and this name can be used for EIR generation when the full name doesn't fit there. This patch adds the preliminary tracking of the provided short name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 +++ include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/mgmt.c | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 24dd770d442b..3fcc7f0d08c3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -129,6 +129,8 @@ struct le_scan_params { int timeout; }; +#define HCI_MAX_SHORT_NAME_LENGTH 10 + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -141,6 +143,7 @@ struct hci_dev { __u8 dev_type; bdaddr_t bdaddr; __u8 dev_name[HCI_MAX_NAME_LENGTH]; + __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH]; __u8 eir[HCI_MAX_EIR_LENGTH]; __u8 dev_class[3]; __u8 major_class; diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ac59cdd0fa1b..495668c77fb6 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -75,7 +75,7 @@ struct mgmt_rp_read_index_list { /* Reserve one extra byte for names in management messages so that they * are always guaranteed to be nul-terminated */ #define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) -#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1) +#define MGMT_MAX_SHORT_NAME_LENGTH (HCI_MAX_SHORT_NAME_LENGTH + 1) #define MGMT_SETTING_POWERED 0x00000001 #define MGMT_SETTING_CONNECTABLE 0x00000002 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 16bddd22713f..3f6a2df9d150 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2273,6 +2273,9 @@ static int set_local_name(struct sock *sk, u16 index, void *data, goto failed; } + memcpy(hdev->short_name, mgmt_cp->short_name, + sizeof(hdev->short_name)); + memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), &hci_cp); -- cgit v1.2.3 From db99b5fc77e6cec47d80703b471f1efe04527d2f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 20:14:22 +0200 Subject: Bluetooth: Fix read_name updating when HCI_SETUP is not set The local name should only be updated as a consequence of a hci_read_local_name if we are in the HCI_SETUP state. In all other scenarios it should only be updated through hci_write_local_name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c79ffb955554..9917fe3d1d18 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -227,7 +227,8 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); + if (test_bit(HCI_SETUP, &hdev->dev_flags)) + memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); } static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From 28cc7bde5978cbc58c9026123fa5f33b62ad66b3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 21:06:55 +0200 Subject: Bluetooth: mgmt: Allow local name changes while powered off This patch makes it possible to set the local name before powering on the device. The name will be applied using the hci_write_local_name command once the device gets powered on. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 13 ++++++++++--- net/bluetooth/mgmt.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 15 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9917fe3d1d18..9b30587c0de6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -209,11 +209,10 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (status == 0) - memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); - if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_set_local_name_complete(hdev, sent, status); + else if (!status) + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); hci_dev_unlock(hdev); } @@ -563,6 +562,14 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); + if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + test_bit(HCI_MGMT, &hdev->dev_flags)) { + struct hci_cp_write_local_name cp; + + memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); + hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); + } + if (hdev->features[6] & LMP_SIMPLE_PAIR) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3f6a2df9d150..9c1f7714794d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2260,22 +2260,29 @@ static int set_local_name(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); + memcpy(hdev->short_name, mgmt_cp->short_name, + sizeof(hdev->short_name)); + if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, - MGMT_STATUS_NOT_POWERED); + memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name)); + + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, + data, len); + if (err < 0) + goto failed; + + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len, + sk); + goto failed; } - cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, - len); + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); if (!cmd) { err = -ENOMEM; goto failed; } - memcpy(hdev->short_name, mgmt_cp->short_name, - sizeof(hdev->short_name)); - memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), &hci_cp); @@ -3563,10 +3570,17 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) { struct pending_cmd *cmd; struct mgmt_cp_set_local_name ev; - int err; + bool changed = false; + int err = 0; + + if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) { + memcpy(hdev->dev_name, name, sizeof(hdev->dev_name)); + changed = true; + } memset(&ev, 0, sizeof(ev)); memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH); cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev); if (!cmd) @@ -3578,16 +3592,16 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) goto failed; } - update_eir(hdev); - err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev, sizeof(ev)); if (err < 0) goto failed; send_event: - err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); + if (changed) + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, + sizeof(ev), cmd ? cmd->sk : NULL); + update_eir(hdev); failed: -- cgit v1.2.3 From 7bdaae4a4bc075cf73ab9c3a531b7229caa1f49e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 21:39:58 +0200 Subject: Bluetooth: mgmt: Fix name_changed event for short name changes Since we can't reliably track the short name changes just assume that we had a change whenever there's a pending mgmt command. In the worst case we just get one unnecessary name_changed signal. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9c1f7714794d..ee57edbb13ec 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3586,6 +3586,10 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) if (!cmd) goto send_event; + /* Always assume that either the short or the complete name has + * changed if there was a pending mgmt command */ + changed = true; + if (status) { err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, mgmt_status(status)); -- cgit v1.2.3 From 27fcc362297b8e838a929c947b82eabb3f4b7591 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 21:46:22 +0200 Subject: Bluetooth: mgmt: Fix missing short_name in read_info The short name is part of the Read Controller Info response and should be appropriately filled in based on the value of hdev->short_name. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ee57edbb13ec..6850a8b46c62 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -648,6 +648,7 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.dev_class, hdev->dev_class, 3); memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); + memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From 09b3c3fbbee9aef8ac5d9148ae61aae35766b2a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:01:41 +0200 Subject: Bluetooth: Fix clearing of dev_class when powering down We should assume a value of 0 for the device class when powered off. The appropriate place to do this is in hci_dev_do_close(). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2d75ffb42f7d..2ab78bfc108e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -795,6 +795,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->flags = 0; memset(hdev->eir, 0, sizeof(hdev->eir)); + memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); hci_req_unlock(hdev); -- cgit v1.2.3 From 8ec37034ef36b89cfb060bd9273db24e6acb1b3a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:02:50 +0200 Subject: Bluetooth: mgmt: Fix return value for set_class The return parameters for Set Device Class should consist of the new class value. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6850a8b46c62..23421f05abf2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1470,7 +1470,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, - NULL, 0); + hdev->dev_class, 3); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3 From 7770c4aacaf34fb69cb2acfb7469e9b4e34f1674 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:06:38 +0200 Subject: Bluetooth: mgmt: Check for HCI_UP in update_eir() and update_class() These functions should just silently fail when we're not powered on instead of trying to send HCI commands. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 23421f05abf2..3a2066504ffe 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -532,6 +532,9 @@ static int update_eir(struct hci_dev *hdev) { struct hci_cp_write_eir cp; + if (!test_bit(HCI_UP, &hdev->flags)) + return 0; + if (!(hdev->features[6] & LMP_EXT_INQ)) return 0; @@ -570,6 +573,9 @@ static int update_class(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + if (!test_bit(HCI_UP, &hdev->flags)) + return 0; + if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return 0; -- cgit v1.2.3 From 932f5ff5e32bf520eb9287b050c926faa6e76bcf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:11:32 +0200 Subject: Bluetooth: mgmt: Allow class of device changes while powered off This patch makes it possible to set the class when powered off. When powering on the right class of device value will be automatically writen to the controller. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3a2066504ffe..a45c2b70dfdb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1456,15 +1456,15 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + hdev->major_class = cp->major; + hdev->minor_class = cp->minor; + if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_NOT_POWERED); + err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + hdev->dev_class, 3); goto unlock; } - hdev->major_class = cp->major; - hdev->minor_class = cp->minor; - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { hci_dev_unlock(hdev); cancel_delayed_work_sync(&hdev->service_cache); -- cgit v1.2.3 From 5f97c1df5563349795f26ed249e2a8840237c569 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:41:18 +0200 Subject: Bluetooth: mgmt: Add missing powered checks to commands This patch adds missing powered checks to pair_device, cancel_pair_device, add_remote_oob_data and remove_remote_oob_data. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a45c2b70dfdb..7c7bc2a21393 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1735,6 +1735,12 @@ static int get_connections(struct sock *sk, u16 index) hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + count = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) @@ -1766,8 +1772,9 @@ static int get_connections(struct sock *sk, u16 index) err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len); -unlock: kfree(rp); + +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -2002,6 +2009,12 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + sec_level = BT_SECURITY_MEDIUM; if (cp->io_cap == 0x03) auth_type = HCI_AT_DEDICATED_BONDING; @@ -2084,6 +2097,12 @@ static int cancel_pair_device(struct sock *sk, u16 index, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); if (!cmd) { err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, @@ -2375,6 +2394,13 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, cp->randomizer); if (err < 0) @@ -2385,6 +2411,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2413,6 +2440,13 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, hci_dev_lock(hdev); + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); if (err < 0) status = MGMT_STATUS_INVALID_PARAMS; @@ -2422,6 +2456,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); +unlock: hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From 86a8cfc6d0428f32d702ec59c1b3ef38541a6821 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 22 Feb 2012 22:53:34 +0200 Subject: Bluetooth: mgmt: Fix unpair_device responses This patch adds an error return when not powered and cleans up/simpifies the function logic in the same go. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7c7bc2a21393..36bebfb2d840 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1561,7 +1561,6 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; - u8 status = 0; int err; if (len != sizeof(*cp)) @@ -1579,32 +1578,38 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); rp.addr.type = cp->addr.type; + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + MGMT_STATUS_NOT_POWERED, + &rp, sizeof(rp)); + goto unlock; + } + if (cp->addr.type == MGMT_ADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); else err = hci_remove_ltk(hdev, &cp->addr.bdaddr); if (err < 0) { - status = MGMT_STATUS_NOT_PAIRED; - goto unlock; - } - - if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, - &rp, sizeof(rp)); - device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + MGMT_STATUS_NOT_PAIRED, + &rp, sizeof(rp)); goto unlock; } - if (cp->addr.type == MGMT_ADDR_BREDR) - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + if (cp->disconnect) { + if (cp->addr.type == MGMT_ADDR_BREDR) + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); - else - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, + else + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); + } else { + conn = NULL; + } if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, + err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0, &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; @@ -1624,9 +1629,6 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) mgmt_pending_remove(cmd); unlock: - if (err < 0) - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status, - &rp, sizeof(rp)); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From 9a395a80dc6a2004787539dcc0c7d167ba87e89a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 00:00:32 +0200 Subject: Bluetooth: mgmt: Fix device_found parameters According to the latest mgmt API there's a flags field instead of a separate confirm_name paramter. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 5 ++++- net/bluetooth/mgmt.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 495668c77fb6..09646f5ef36a 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -393,11 +393,14 @@ struct mgmt_ev_auth_failed { __u8 status; } __packed; +#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01 +#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02 + #define MGMT_EV_DEVICE_FOUND 0x0012 struct mgmt_ev_device_found { struct mgmt_addr_info addr; __s8 rssi; - __u8 confirm_name; + __u8 flags[4]; __le16 eir_len; __u8 eir[0]; } __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 36bebfb2d840..b7b10ca297d5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3745,7 +3745,8 @@ 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 (cfm_name) + ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; if (eir_len > 0) memcpy(ev->eir, eir, eir_len); -- cgit v1.2.3 From 388fc8faf200f80159353eb86cde4ab75d0a0bbd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 00:38:59 +0200 Subject: Bluetooth: mgmt: Add legacy pairing info to dev_found events This patch makes sure that legacy pairing vs SSP infomation gets properly propageted to the device_found events in the form of the legacy pairing flag. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_core.c | 8 +++++++- net/bluetooth/hci_event.c | 26 ++++++++++++++------------ net/bluetooth/mgmt.c | 4 +++- 4 files changed, 27 insertions(+), 16 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3fcc7f0d08c3..720bdc26b7e9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -407,7 +407,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, struct inquiry_entry *ie); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known); + bool name_known, bool *ssp); /* ----- HCI Connections ----- */ enum { @@ -1018,7 +1018,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, 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 cfm_name, u8 *eir, u16 eir_len); + u8 cfm_name, u8 ssp, u8 *eir, + u16 eir_len); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2ab78bfc108e..e6cbb8a1f47d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -466,15 +466,21 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, } bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known) + bool name_known, bool *ssp) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); + if (ssp) + *ssp = data->ssp_mode; + ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); if (ie) { + if (ie->data.ssp_mode && ssp) + *ssp = true; + if (ie->name_state == NAME_NEEDED && data->rssi != ie->data.rssi) { ie->data.rssi = data->rssi; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9b30587c0de6..276f3ac06089 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1696,7 +1696,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { - bool name_known; + bool name_known, ssp; bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -1707,9 +1707,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.rssi = 0x00; data.ssp_mode = 0x00; - name_known = hci_inquiry_cache_update(hdev, &data, false); + name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, + info->dev_class, 0, !name_known, ssp, NULL, 0); } @@ -2783,7 +2783,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct { struct inquiry_data data; int num_rsp = *((__u8 *) skb->data); - bool name_known; + bool name_known, ssp; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -2807,10 +2807,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL, 0); + !name_known, ssp, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2825,10 +2825,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.rssi = info->rssi; data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, NULL, 0); + !name_known, ssp, NULL, 0); } } @@ -2964,7 +2964,7 @@ 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; + bool name_known, ssp; bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -2982,10 +2982,11 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct else name_known = true; - name_known = hci_inquiry_cache_update(hdev, &data, name_known); + name_known = hci_inquiry_cache_update(hdev, &data, name_known, + &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, info->data, + !name_known, ssp, info->data, sizeof(info->data)); } @@ -3310,7 +3311,8 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, - NULL, rssi, 0, ev->data, ev->length); + NULL, rssi, 0, 1, ev->data, + ev->length); ptr += sizeof(*ev) + ev->length + 1; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b7b10ca297d5..42d665bdc01f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3730,7 +3730,7 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, 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 cfm_name, u8 *eir, u16 eir_len) + u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len) { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; @@ -3747,6 +3747,8 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev->rssi = rssi; if (cfm_name) ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; + if (!ssp) + ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING; if (eir_len > 0) memcpy(ev->eir, eir, eir_len); -- cgit v1.2.3 From 643162a8e2c15a1c1983a0063d9941240b3bde30 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 17:11:55 +0200 Subject: Bluetooth: Add unlocked __l2cap_chan_add function Add unlocked L2CAP channel add function. Unlocked version will be used in later patches. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c0640b73c628..0e4f4cb2acbb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -300,7 +300,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } -static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, chan->psm, chan->dcid); @@ -346,8 +346,13 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_chan_hold(chan); - mutex_lock(&conn->chan_lock); list_add(&chan->list, &conn->chan_l); +} + +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +{ + mutex_lock(&conn->chan_lock); + __l2cap_chan_add(conn, chan); mutex_unlock(&conn->chan_lock); } -- cgit v1.2.3 From 6be3655552ee49aa2b5fd20fa1b08f28d0feac86 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 17:11:56 +0200 Subject: Bluetooth: Change sk lock to chan lock in L2CAP core Change sk lock to chan lock in l2cap core and move sk locks to l2cap sock code. bh_locks were used because of being RCU critical section. When needed use explicit socket locks. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 166 ++++++++++++++++++++++++++------------------- net/bluetooth/l2cap_sock.c | 18 ++++- 2 files changed, 114 insertions(+), 70 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0e4f4cb2acbb..5f4cfea33915 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -238,13 +238,12 @@ static void l2cap_chan_timeout(struct work_struct *work) struct l2cap_chan *chan = container_of(work, struct l2cap_chan, chan_timer.work); struct l2cap_conn *conn = chan->conn; - struct sock *sk = chan->sk; int reason; BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); mutex_lock(&conn->chan_lock); - lock_sock(sk); + l2cap_chan_lock(chan); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; @@ -256,7 +255,7 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_close(chan, reason); - release_sock(sk); + l2cap_chan_unlock(chan); chan->ops->close(chan->data); mutex_unlock(&conn->chan_lock); @@ -356,8 +355,6 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) mutex_unlock(&conn->chan_lock); } -/* Delete channel. - * Must be called on the locked socket. */ static void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; @@ -378,6 +375,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) hci_conn_put(conn->hcon); } + lock_sock(sk); + __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); @@ -390,6 +389,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); + release_sock(sk); + if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) && test_bit(CONF_INPUT_DONE, &chan->conf_state))) return; @@ -422,10 +423,10 @@ static void l2cap_chan_cleanup_listen(struct sock *parent) while ((sk = bt_accept_dequeue(parent, NULL))) { struct l2cap_chan *chan = l2cap_pi(sk)->chan; + l2cap_chan_lock(chan); __clear_chan_timer(chan); - lock_sock(sk); l2cap_chan_close(chan, ECONNRESET); - release_sock(sk); + l2cap_chan_unlock(chan); chan->ops->close(chan->data); } @@ -441,10 +442,12 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) switch (chan->state) { case BT_LISTEN: + lock_sock(sk); l2cap_chan_cleanup_listen(sk); __l2cap_state_change(chan, BT_CLOSED); sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); break; case BT_CONNECTED: @@ -487,7 +490,9 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) break; default: + lock_sock(sk); sock_set_flag(sk, SOCK_ZAPPED); + release_sock(sk); break; } } @@ -715,6 +720,7 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { + struct sock *sk = chan->sk; struct l2cap_disconn_req req; if (!conn) @@ -731,8 +737,10 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); + lock_sock(sk); __l2cap_state_change(chan, BT_DISCONN); __l2cap_chan_set_err(chan, err); + release_sock(sk); } /* ---- L2CAP connections ---- */ @@ -747,10 +755,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn) list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; - bh_lock_sock(sk); + l2cap_chan_lock(chan); if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -759,17 +767,15 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (!l2cap_chan_check_security(chan) || !__l2cap_no_conn_pending(chan)) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (!l2cap_mode_supported(chan->mode, conn->feat_mask) && test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) { - /* l2cap_chan_close() calls list_del(chan) - * so release the lock */ l2cap_chan_close(chan, ECONNRESET); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -789,6 +795,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.dcid = cpu_to_le16(chan->scid); if (l2cap_chan_check_security(chan)) { + lock_sock(sk); if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); @@ -801,6 +808,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); } + release_sock(sk); } else { rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); @@ -811,7 +819,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (test_bit(CONF_REQ_SENT, &chan->conf_state) || rsp.result != L2CAP_CR_SUCCESS) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -821,7 +829,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) chan->num_conf_req++; } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); @@ -910,7 +918,11 @@ clean: static void l2cap_chan_ready(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - struct sock *parent = bt_sk(sk)->parent; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; BT_DBG("sk %p, parent %p", sk, parent); @@ -922,6 +934,8 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) if (parent) parent->sk_data_ready(parent, 0); + + release_sock(sk); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -939,23 +953,25 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; - bh_lock_sock(sk); + l2cap_chan_lock(chan); if (conn->hcon->type == LE_LINK) { if (smp_conn_security(conn, chan->sec_level)) l2cap_chan_ready(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { + struct sock *sk = chan->sk; __clear_chan_timer(chan); + lock_sock(sk); __l2cap_state_change(chan, BT_CONNECTED); sk->sk_state_change(sk); + release_sock(sk); } else if (chan->state == BT_CONNECT) l2cap_do_start(chan); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); @@ -993,7 +1009,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan, *l; - struct sock *sk; if (!conn) return; @@ -1006,10 +1021,12 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); + l2cap_chan_del(chan, err); - release_sock(sk); + + l2cap_chan_unlock(chan); + chan->ops->close(chan->data); } @@ -1140,7 +1157,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d hci_dev_lock(hdev); - lock_sock(sk); + l2cap_chan_lock(chan); /* PSM must be odd and lsb of upper byte must be 0 */ if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && @@ -1167,17 +1184,21 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d goto done; } + lock_sock(sk); + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: /* Already connecting */ err = 0; + release_sock(sk); goto done; case BT_CONNECTED: /* Already connected */ err = -EISCONN; + release_sock(sk); goto done; case BT_OPEN: @@ -1187,11 +1208,15 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d default: err = -EBADFD; + release_sock(sk); goto done; } /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, dst); + + release_sock(sk); + chan->psm = psm; chan->dcid = cid; @@ -1219,16 +1244,18 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d /* Update source addr of the socket */ bacpy(src, conn->src); + l2cap_chan_unlock(chan); l2cap_chan_add(conn, chan); + l2cap_chan_lock(chan); - __l2cap_state_change(chan, BT_CONNECT); + l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); if (l2cap_chan_check_security(chan)) - __l2cap_state_change(chan, BT_CONNECTED); + l2cap_state_change(chan, BT_CONNECTED); } else l2cap_do_start(chan); } @@ -1236,6 +1263,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d err = 0; done: + l2cap_chan_unlock(chan); hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1277,14 +1305,14 @@ static void l2cap_monitor_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, monitor_timer.work); - struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - lock_sock(sk); + l2cap_chan_lock(chan); + if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - release_sock(sk); + l2cap_chan_unlock(chan); return; } @@ -1292,25 +1320,26 @@ static void l2cap_monitor_timeout(struct work_struct *work) __set_monitor_timer(chan); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - release_sock(sk); + l2cap_chan_unlock(chan); } static void l2cap_retrans_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, retrans_timer.work); - struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - lock_sock(sk); + l2cap_chan_lock(chan); + chan->retry_count = 1; __set_monitor_timer(chan); set_bit(CONN_WAIT_F, &chan->conn_state); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - release_sock(sk); + + l2cap_chan_unlock(chan); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) @@ -2001,9 +2030,11 @@ static void l2cap_ack_timeout(struct work_struct *work) BT_DBG("chan %p", chan); - lock_sock(chan->sk); + l2cap_chan_lock(chan); + __l2cap_send_ack(chan); - release_sock(chan->sk); + + l2cap_chan_unlock(chan); l2cap_chan_put(chan); } @@ -2664,7 +2695,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - l2cap_chan_add(conn, chan); + __l2cap_chan_add(conn, chan); dcid = chan->scid; @@ -2737,7 +2768,6 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; struct l2cap_chan *chan; - struct sock *sk; u8 req[128]; int err; @@ -2767,8 +2797,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd err = 0; - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); switch (result) { case L2CAP_CR_SUCCESS: @@ -2794,7 +2823,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; } - release_sock(sk); + l2cap_chan_unlock(chan); unlock: mutex_unlock(&conn->chan_lock); @@ -2819,7 +2848,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u8 rsp[64]; struct l2cap_chan *chan; - struct sock *sk; int len; dcid = __le16_to_cpu(req->dcid); @@ -2831,8 +2859,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return -ENOENT; - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -2921,7 +2948,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } unlock: - release_sock(sk); + l2cap_chan_unlock(chan); return 0; } @@ -2930,7 +2957,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct l2cap_chan *chan; - struct sock *sk; int len = cmd->len - sizeof(*rsp); scid = __le16_to_cpu(rsp->scid); @@ -2944,8 +2970,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return 0; - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); switch (result) { case L2CAP_CONF_SUCCESS: @@ -3004,7 +3029,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } default: - __l2cap_chan_set_err(chan, ECONNRESET); + l2cap_chan_set_err(chan, ECONNRESET); __set_chan_timer(chan, msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); @@ -3031,7 +3056,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } done: - release_sock(sk); + l2cap_chan_unlock(chan); return 0; } @@ -3056,17 +3081,21 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd return 0; } + l2cap_chan_lock(chan); + sk = chan->sk; - lock_sock(sk); rsp.dcid = cpu_to_le16(chan->scid); rsp.scid = cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); + lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; + release_sock(sk); l2cap_chan_del(chan, ECONNRESET); - release_sock(sk); + + l2cap_chan_unlock(chan); chan->ops->close(chan->data); @@ -3080,7 +3109,6 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; u16 dcid, scid; struct l2cap_chan *chan; - struct sock *sk; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); @@ -3095,11 +3123,11 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; } - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); l2cap_chan_del(chan, 0); - release_sock(sk); + + l2cap_chan_unlock(chan); chan->ops->close(chan->data); @@ -4251,7 +4279,6 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct l2cap_chan *chan; - struct sock *sk = NULL; u32 control; u16 tx_seq; int len; @@ -4259,11 +4286,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk chan = l2cap_get_chan_by_scid(conn, cid); if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); - goto drop; + /* Drop packet and return */ + kfree(skb); + return 0; } - sk = chan->sk; - lock_sock(sk); + l2cap_chan_lock(chan); BT_DBG("chan %p, len %d", chan, skb->len); @@ -4334,8 +4362,7 @@ drop: kfree_skb(skb); done: - if (sk) - release_sock(sk); + l2cap_chan_unlock(chan); return 0; } @@ -4554,9 +4581,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { - struct sock *sk = chan->sk; - - bh_lock_sock(sk); + l2cap_chan_lock(chan); BT_DBG("chan->scid %d", chan->scid); @@ -4566,19 +4591,19 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) l2cap_chan_ready(chan); } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } if (!status && (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)) { l2cap_check_encryption(chan, encrypt); - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); continue; } @@ -4599,9 +4624,12 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); } } else if (chan->state == BT_CONNECT2) { + struct sock *sk = chan->sk; struct l2cap_conn_rsp rsp; __u16 res, stat; + lock_sock(sk); + if (!status) { if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; @@ -4622,6 +4650,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) stat = L2CAP_CS_NO_INFO; } + release_sock(sk); + rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(res); @@ -4630,7 +4660,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) sizeof(rsp), &rsp); } - bh_unlock_sock(sk); + l2cap_chan_unlock(chan); } mutex_unlock(&conn->chan_lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1273fcbeec28..73a06c1b0cd7 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -127,6 +127,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (err) goto done; + lock_sock(sk); + err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: @@ -810,14 +812,18 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) if (conn) mutex_lock(&conn->chan_lock); + l2cap_chan_lock(chan); lock_sock(sk); + if (!sk->sk_shutdown) { if (chan->mode == L2CAP_MODE_ERTM) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; + release_sock(sk); l2cap_chan_close(chan, 0); + lock_sock(sk); if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) err = bt_sock_wait_state(sk, BT_CLOSED, @@ -828,6 +834,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = -sk->sk_err; release_sock(sk); + l2cap_chan_unlock(chan); if (conn) mutex_unlock(&conn->chan_lock); @@ -874,8 +881,12 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) struct sock *sk = data; struct l2cap_pinfo *pi = l2cap_pi(sk); - if (pi->rx_busy_skb) - return -ENOMEM; + lock_sock(sk); + + if (pi->rx_busy_skb) { + err = -ENOMEM; + goto done; + } err = sock_queue_rcv_skb(sk, skb); @@ -894,6 +905,9 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) err = 0; } +done: + release_sock(sk); + return err; } -- cgit v1.2.3 From b3fb611ec7b76048cb14600e9a5a9b57e5d913da Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 22 Feb 2012 17:11:57 +0200 Subject: Bluetooth: Remove socket lock check Simplify code so that we do not need to check whether socket is locked. Signed-off-by: Andrei Emeltchenko Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 73a06c1b0cd7..52c94c765779 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -125,15 +125,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); if (err) - goto done; + return err; lock_sock(sk); err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); -done: - if (sock_owned_by_user(sk)) - release_sock(sk); + + release_sock(sk); + return err; } -- cgit v1.2.3 From 60fc5fb66efa0bcbe028637206ed59df8cd4ac19 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 09:52:28 +0200 Subject: Bluetooth: mgmt: Fix count parameter in get_connections reply This patch fixes the count parameter in the Get Connections reply message. We cannot know the right number until iterating through all connections so set the parameter value only after the loop. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 42d665bdc01f..7fdba8fb9808 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1725,8 +1725,8 @@ static int get_connections(struct sock *sk, u16 index) struct hci_dev *hdev; struct hci_conn *c; size_t rp_len; - u16 count; - int i, err; + int err; + u16 i; BT_DBG(""); @@ -1743,21 +1743,19 @@ static int get_connections(struct sock *sk, u16 index) goto unlock; } - count = 0; + i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) - count++; + i++; } - rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info)); + rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); rp = kmalloc(rp_len, GFP_ATOMIC); if (!rp) { err = -ENOMEM; goto unlock; } - put_unaligned_le16(count, &rp->conn_count); - i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) @@ -1769,6 +1767,8 @@ static int get_connections(struct sock *sk, u16 index) i++; } + put_unaligned_le16(i, &rp->conn_count); + /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); -- cgit v1.2.3 From 69775ff6d101ccf435bd26ae822c24bbb20e11cf Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 23 Feb 2012 16:50:05 +0200 Subject: Bluetooth: Set DISCOVERY_STOPPED if controller resets If controller is reset during the discovery procedure, Start Discovery command stops working. This can be easily reproduced by running "hciconfig hci0 reset" while discovering devices, for instance. We should force discovery state to DISCOVERY_STOPPED in case we receive a reset command complete event. Otherwise we may stuck in one of the active discovery states (DISCOVERY_INQUIRY, DISCOVERY_LE_SCAN and DISCOVERY_RESOLVING) and subsequent Start Discovery commands will simply fail. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 276f3ac06089..3d1eef0df2a3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -194,6 +194,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) /* Reset all non-persistent flags */ hdev->dev_flags &= ~(BIT(HCI_LE_SCAN)); + + hdev->discovery.state = DISCOVERY_STOPPED; } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From 504c8dcd6b0ec3cd36ab221695c5516e88cf3d79 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 13:30:41 +0200 Subject: Bluetooth: mgmt: Fix update_eir/class with HCI_AUTO_OFF flag set If we're powered but still have the HCI_AUTO_OFF flag set the update_eir and update_class functions should not do anything. Additionally these functions need to be called when the flag is finally cleared through set_powered or when powering on for real. Signed-off-by: Johan Hedberg Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7fdba8fb9808..4e4889490635 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -532,7 +532,7 @@ static int update_eir(struct hci_dev *hdev) { struct hci_cp_write_eir cp; - if (!test_bit(HCI_UP, &hdev->flags)) + if (!hdev_is_powered(hdev)) return 0; if (!(hdev->features[6] & LMP_EXT_INQ)) @@ -573,7 +573,7 @@ static int update_class(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!test_bit(HCI_UP, &hdev->flags)) + if (!hdev_is_powered(hdev)) return 0; if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) @@ -3121,6 +3121,9 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) if (scan) hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + + update_class(hdev); + update_eir(hdev); } else { u8 status = ENETDOWN; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); -- cgit v1.2.3 From 9997a5332320dbaaee64b5c0581ccaa6589a15c9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 15:57:46 +0200 Subject: Bluetooth: mgmt: Fix return value of add/remove_uuid The Add/Remove UUID commands should return the device class instead of an empty parameter list. Signed-off-by: Johan Hedberg Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4e4889490635..000abc07bc1e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1367,7 +1367,7 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); failed: hci_dev_unlock(hdev); @@ -1428,7 +1428,8 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto unlock; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0); + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + hdev->dev_class, 3); unlock: hci_dev_unlock(hdev); -- cgit v1.2.3 From 4004b6d96a14edbd157a62ae25bf61022d7caccc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 21:30:12 +0200 Subject: Bluetooth: mgmt: Move service cache setting to a more sensible place Since we can now add UUIDs when powered off we don't really need to always use the service cache to avoid large bursts of HCI commands. Instead, the only important use case is when we're already powered and user space starts to initialize itself. This can be easiest detected by a "clear UUIDs" operation which is where this patch moves the service cache setting. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 000abc07bc1e..30a30b7b301c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -617,10 +617,6 @@ static void mgmt_init_hdev(struct hci_dev *hdev) */ clear_bit(HCI_PAIRABLE, &hdev->dev_flags); } - - if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) - schedule_delayed_work(&hdev->service_cache, - msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); } static int read_controller_info(struct sock *sk, u16 index) @@ -1399,6 +1395,12 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); + + if (hdev_is_powered(hdev) && + !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) + schedule_delayed_work(&hdev->service_cache, + msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + goto unlock; } -- cgit v1.2.3 From 9246a8693e74b3480913cf6e0c2d472267169990 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 21:33:16 +0200 Subject: Bluetooth: mgmt: Fix clear UUIDs response We also need to send a proper response when clearing UUIDs. This patch adds fixes the missing response for this use case. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 30a30b7b301c..93f2c1348add 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1401,7 +1401,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) schedule_delayed_work(&hdev->service_cache, msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); - goto unlock; + goto update_class; } found = 0; @@ -1422,6 +1422,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) goto unlock; } +update_class: err = update_class(hdev); if (err < 0) goto unlock; -- cgit v1.2.3 From 08c79b6133b70a6e3d462d11a89c80259ac66ec7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 22:31:51 +0200 Subject: Bluetooth: mgmt: Add flags parameter to device_connected This patch updates the Device Connected events to match the latest API by adding a flags parameter to them. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++-- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/hci_event.c | 8 ++++---- net/bluetooth/mgmt.c | 6 ++++-- 4 files changed, 11 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 720bdc26b7e9..facd7ed32b74 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -980,8 +980,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent); int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *name, u8 name_len, - u8 *dev_class); + u8 addr_type, u32 flags, u8 *name, + u8 name_len, u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 09646f5ef36a..7aab53e6b813 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -357,6 +357,7 @@ struct mgmt_ev_new_long_term_key { #define MGMT_EV_DEVICE_CONNECTED 0x000B struct mgmt_ev_device_connected { struct mgmt_addr_info addr; + __le32 flags; __le16 eir_len; __u8 eir[0]; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3d1eef0df2a3..fb6543b60dec 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1368,7 +1368,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, struct inquiry_entry *e; if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, + mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name, name_len, conn->dev_class); if (discov->state == DISCOVERY_STOPPED) @@ -2104,7 +2104,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, NULL, 0, + conn->dst_type, 0, NULL, 0, conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { @@ -2872,7 +2872,7 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, NULL, 0, + conn->dst_type, 0, NULL, 0, conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { @@ -3282,7 +3282,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type, NULL, 0, 0); + conn->dst_type, 0, NULL, 0, 0); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 93f2c1348add..79fe57573463 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3249,8 +3249,8 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) } int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *name, u8 name_len, - u8 *dev_class) + u8 addr_type, u32 flags, u8 *name, + u8 name_len, u8 *dev_class) { char buf[512]; struct mgmt_ev_device_connected *ev = (void *) buf; @@ -3259,6 +3259,8 @@ int mgmt_device_connected(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); + put_unaligned_le32(flags, &ev->flags); + if (name_len > 0) eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, name_len); -- cgit v1.2.3 From c95f0ba76f902bc8b540468b695bcfe8948e8e46 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 22:54:38 +0200 Subject: Bluetooth: mgmt: Track pending class changes This patch adds a flag to track pending changes to the class of device. This is needed since we cannot cleanly handle multiple simultaneous commands and need to return a "busy" error status in the mgmt commands that might trigger a class change. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c97cf0872ac9..05bd9aca4054 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -100,6 +100,7 @@ enum { HCI_CONNECTABLE, HCI_DISCOVERABLE, HCI_LINK_SECURITY, + HCI_PENDING_CLASS, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 79fe57573463..9f912dc71bae 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -570,6 +570,7 @@ static u8 get_service_classes(struct hci_dev *hdev) static int update_class(struct hci_dev *hdev) { u8 cod[3]; + int err; BT_DBG("%s", hdev->name); @@ -586,7 +587,11 @@ static int update_class(struct hci_dev *hdev) if (memcmp(cod, hdev->dev_class, 3) == 0) return 0; - return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); + err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); + if (err == 0) + set_bit(HCI_PENDING_CLASS, &hdev->dev_flags); + + return err; } static void service_cache_off(struct work_struct *work) @@ -1344,6 +1349,12 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_ADD_UUID, + MGMT_STATUS_BUSY); + goto failed; + } + uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { err = -ENOMEM; @@ -1393,6 +1404,12 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + MGMT_STATUS_BUSY); + goto unlock; + } + if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -1460,6 +1477,12 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hci_dev_lock(hdev); + if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + MGMT_STATUS_BUSY); + goto unlock; + } + hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -3259,7 +3282,7 @@ int mgmt_device_connected(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); - put_unaligned_le32(flags, &ev->flags); + ev->flags = __cpu_to_le32(flags); if (name_len > 0) eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, @@ -3614,6 +3637,8 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, { int err; + clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); return err; -- cgit v1.2.3 From 90e704543d6702971ecfe3fe2325829d89b76f6b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 23:09:40 +0200 Subject: Bluetooth: mgmt: Fix dev_class related command response timing All mgmt commands that may fire off a hci_write_class_of_device command should wait for the completion of the HCI command before sending a response to user space. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9f912dc71bae..7a906d6e0236 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1332,6 +1332,7 @@ failed: static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; + struct pending_cmd *cmd; struct hci_dev *hdev; struct bt_uuid *uuid; int err; @@ -1374,7 +1375,17 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) if (err < 0) goto failed; - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); + if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, + hdev->dev_class, 3); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } failed: hci_dev_unlock(hdev); @@ -1386,6 +1397,7 @@ failed: static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_remove_uuid *cp = data; + struct pending_cmd *cmd; struct list_head *p, *n; struct hci_dev *hdev; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1448,8 +1460,17 @@ update_class: if (err < 0) goto unlock; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, hdev->dev_class, 3); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } unlock: hci_dev_unlock(hdev); @@ -1462,6 +1483,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) { struct hci_dev *hdev; struct mgmt_cp_set_dev_class *cp = data; + struct pending_cmd *cmd; int err; BT_DBG("request for hci%u", index); @@ -1500,10 +1522,20 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) } err = update_class(hdev); + if (err < 0) + goto unlock; - if (err == 0) + if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, hdev->dev_class, 3); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } unlock: hci_dev_unlock(hdev); @@ -3110,6 +3142,7 @@ int mgmt_index_removed(struct hci_dev *hdev) struct cmd_lookup { struct sock *sk; struct hci_dev *hdev; + u8 mgmt_status; }; static void settings_rsp(struct pending_cmd *cmd, void *data) @@ -3632,14 +3665,41 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) return err; } +static void class_rsp(struct pending_cmd *cmd, void *data) +{ + struct cmd_lookup *match = data; + + cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status, + match->hdev->dev_class, 3); + + list_del(&cmd->list); + + if (match->sk == NULL) { + match->sk = cmd->sk; + sock_hold(match->sk); + } + + mgmt_pending_free(cmd); +} + int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status) { - int err; + struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; + int err = 0; clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); - err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); + mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match); + mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match); + mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match); + + if (!status) + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, + dev_class, 3, NULL); + + if (match.sk) + sock_put(match.sk); return err; } -- cgit v1.2.3 From 24b78d0f49b94f658e8bae707c158962535053dd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 23 Feb 2012 23:24:30 +0200 Subject: Bluetooth: mgmt: Fix clear_uuids response Since the clear_uuids operation doesn't send an immediate HCI command but just sets off a timer to wait for subsequent add_uuid calls it doesn't make sense to wait until the timer fires off to send the response. Instead send the response immediately. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7a906d6e0236..07e31f73f703 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1394,6 +1394,20 @@ failed: return err; } +static bool enable_service_cache(struct hci_dev *hdev) +{ + if (!hdev_is_powered(hdev)) + return false; + + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { + schedule_delayed_work(&hdev->service_cache, + msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + return true; + } + + return false; +} + static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) { struct mgmt_cp_remove_uuid *cp = data; @@ -1425,10 +1439,11 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); - if (hdev_is_powered(hdev) && - !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) - schedule_delayed_work(&hdev->service_cache, - msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + if (enable_service_cache(hdev)) { + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + hdev->dev_class, 3); + goto unlock; + } goto update_class; } -- cgit v1.2.3 From 3159d3843aa628b0ee9e8ef4b4fe8c935500c03f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Feb 2012 13:47:56 +0200 Subject: Bluetooth: Fix init request completion with old controllers With Bluetooth 1.1 controllers the last command in the HCI init sequence will be a write_local_name, however there was no callback to indicate init request completion in this case. This patch fixes the issue by adding the necessary callback to the write_local_name_complete handler. Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fb6543b60dec..3e817fed7706 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -217,6 +217,8 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); hci_dev_unlock(hdev); + + hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); } static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From 28b8df77449faa03b573638e089a855f8d25e0ed Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 24 Feb 2012 12:45:44 +0200 Subject: Bluetooth: Fix init request completion with AMP controllers Mark request status as done for Read Local Version HCI command. In AMP initialization this HCI command is the last and needs to be completed. Signed-off-by: Andrei Emeltchenko Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3e817fed7706..e920cd520a82 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -620,7 +620,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, rp->status); if (rp->status) - return; + goto done; hdev->hci_ver = rp->hci_ver; hdev->hci_rev = __le16_to_cpu(rp->hci_rev); @@ -634,6 +634,9 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_INIT, &hdev->flags)) hci_setup(hdev); + +done: + hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status); } static void hci_setup_link_policy(struct hci_dev *hdev) -- cgit v1.2.3 From 5b4cedaa14bd1fe3ca1d59c684203a6ae7747faa Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 24 Feb 2012 16:35:32 +0200 Subject: Bluetooth: Fix double locking in LE and conless chan Remove socket lock since chan->ops->recv locks socket itself. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5f4cfea33915..db04c9e4e1d9 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4369,18 +4369,13 @@ done: static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) { - struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_psm(0, psm, conn->src); if (!chan) goto drop; - sk = chan->sk; - - lock_sock(sk); - - BT_DBG("sk %p, len %d", sk, skb->len); + BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_BOUND && chan->state != BT_CONNECTED) goto drop; @@ -4389,31 +4384,23 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str goto drop; if (!chan->ops->recv(chan->data, skb)) - goto done; + return 0; drop: kfree_skb(skb); -done: - if (sk) - release_sock(sk); return 0; } static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { - struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_scid(0, cid, conn->src); if (!chan) goto drop; - sk = chan->sk; - - lock_sock(sk); - - BT_DBG("sk %p, len %d", sk, skb->len); + BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_BOUND && chan->state != BT_CONNECTED) goto drop; @@ -4422,14 +4409,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct goto drop; if (!chan->ops->recv(chan->data, skb)) - goto done; + return 0; drop: kfree_skb(skb); -done: - if (sk) - release_sock(sk); return 0; } -- cgit v1.2.3 From 9b27f350688c9399da10c2b888c4044c2c1bd923 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 24 Feb 2012 16:00:00 +0200 Subject: Bluetooth: Remove duplicated code in l2cap conn req The same sequence sending L2CAP Connection Request was used in several places. Using subroutine makes those places easy to read. Signed-off-by: Andrei Emeltchenko Reviewed-by: Ulisses Furquim Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 49 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index db04c9e4e1d9..bdcfbf0f631e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -667,6 +667,21 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); } +static void l2cap_send_conn_req(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct l2cap_conn_req req; + + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; + + chan->ident = l2cap_get_ident(conn); + + set_bit(CONF_CONNECT_PEND, &chan->conf_state); + + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -676,17 +691,8 @@ static void l2cap_do_start(struct l2cap_chan *chan) return; if (l2cap_chan_check_security(chan) && - __l2cap_no_conn_pending(chan)) { - struct l2cap_conn_req req; - req.scid = cpu_to_le16(chan->scid); - req.psm = chan->psm; - - chan->ident = l2cap_get_ident(conn); - set_bit(CONF_CONNECT_PEND, &chan->conf_state); - - l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, - sizeof(req), &req); - } + __l2cap_no_conn_pending(chan)) + l2cap_send_conn_req(chan); } else { struct l2cap_info_req req; req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); @@ -763,8 +769,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } if (chan->state == BT_CONNECT) { - struct l2cap_conn_req req; - if (!l2cap_chan_check_security(chan) || !__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); @@ -779,14 +783,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - req.scid = cpu_to_le16(chan->scid); - req.psm = chan->psm; - - chan->ident = l2cap_get_ident(conn); - set_bit(CONF_CONNECT_PEND, &chan->conf_state); - - l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, - sizeof(req), &req); + l2cap_send_conn_req(chan); } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -4593,15 +4590,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (chan->state == BT_CONNECT) { if (!status) { - struct l2cap_conn_req req; - req.scid = cpu_to_le16(chan->scid); - req.psm = chan->psm; - - chan->ident = l2cap_get_ident(conn); - set_bit(CONF_CONNECT_PEND, &chan->conf_state); - - l2cap_send_cmd(conn, chan->ident, - L2CAP_CONN_REQ, sizeof(req), &req); + l2cap_send_conn_req(chan); } else { __clear_chan_timer(chan); __set_chan_timer(chan, -- cgit v1.2.3 From 816a11d5ced501d368fabe09172f3d62744e8b53 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 26 Feb 2012 13:04:52 +0200 Subject: Bluetooth: Use kernel int types instead of ones from stdint.h u8/__u8/u32/etc should be used in the kernel instead of stdint.h types. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 4 ++-- net/bluetooth/bnep/sock.c | 6 +++--- net/bluetooth/cmtp/sock.c | 6 +++--- net/bluetooth/hidp/sock.c | 6 +++--- net/bluetooth/mgmt.c | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 05bd9aca4054..0c54fcfe7e0f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -691,8 +691,8 @@ struct hci_cp_host_buffer_size { #define HCI_OP_WRITE_EIR 0x0c52 struct hci_cp_write_eir { - uint8_t fec; - uint8_t data[HCI_MAX_EIR_LENGTH]; + __u8 fec; + __u8 data[HCI_MAX_EIR_LENGTH]; } __packed; #define HCI_OP_READ_SSP_MODE 0x0c55 diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 17800b1d28ea..9f9c8dcd8af0 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -143,10 +143,10 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == BNEPGETCONNLIST) { struct bnep_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -157,7 +157,7 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = bnep_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 3f2dd5c25ae5..1230faaac29b 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -137,10 +137,10 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == CMTPGETCONNLIST) { struct cmtp_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -151,7 +151,7 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = cmtp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 178ac7f127ad..73a32d705c1f 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -160,10 +160,10 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne { if (cmd == HIDPGETCONNLIST) { struct hidp_connlist_req cl; - uint32_t uci; + u32 uci; int err; - if (get_user(cl.cnum, (uint32_t __user *) arg) || + if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; @@ -174,7 +174,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne err = hidp_get_connlist(&cl); - if (!err && put_user(cl.cnum, (uint32_t __user *) arg)) + if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 07e31f73f703..27830f401698 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1075,7 +1075,7 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_mode *cp = data; struct pending_cmd *cmd; struct hci_dev *hdev; - uint8_t val; + u8 val; int err; BT_DBG("request for hci%u", index); @@ -1147,7 +1147,7 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) struct mgmt_mode *cp = data; struct pending_cmd *cmd; struct hci_dev *hdev; - uint8_t val; + u8 val; int err; BT_DBG("request for hci%u", index); -- cgit v1.2.3 From 0b60eba1b29740a606e6b7694d2dc98b6085a1bf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 00:57:24 +0200 Subject: Bluetooth: Don't send unnecessary write_le_enable command If the local host features indicate that LE is already in the state that is desired there's no point in sending the HCI command to try to change the setting. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 27830f401698..c4d3bc9c86b5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1260,7 +1260,7 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) struct pending_cmd *cmd; struct hci_dev *hdev; int err; - u8 val; + u8 val, enabled; BT_DBG("request for hci%u", index); @@ -1280,8 +1280,9 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) } val = !!cp->val; + enabled = !!(hdev->host_features[0] & LMP_HOST_LE); - if (!hdev_is_powered(hdev)) { + if (!hdev_is_powered(hdev) || val == enabled) { bool changed = false; if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { -- cgit v1.2.3 From 8f984dfaf0bfa1355548cfba00473c8fa8e22d6e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 01:07:22 +0200 Subject: Bluetooth: Remove redundant read_host_features commands Previously the write_le_enable would trigger a read_host_features command but since we have access to the value LE support was set to we can simply just clear or set the bit in hdev->host_features. This also removes a second unnecessary read_host_features command from the device initialization procedure since LE is only enabled after the first read_host_features command completes. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 59 +++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 25 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e920cd520a82..488fdbcfe762 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -542,20 +542,6 @@ static void hci_setup_event_mask(struct hci_dev *hdev) hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); } -static void hci_set_le_support(struct hci_dev *hdev) -{ - struct hci_cp_write_le_host_supported cp; - - memset(&cp, 0, sizeof(cp)); - - if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { - cp.le = 1; - cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); - } - - hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); -} - static void hci_setup(struct hci_dev *hdev) { if (hdev->dev_type != HCI_BREDR) @@ -608,9 +594,6 @@ static void hci_setup(struct hci_dev *hdev) hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable), &enable); } - - if (hdev->features[4] & LMP_LE) - hci_set_le_support(hdev); } static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) @@ -730,6 +713,22 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb hdev->features[6], hdev->features[7]); } +static void hci_set_le_support(struct hci_dev *hdev) +{ + struct hci_cp_write_le_host_supported cp; + + memset(&cp, 0, sizeof(cp)); + + if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + cp.le = 1; + cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); + } + + if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE)) + hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(cp), &cp); +} + static void hci_cc_read_local_ext_features(struct hci_dev *hdev, struct sk_buff *skb) { @@ -738,7 +737,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, BT_DBG("%s status 0x%x", hdev->name, rp->status); if (rp->status) - return; + goto done; switch (rp->page) { case 0: @@ -749,6 +748,10 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, break; } + if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE) + hci_set_le_support(hdev); + +done: hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status); } @@ -1149,21 +1152,27 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_cp_read_local_ext_features cp; struct hci_cp_write_le_host_supported *sent; __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); - if (sent && test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_le_enable_complete(hdev, sent->le, status); - - if (status) + if (!sent) return; - cp.page = 0x01; - hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp); + if (!status) { + if (sent->le) + hdev->host_features[0] |= LMP_HOST_LE; + else + hdev->host_features[0] &= ~LMP_HOST_LE; + } + + if (test_bit(HCI_MGMT, &hdev->dev_flags) && + !test_bit(HCI_INIT, &hdev->flags)) + mgmt_le_enable_complete(hdev, sent->le, status); + + hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status); } static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) -- cgit v1.2.3 From 02b7cc62b6176748dc5b55e0ca9c965f73a5c300 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 02:28:43 +0200 Subject: Bluetooth: Use LMP_HOST_SSP define instead of magic values This patch fixes the code to use the proper LMP_HOST_SSP define instead of magic values and thereby makes the code more readable. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 488fdbcfe762..8c3261db7611 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2869,9 +2869,9 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b ie = hci_inquiry_cache_lookup(hdev, &conn->dst); if (ie) - ie->data.ssp_mode = (ev->features[0] & 0x01); + ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP); - if (ev->features[0] & 0x01) + if (ev->features[0] & LMP_HOST_SSP) set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } @@ -3224,7 +3224,7 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); if (ie) - ie->data.ssp_mode = (ev->features[0] & 0x01); + ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP); hci_dev_unlock(hdev); } -- cgit v1.2.3 From 3379013bcfceb3c0365a3cf03543d6c67b84fc34 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Feb 2012 09:52:46 +0300 Subject: Bluetooth: use kfree_skb() instead of kfree() sk_buffs should be freed using kfree_skb(). Signed-off-by: Dan Carpenter Acked-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bdcfbf0f631e..df3be692f2cf 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4284,7 +4284,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); /* Drop packet and return */ - kfree(skb); + kfree_skb(skb); return 0; } -- cgit v1.2.3 From 89bb46d02046b59c1de3d2e92680f3a1062750d0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Feb 2012 09:57:59 +0300 Subject: Bluetooth: change min_t() cast in hci_reassembly() "count" is type int so the cast to __u16 truncates the high bits away and triggers a Smatch static checker warning. It looks like a high value of count could cause a forever loop, but I didn't follow it through to see if count is capped somewhere. Signed-off-by: Dan Carpenter Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e6cbb8a1f47d..db484a8e7364 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1966,7 +1966,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, while (count) { scb = (void *) skb->cb; - len = min_t(__u16, scb->expect, count); + len = min_t(uint, scb->expect, count); memcpy(skb_put(skb, len), data, len); -- cgit v1.2.3 From 978c93b90fc4768e295b20492b5db76d5e026e5e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 29 Feb 2012 10:41:41 +0200 Subject: Bluetooth: Save remote L2CAP fixed channel mask Fixed channel mask needs to be stored to decide whether to use A2MP for example. So far save only one relevant byte which keeps all information we need. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d6d8ec8eb8cf..3732a4849f2e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -522,6 +522,7 @@ struct l2cap_conn { unsigned int mtu; __u32 feat_mask; + __u8 fixed_chan_mask; __u8 info_state; __u8 info_ident; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index df3be692f2cf..bc8d558b01f6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3209,7 +3209,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm return 0; } - if (type == L2CAP_IT_FEAT_MASK) { + switch (type) { + case L2CAP_IT_FEAT_MASK: conn->feat_mask = get_unaligned_le32(rsp->data); if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { @@ -3226,11 +3227,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm l2cap_conn_start(conn); } - } else if (type == L2CAP_IT_FIXED_CHAN) { + break; + + case L2CAP_IT_FIXED_CHAN: + conn->fixed_chan_mask = rsp->data[0]; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; l2cap_conn_start(conn); + break; } return 0; -- cgit v1.2.3 From 426c189a1b34c0d36d5eddbe1c35bc961b1a1b68 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Feb 2012 11:41:04 -0300 Subject: Bluetooth: Change interleaved discovery behavior According to last discussion on IRC, if an interleaved discovery is issued, but the device is not dual mode, we should return error instead of performing a regular BR/EDR or LE-only discovery. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c4d3bc9c86b5..b0c43fe43563 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2540,29 +2540,6 @@ unlock: return err; } -static int discovery(struct hci_dev *hdev) -{ - int err; - - if (lmp_host_le_capable(hdev)) { - if (lmp_bredr_capable(hdev)) { - err = hci_le_scan(hdev, LE_SCAN_TYPE, - LE_SCAN_INT, LE_SCAN_WIN, - LE_SCAN_TIMEOUT_BREDR_LE); - } else { - hdev->discovery.type = DISCOV_TYPE_LE; - err = hci_le_scan(hdev, LE_SCAN_TYPE, - LE_SCAN_INT, LE_SCAN_WIN, - LE_SCAN_TIMEOUT_LE_ONLY); - } - } else { - hdev->discovery.type = DISCOV_TYPE_BREDR; - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); - } - - return err; -} - int mgmt_interleaved_discovery(struct hci_dev *hdev) { int err; @@ -2632,7 +2609,11 @@ static int start_discovery(struct sock *sk, u16 index, break; case DISCOV_TYPE_INTERLEAVED: - err = discovery(hdev); + if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE); + else + err = -ENOTSUPP; break; default: -- cgit v1.2.3 From 95b23582d796305c66952188de2f5159b28be766 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Sun, 12 Feb 2012 13:55:35 +0100 Subject: Bluetooth: Use NULL instead of integer for mgmt_device_connected param Last param of mgmt_device_connected is of pointer type, so use NULL instead of 0 for it. This fix following sparse warning: CHECK net/bluetooth/hci_event.c net/bluetooth/hci_event.c:3262:74: warning: Using plain integer as NULL pointer Signed-off-by: Szymon Janc Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8c3261db7611..746f7d372258 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3296,7 +3296,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type, 0, NULL, 0, 0); + conn->dst_type, 0, NULL, 0, NULL); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); -- cgit v1.2.3 From 53bf2426b4122d933213bba78bf736e88f7dc929 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 29 Feb 2012 16:38:13 -0300 Subject: Bluetooth: Fix Kconfig help description SMP is not a kernel module, it is part of Bluetooth Core (as already described in lines above). Signed-off-by: Andre Guedes Acked-by: Gustavo F. Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 9ec85eb8853d..3537d385035e 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -29,7 +29,6 @@ menuconfig BT BNEP Module (Bluetooth Network Encapsulation Protocol) CMTP Module (CAPI Message Transport Protocol) HIDP Module (Human Interface Device Protocol) - SMP Module (Security Manager Protocol) Say Y here to compile Bluetooth support into the kernel or say M to compile it as module (bluetooth). -- cgit v1.2.3 From 00abfe4442864144a77f70b6b411d691bcb796bf Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 1 Mar 2012 00:37:10 -0300 Subject: Bluetooth: Fix coding style with breaking lines Our limit is 80 and broken lines should as right as possible. Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btmrvl_debugfs.c | 19 +++++++++---------- net/bluetooth/hci_event.c | 3 ++- net/bluetooth/mgmt.c | 3 +-- 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 60fe333cfd40..3497347e6dbb 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -401,28 +401,27 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - priv, &btmrvl_psmode_fops); + priv, &btmrvl_psmode_fops); dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, - priv, &btmrvl_pscmd_fops); + priv, &btmrvl_pscmd_fops); dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, - priv, &btmrvl_gpiogap_fops); + priv, &btmrvl_gpiogap_fops); dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, - priv, &btmrvl_hsmode_fops); + priv, &btmrvl_hsmode_fops); dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, - priv, &btmrvl_hscmd_fops); + priv, &btmrvl_hscmd_fops); dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, - priv, &btmrvl_hscfgcmd_fops); + priv, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); dbg->curpsmode = debugfs_create_file("curpsmode", 0444, dbg->status_dir, priv, &btmrvl_curpsmode_fops); dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, - priv, &btmrvl_psstate_fops); + priv, &btmrvl_psstate_fops); dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, - priv, &btmrvl_hsstate_fops); + priv, &btmrvl_hsstate_fops); dbg->txdnldready = debugfs_create_file("txdnldready", 0444, - dbg->status_dir, - priv, + dbg->status_dir, priv, &btmrvl_txdnldready_fops); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 746f7d372258..aee9556e1039 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1344,7 +1344,8 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 1; } -static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e) +static inline int hci_resolve_name(struct hci_dev *hdev, + struct inquiry_entry *e) { struct hci_cp_remote_name_req cp; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b0c43fe43563..373b46a9eb17 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1926,8 +1926,7 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) goto failed; } - cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, - len); + cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len); if (!cmd) { err = -ENOMEM; goto failed; -- cgit v1.2.3 From 1de028ceb54ccd28cc96f1530a195ae1b6a6d5b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Feb 2012 19:55:35 -0800 Subject: Bluetooth: mgmt: Add missing hci_dev locking to set_le() The set_le() function was missing hci_dev locking which is e.g. critical for the mgmt pending command adding/removing. Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 373b46a9eb17..abf1adb8bc16 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1273,10 +1273,12 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_INVALID_PARAMS); + hci_dev_lock(hdev); + if (!enable_le || !(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); - goto failed; + goto unlock; } val = !!cp->val; @@ -1292,23 +1294,23 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev); if (err < 0) - goto failed; + goto unlock; if (changed) err = new_settings(hdev, sk); - goto failed; + goto unlock; } if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY); - goto failed; + goto unlock; } cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len); if (!cmd) { err = -ENOMEM; - goto failed; + goto unlock; } memset(&hci_cp, 0, sizeof(hci_cp)); @@ -1322,10 +1324,11 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) sizeof(hci_cp), &hci_cp); if (err < 0) { mgmt_pending_remove(cmd); - goto failed; + goto unlock; } -failed: +unlock: + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } -- cgit v1.2.3 From 8b90129cc5789a4c65547c91c9a7b1fd3a4d56a4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 23 Feb 2012 18:09:27 -0300 Subject: Bluetooth: Check capabilities in BR/EDR and LE-Only discovery This patch add an extra check for BR/EDR and LE-Only discovery. This way, we are able to return error immediately if the discovery type requested is not supported by the device. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index abf1adb8bc16..3fcccad75453 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2602,12 +2602,18 @@ static int start_discovery(struct sock *sk, u16 index, switch (hdev->discovery.type) { case DISCOV_TYPE_BREDR: - err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + if (lmp_bredr_capable(hdev)) + err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); + else + err = -ENOTSUPP; break; case DISCOV_TYPE_LE: - err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, + if (lmp_host_le_capable(hdev)) + err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + else + err = -ENOTSUPP; break; case DISCOV_TYPE_INTERLEAVED: -- cgit v1.2.3 From 75fb0e324daa48ec458fb5c2960eb07b80cfad9d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 1 Mar 2012 21:35:55 +0200 Subject: Bluetooth: Fix init sequence for some CSR based controllers Some CSR controllers will generate a spontaneous reset during init and just eat up any pending command without sending a command complete for it. This patch solves the issue by just resending whatever was the last sent command. hci_send_cmd is not used since we need to bypass all other commands in the send queue. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index db484a8e7364..d3ddc0ba9cd4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -82,8 +82,28 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) /* If this is the init phase check if the completed command matches * the last init command, and if not just return. */ - if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) + if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) { + struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; + struct sk_buff *skb; + + /* Some CSR based controllers generate a spontaneous + * reset complete event during init and any pending + * command will never be completed. In such a case we + * need to resend whatever was the last sent + * command. + */ + + if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET) + return; + + skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC); + if (skb) { + skb_queue_head(&hdev->cmd_q, skb); + queue_work(hdev->workqueue, &hdev->cmd_work); + } + return; + } if (hdev->req_status == HCI_REQ_PEND) { hdev->req_result = result; -- cgit v1.2.3 From bdb6d97154b7b7e98867e9b71bae0f47ec70b1d7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 06:13:32 +0200 Subject: Bluetooth: mgmt: Refactor hci_dev lookup for commands Almost all mgmt commands need to lookup a struct hci_dev based on the index received within the mgmt headers. It makese therefore sense to look this up in a single place and then just pass the hdev pointer to each command handler function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 764 ++++++++++++++++++--------------------------------- 1 file changed, 274 insertions(+), 490 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3fcccad75453..cc9fb64def90 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -624,17 +624,11 @@ static void mgmt_init_hdev(struct hci_dev *hdev) } } -static int read_controller_info(struct sock *sk, u16 index) +static int read_controller_info(struct sock *sk, struct hci_dev *hdev) { struct mgmt_rp_read_info rp; - struct hci_dev *hdev; - - BT_DBG("sock %p hci%u", sk, index); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_READ_INFO, - MGMT_STATUS_INVALID_PARAMS); + BT_DBG("sock %p %s", sk, hdev->name); hci_dev_lock(hdev); @@ -658,9 +652,9 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name)); hci_dev_unlock(hdev); - hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp)); + return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp, + sizeof(rp)); } static void mgmt_pending_free(struct pending_cmd *cmd) @@ -744,22 +738,17 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) sizeof(settings)); } -static int set_powered(struct sock *sk, u16 index, void *data, u16 len) +static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_POWERED, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_POWERED, + return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -780,7 +769,7 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_POWERED, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, MGMT_STATUS_BUSY); goto failed; } @@ -800,7 +789,6 @@ static int set_powered(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } @@ -843,48 +831,43 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip) return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); } -static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) +static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_set_discoverable *cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; u16 timeout; u8 scan; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); timeout = get_unaligned_le16(&cp->timeout); if (!cp->val && timeout > 0) - return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev) && timeout > 0) { - err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_BUSY); goto failed; } if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_REJECTED); goto failed; } @@ -945,28 +928,21 @@ static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) +static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; u8 scan; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -996,7 +972,7 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_BUSY); goto failed; } @@ -1028,26 +1004,19 @@ static int set_connectable(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) +static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1065,28 +1034,21 @@ static int set_pairable(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) +static int set_link_security(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; u8 val; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1111,7 +1073,7 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, MGMT_STATUS_BUSY); goto failed; } @@ -1137,34 +1099,26 @@ static int set_link_security(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) +static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; u8 val; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_SSP, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_SSP, + return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, MGMT_STATUS_NOT_SUPPORTED); goto failed; } @@ -1190,7 +1144,8 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_BUSY); goto failed; } @@ -1213,70 +1168,49 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_hs(struct sock *sk, u16 index, void *data, u16 len) +static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; - struct hci_dev *hdev; - int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_HS, + return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_HS, - MGMT_STATUS_INVALID_PARAMS); - - if (!enable_hs) { - err = cmd_status(sk, index, MGMT_OP_SET_HS, - MGMT_STATUS_NOT_SUPPORTED); - goto failed; - } + if (!enable_hs) + return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, + MGMT_STATUS_NOT_SUPPORTED); if (cp->val) set_bit(HCI_HS_ENABLED, &hdev->dev_flags); else clear_bit(HCI_HS_ENABLED, &hdev->dev_flags); - err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); - -failed: - hci_dev_put(hdev); - return err; + return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); } -static int set_le(struct sock *sk, u16 index, void *data, u16 len) +static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; struct hci_cp_write_le_host_supported hci_cp; struct pending_cmd *cmd; - struct hci_dev *hdev; int err; u8 val, enabled; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_LE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_LE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!enable_le || !(hdev->features[4] & LMP_LE)) { - err = cmd_status(sk, index, MGMT_OP_SET_LE, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); goto unlock; } @@ -1303,7 +1237,8 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { - err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, + MGMT_STATUS_BUSY); goto unlock; } @@ -1329,33 +1264,26 @@ static int set_le(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) +static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_add_uuid *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; struct bt_uuid *uuid; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_ADD_UUID, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_ADD_UUID, + return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_ADD_UUID, + err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, MGMT_STATUS_BUSY); goto failed; } @@ -1380,7 +1308,7 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) goto failed; if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); goto failed; } @@ -1393,8 +1321,6 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } @@ -1412,30 +1338,25 @@ static bool enable_service_cache(struct hci_dev *hdev) return false; } -static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) +static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_remove_uuid *cp = data; struct pending_cmd *cmd; struct list_head *p, *n; - struct hci_dev *hdev; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int err, found; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, MGMT_STATUS_BUSY); goto unlock; } @@ -1444,8 +1365,8 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) err = hci_uuids_clear(hdev); if (enable_service_cache(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, - hdev->dev_class, 3); + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, + 0, hdev->dev_class, 3); goto unlock; } @@ -1465,7 +1386,7 @@ static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) } if (found == 0) { - err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, + err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -1480,7 +1401,7 @@ update_class: goto unlock; if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, hdev->dev_class, 3); goto unlock; } @@ -1493,33 +1414,26 @@ update_class: unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) +static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_set_dev_class *cp = data; struct pending_cmd *cmd; int err; - BT_DBG("request for hci%u", index); + BT_DBG("request for %s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, + err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, MGMT_STATUS_BUSY); goto unlock; } @@ -1528,7 +1442,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) hdev->minor_class = cp->minor; if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, hdev->dev_class, 3); goto unlock; } @@ -1545,7 +1459,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) goto unlock; if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { - err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, hdev->dev_class, 3); goto unlock; } @@ -1558,20 +1472,18 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) +static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; int i; if (len < sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); key_count = get_unaligned_le16(&cp->key_count); @@ -1581,16 +1493,11 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) if (expected_len != len) { BT_ERR("load_link_keys: expected %u bytes, got %u bytes", len, expected_len); - return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); } - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); - - BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, + BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, key_count); hci_dev_lock(hdev); @@ -1611,10 +1518,9 @@ static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len) key->type, key->pin_len); } - cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); + cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); hci_dev_unlock(hdev); - hci_dev_put(hdev); return 0; } @@ -1631,9 +1537,9 @@ static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, skip_sk); } -static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) +static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_unpair_device *cp = data; struct mgmt_rp_unpair_device rp; struct hci_cp_disconnect dc; @@ -1642,12 +1548,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) int err; if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1657,7 +1558,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); goto unlock; @@ -1669,7 +1570,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) err = hci_remove_ltk(hdev, &cp->addr.bdaddr); if (err < 0) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp)); goto unlock; @@ -1687,7 +1588,7 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) } if (!conn) { - err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0, &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; @@ -1708,14 +1609,12 @@ static int unpair_device(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int disconnect(struct sock *sk, u16 index, void *data, u16 len) +static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_disconnect *cp = data; struct hci_cp_disconnect dc; struct pending_cmd *cmd; @@ -1725,24 +1624,19 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_DISCONNECT, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_DISCONNECT, + return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { - err = cmd_status(sk, index, MGMT_OP_DISCONNECT, + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { - err = cmd_status(sk, index, MGMT_OP_DISCONNECT, + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_BUSY); goto failed; } @@ -1753,7 +1647,7 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); if (!conn) { - err = cmd_status(sk, index, MGMT_OP_DISCONNECT, + err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1773,8 +1667,6 @@ static int disconnect(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } @@ -1797,10 +1689,9 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } -static int get_connections(struct sock *sk, u16 index) +static int get_connections(struct sock *sk, struct hci_dev *hdev) { struct mgmt_rp_get_connections *rp; - struct hci_dev *hdev; struct hci_conn *c; size_t rp_len; int err; @@ -1808,15 +1699,10 @@ static int get_connections(struct sock *sk, u16 index) BT_DBG(""); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, + err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -1850,18 +1736,18 @@ static int get_connections(struct sock *sk, u16 index) /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); - err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len); + err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp, + rp_len); kfree(rp); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int send_pin_code_neg_reply(struct sock *sk, u16 index, - struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp) +static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, + struct mgmt_cp_pin_code_neg_reply *cp) { struct pending_cmd *cmd; int err; @@ -1879,9 +1765,9 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, return err; } -static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) +static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct hci_conn *conn; struct mgmt_cp_pin_code_reply *cp = data; struct hci_cp_pin_code_reply reply; @@ -1891,25 +1777,20 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); if (!conn) { - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1921,9 +1802,9 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) BT_ERR("PIN code is not 16 bytes long"); - err = send_pin_code_neg_reply(sk, index, hdev, &ncp); + err = send_pin_code_neg_reply(sk, hdev, &ncp); if (err >= 0) - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); goto failed; @@ -1945,59 +1826,45 @@ static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len) +static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_pin_code_neg_reply *cp = data; int err; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, + err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_NOT_POWERED); goto failed; } - err = send_pin_code_neg_reply(sk, index, hdev, cp); + err = send_pin_code_neg_reply(sk, hdev, cp); failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) +static int set_io_capability(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_set_io_capability *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, + return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -2008,9 +1875,9 @@ static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len) hdev->io_capability); hci_dev_unlock(hdev); - hci_dev_put(hdev); - return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0); + return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, + NULL, 0); } static inline struct pending_cmd *find_pairing(struct hci_conn *conn) @@ -2065,9 +1932,9 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, mgmt_status(status)); } -static int pair_device(struct sock *sk, u16 index, void *data, u16 len) +static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_pair_device *cp = data; struct mgmt_rp_pair_device rp; struct pending_cmd *cmd; @@ -2078,18 +1945,13 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -2112,7 +1974,7 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_CONNECT_FAILED, &rp, sizeof(rp)); goto unlock; @@ -2120,7 +1982,7 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) if (conn->connect_cfm_cb) { hci_conn_put(conn); - err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, + err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } @@ -2149,16 +2011,13 @@ static int pair_device(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int cancel_pair_device(struct sock *sk, u16 index, +static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, unsigned char *data, u16 len) { struct mgmt_addr_info *addr = (void *) data; - struct hci_dev *hdev; struct pending_cmd *cmd; struct hci_conn *conn; int err; @@ -2166,25 +2025,20 @@ static int cancel_pair_device(struct sock *sk, u16 index, BT_DBG(""); if (len != sizeof(*addr)) - return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_NOT_POWERED); goto unlock; } cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); if (!cmd) { - err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -2192,40 +2046,33 @@ static int cancel_pair_device(struct sock *sk, u16 index, conn = cmd->user_data; if (bacmp(&addr->bdaddr, &conn->dst) != 0) { - err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, + err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); goto unlock; } pairing_complete(cmd, MGMT_STATUS_CANCELLED); - err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr, - sizeof(*addr)); + err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0, + addr, sizeof(*addr)); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, - u8 type, u16 mgmt_op, u16 hci_op, - __le32 passkey) +static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type, u16 mgmt_op, + u16 hci_op, __le32 passkey) { struct pending_cmd *cmd; - struct hci_dev *hdev; struct hci_conn *conn; int err; - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, mgmt_op, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); + err = cmd_status(sk, hdev->id, mgmt_op, + MGMT_STATUS_NOT_POWERED); goto done; } @@ -2235,7 +2082,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); if (!conn) { - err = cmd_status(sk, index, mgmt_op, + err = cmd_status(sk, hdev->id, mgmt_op, MGMT_STATUS_NOT_CONNECTED); goto done; } @@ -2245,10 +2092,10 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, err = smp_user_confirm_reply(conn, mgmt_op, passkey); if (!err) - err = cmd_status(sk, index, mgmt_op, + err = cmd_status(sk, hdev->id, mgmt_op, MGMT_STATUS_SUCCESS); else - err = cmd_status(sk, index, mgmt_op, + err = cmd_status(sk, hdev->id, mgmt_op, MGMT_STATUS_FAILED); goto done; @@ -2275,92 +2122,86 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, done: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) +static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_confirm_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_CONFIRM_REPLY, HCI_OP_USER_CONFIRM_REPLY, 0); } -static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, - u16 len) +static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_confirm_neg_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_CONFIRM_NEG_REPLY, HCI_OP_USER_CONFIRM_NEG_REPLY, 0); } -static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) +static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_passkey_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY, + return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY, EINVAL); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_REPLY, HCI_OP_USER_PASSKEY_REPLY, cp->passkey); } -static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, - u16 len) +static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { struct mgmt_cp_user_passkey_neg_reply *cp = data; BT_DBG(""); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY, - EINVAL); + return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY, + EINVAL); - return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type, + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_NEG_REPLY, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } -static int set_local_name(struct sock *sk, u16 index, void *data, +static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_set_local_name *mgmt_cp = data; struct hci_cp_write_local_name hci_cp; - struct hci_dev *hdev; struct pending_cmd *cmd; int err; BT_DBG(""); if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, + return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -2396,40 +2237,32 @@ static int set_local_name(struct sock *sk, u16 index, void *data, failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int read_local_oob_data(struct sock *sk, u16 index) +static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev) { - struct hci_dev *hdev; struct pending_cmd *cmd; int err; - BT_DBG("hci%u", index); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); + BT_DBG("%s", hdev->name); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_NOT_POWERED); goto unlock; } if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { - err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_NOT_SUPPORTED); goto unlock; } if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { - err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_BUSY); goto unlock; } @@ -2446,35 +2279,26 @@ static int read_local_oob_data(struct sock *sk, u16 index) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int add_remote_oob_data(struct sock *sk, u16 index, void *data, - u16 len) +static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_add_remote_oob_data *cp = data; u8 status; int err; - BT_DBG("hci%u ", index); + BT_DBG("%s ", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_NOT_POWERED, &cp->addr, sizeof(cp->addr)); goto unlock; @@ -2487,42 +2311,34 @@ static int add_remote_oob_data(struct sock *sk, u16 index, void *data, else status = 0; - err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status, + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int remove_remote_oob_data(struct sock *sk, u16 index, +static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_remove_remote_oob_data *cp = data; u8 status; int err; - BT_DBG("hci%u ", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->addr, sizeof(cp->addr)); + err = cmd_complete(sk, hdev->id, + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, + &cp->addr, sizeof(cp->addr)); goto unlock; } @@ -2532,13 +2348,11 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, else status = 0; - err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status, - &cp->addr, sizeof(cp->addr)); + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + status, &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } @@ -2559,36 +2373,30 @@ int mgmt_interleaved_discovery(struct hci_dev *hdev) return err; } -static int start_discovery(struct sock *sk, u16 index, +static int start_discovery(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; struct pending_cmd *cmd; - struct hci_dev *hdev; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, + return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_NOT_POWERED); goto failed; } if (hdev->discovery.state != DISCOVERY_STOPPED) { - err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_BUSY); goto failed; } @@ -2635,42 +2443,35 @@ static int start_discovery(struct sock *sk, u16 index, failed: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) +static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_stop_discovery *mgmt_cp = data; - struct hci_dev *hdev; struct pending_cmd *cmd; struct hci_cp_remote_name_req_cancel cp; struct inquiry_entry *e; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, + return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_REJECTED, &mgmt_cp->type, sizeof(mgmt_cp->type)); goto unlock; } if (hdev->discovery.type != mgmt_cp->type) { - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, + err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type, sizeof(mgmt_cp->type)); goto unlock; @@ -2694,7 +2495,7 @@ static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); if (!e) { mgmt_pending_remove(cmd); - err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0, &mgmt_cp->type, sizeof(mgmt_cp->type)); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; @@ -2710,41 +2511,34 @@ static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len) unlock: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) +static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_confirm_name *cp = data; struct inquiry_entry *e; - struct hci_dev *hdev; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); 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); + return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, + err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, MGMT_STATUS_FAILED); goto failed; } e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { - err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); + err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS); goto failed; } @@ -2760,29 +2554,22 @@ static int confirm_name(struct sock *sk, u16 index, void *data, u16 len) failed: hci_dev_unlock(hdev); - return err; } -static int block_device(struct sock *sk, u16 index, void *data, u16 len) +static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_block_device *cp = data; u8 status; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2791,34 +2578,27 @@ static int block_device(struct sock *sk, u16 index, void *data, u16 len) else status = 0; - err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status, + err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) +static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { - struct hci_dev *hdev; struct mgmt_cp_unblock_device *cp = data; u8 status; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, + return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS, - &cp->addr, sizeof(cp->addr)); - hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2827,41 +2607,35 @@ static int unblock_device(struct sock *sk, u16 index, void *data, u16 len) else status = 0; - err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status, + err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); - hci_dev_put(hdev); return err; } -static int set_fast_connectable(struct sock *sk, u16 index, - void *data, u16 len) +static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) { - struct hci_dev *hdev; struct mgmt_mode *cp = data; struct hci_cp_write_page_scan_activity acp; u8 type; int err; - BT_DBG("hci%u", index); + BT_DBG("%s", hdev->name); if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); if (!hdev_is_powered(hdev)) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_NOT_POWERED); if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) - return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_REJECTED); + return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_REJECTED); hci_dev_lock(hdev); @@ -2878,37 +2652,34 @@ static int set_fast_connectable(struct sock *sk, u16 index, err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), &acp); if (err < 0) { - err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_FAILED); goto done; } err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); if (err < 0) { - err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, + MGMT_STATUS_FAILED); goto done; } - err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0, + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0, NULL, 0); done: hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; } -static int load_long_term_keys(struct sock *sk, u16 index, +static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, void *cp_data, u16 len) { - struct hci_dev *hdev; struct mgmt_cp_load_long_term_keys *cp = cp_data; u16 key_count, expected_len; int i; if (len < sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, EINVAL); key_count = get_unaligned_le16(&cp->key_count); @@ -2918,16 +2689,11 @@ static int load_long_term_keys(struct sock *sk, u16 index, if (expected_len != len) { BT_ERR("load_keys: expected %u bytes, got %u bytes", len, expected_len); - return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, EINVAL); } - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, - ENODEV); - - BT_DBG("hci%u key_count %u", index, key_count); + BT_DBG("%s key_count %u", hdev->name, key_count); hci_dev_lock(hdev); @@ -2948,7 +2714,6 @@ static int load_long_term_keys(struct sock *sk, u16 index, } hci_dev_unlock(hdev); - hci_dev_put(hdev); return 0; } @@ -2959,6 +2724,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) u8 *cp; struct mgmt_hdr *hdr; u16 opcode, index, len; + struct hci_dev *hdev = NULL; int err; BT_DBG("got %zu bytes", msglen); @@ -2985,6 +2751,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } + if (opcode < MGMT_OP_READ_INFO) { + if (index != MGMT_INDEX_NONE) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; + } + } else { + hdev = hci_dev_get(index); + if (!hdev) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; + } + } + cp = buf + sizeof(*hdr); switch (opcode) { @@ -2998,112 +2779,112 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = read_index_list(sk); break; case MGMT_OP_READ_INFO: - err = read_controller_info(sk, index); + err = read_controller_info(sk, hdev); break; case MGMT_OP_SET_POWERED: - err = set_powered(sk, index, cp, len); + err = set_powered(sk, hdev, cp, len); break; case MGMT_OP_SET_DISCOVERABLE: - err = set_discoverable(sk, index, cp, len); + err = set_discoverable(sk, hdev, cp, len); break; case MGMT_OP_SET_CONNECTABLE: - err = set_connectable(sk, index, cp, len); + err = set_connectable(sk, hdev, cp, len); break; case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, index, cp, len); + err = set_fast_connectable(sk, hdev, cp, len); break; case MGMT_OP_SET_PAIRABLE: - err = set_pairable(sk, index, cp, len); + err = set_pairable(sk, hdev, cp, len); break; case MGMT_OP_SET_LINK_SECURITY: - err = set_link_security(sk, index, cp, len); + err = set_link_security(sk, hdev, cp, len); break; case MGMT_OP_SET_SSP: - err = set_ssp(sk, index, cp, len); + err = set_ssp(sk, hdev, cp, len); break; case MGMT_OP_SET_HS: - err = set_hs(sk, index, cp, len); + err = set_hs(sk, hdev, cp, len); break; case MGMT_OP_SET_LE: - err = set_le(sk, index, cp, len); + err = set_le(sk, hdev, cp, len); break; case MGMT_OP_ADD_UUID: - err = add_uuid(sk, index, cp, len); + err = add_uuid(sk, hdev, cp, len); break; case MGMT_OP_REMOVE_UUID: - err = remove_uuid(sk, index, cp, len); + err = remove_uuid(sk, hdev, cp, len); break; case MGMT_OP_SET_DEV_CLASS: - err = set_dev_class(sk, index, cp, len); + err = set_dev_class(sk, hdev, cp, len); break; case MGMT_OP_LOAD_LINK_KEYS: - err = load_link_keys(sk, index, cp, len); + err = load_link_keys(sk, hdev, cp, len); break; case MGMT_OP_DISCONNECT: - err = disconnect(sk, index, cp, len); + err = disconnect(sk, hdev, cp, len); break; case MGMT_OP_GET_CONNECTIONS: - err = get_connections(sk, index); + err = get_connections(sk, hdev); break; case MGMT_OP_PIN_CODE_REPLY: - err = pin_code_reply(sk, index, cp, len); + err = pin_code_reply(sk, hdev, cp, len); break; case MGMT_OP_PIN_CODE_NEG_REPLY: - err = pin_code_neg_reply(sk, index, cp, len); + err = pin_code_neg_reply(sk, hdev, cp, len); break; case MGMT_OP_SET_IO_CAPABILITY: - err = set_io_capability(sk, index, cp, len); + err = set_io_capability(sk, hdev, cp, len); break; case MGMT_OP_PAIR_DEVICE: - err = pair_device(sk, index, cp, len); + err = pair_device(sk, hdev, cp, len); break; case MGMT_OP_CANCEL_PAIR_DEVICE: - err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len); + err = cancel_pair_device(sk, hdev, buf + sizeof(*hdr), len); break; case MGMT_OP_UNPAIR_DEVICE: - err = unpair_device(sk, index, cp, len); + err = unpair_device(sk, hdev, cp, len); break; case MGMT_OP_USER_CONFIRM_REPLY: - err = user_confirm_reply(sk, index, cp, len); + err = user_confirm_reply(sk, hdev, cp, len); break; case MGMT_OP_USER_CONFIRM_NEG_REPLY: - err = user_confirm_neg_reply(sk, index, cp, len); + err = user_confirm_neg_reply(sk, hdev, cp, len); break; case MGMT_OP_USER_PASSKEY_REPLY: - err = user_passkey_reply(sk, index, cp, len); + err = user_passkey_reply(sk, hdev, cp, len); break; case MGMT_OP_USER_PASSKEY_NEG_REPLY: - err = user_passkey_neg_reply(sk, index, cp, len); + err = user_passkey_neg_reply(sk, hdev, cp, len); break; case MGMT_OP_SET_LOCAL_NAME: - err = set_local_name(sk, index, cp, len); + err = set_local_name(sk, hdev, cp, len); break; case MGMT_OP_READ_LOCAL_OOB_DATA: - err = read_local_oob_data(sk, index); + err = read_local_oob_data(sk, hdev); break; case MGMT_OP_ADD_REMOTE_OOB_DATA: - err = add_remote_oob_data(sk, index, cp, len); + err = add_remote_oob_data(sk, hdev, cp, len); break; case MGMT_OP_REMOVE_REMOTE_OOB_DATA: - err = remove_remote_oob_data(sk, index, cp, len); + err = remove_remote_oob_data(sk, hdev, cp, len); break; case MGMT_OP_START_DISCOVERY: - err = start_discovery(sk, index, cp, len); + err = start_discovery(sk, hdev, cp, len); break; case MGMT_OP_STOP_DISCOVERY: - err = stop_discovery(sk, index, cp, len); + err = stop_discovery(sk, hdev, cp, len); break; case MGMT_OP_CONFIRM_NAME: - err = confirm_name(sk, index, cp, len); + err = confirm_name(sk, hdev, cp, len); break; case MGMT_OP_BLOCK_DEVICE: - err = block_device(sk, index, cp, len); + err = block_device(sk, hdev, cp, len); break; case MGMT_OP_UNBLOCK_DEVICE: - err = unblock_device(sk, index, cp, len); + err = unblock_device(sk, hdev, cp, len); break; case MGMT_OP_LOAD_LONG_TERM_KEYS: - err = load_long_term_keys(sk, index, cp, len); + err = load_long_term_keys(sk, hdev, cp, len); break; default: BT_DBG("Unknown op %u", opcode); @@ -3118,6 +2899,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = msglen; done: + if (hdev) + hci_dev_put(hdev); + kfree(buf); return err; } -- cgit v1.2.3 From 6a919082e9b82a0de20f1248a33f3b3f005cebaf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 06:17:26 +0200 Subject: Bluetooth: mgmt: Initialize HCI_MGMT flag for any command The read_controller_info is typically the first command that user space sends when taking a controller into use. This is also the reason why this command has been used as the trigger to set the HCI_MGMT flag. However, when not running the user-space daemon and using command line tools it is possible that read_controller_info is not the first controller specific command. This patch moves the HCI_MGMT initialization to a generic place where it will be set for whatever happens to be the first mgmt command targetting a specific controller. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cc9fb64def90..cf8c8403571e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -610,8 +610,11 @@ static void service_cache_off(struct work_struct *work) hci_dev_unlock(hdev); } -static void mgmt_init_hdev(struct hci_dev *hdev) +static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) { + if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + return; + if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); @@ -632,9 +635,6 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev) hci_dev_lock(hdev); - if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) - mgmt_init_hdev(hdev); - memset(&rp, 0, sizeof(rp)); bacpy(&rp.bdaddr, &hdev->bdaddr); @@ -2764,6 +2764,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) MGMT_STATUS_INVALID_PARAMS); goto done; } + + mgmt_init_hdev(sk, hdev); } cp = buf + sizeof(*hdr); -- cgit v1.2.3 From 0f4e68cf6e70fc219f219799c799a8a3e3c13100 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Feb 2012 17:18:30 +0200 Subject: Bluetooth: mgmt: Move command handlers into a table By moving the command handlers into a table (the index being equal to the opcode) the lookup is made a bit more efficient. Having a struct to describe each handler also paves the way to add more meta-data for each handler, e.g. the minimum message size for the command and allow handling of common tasks like this in a centralized place. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 219 +++++++++++++++++++-------------------------------- 1 file changed, 79 insertions(+), 140 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cf8c8403571e..88a342a12593 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -267,7 +267,8 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, return err; } -static int read_version(struct sock *sk) +static int read_version(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_version rp; @@ -280,7 +281,8 @@ static int read_version(struct sock *sk) sizeof(rp)); } -static int read_commands(struct sock *sk) +static int read_commands(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_commands *rp; u16 num_commands = ARRAY_SIZE(mgmt_commands); @@ -313,7 +315,8 @@ static int read_commands(struct sock *sk) return err; } -static int read_index_list(struct sock *sk) +static int read_index_list(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_index_list *rp; struct list_head *p; @@ -627,7 +630,8 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) } } -static int read_controller_info(struct sock *sk, struct hci_dev *hdev) +static int read_controller_info(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_read_info rp; @@ -1689,7 +1693,8 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } -static int get_connections(struct sock *sk, struct hci_dev *hdev) +static int get_connections(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct mgmt_rp_get_connections *rp; struct hci_conn *c; @@ -2015,9 +2020,9 @@ unlock: } static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, - unsigned char *data, u16 len) + void *data, u16 len) { - struct mgmt_addr_info *addr = (void *) data; + struct mgmt_addr_info *addr = data; struct pending_cmd *cmd; struct hci_conn *conn; int err; @@ -2240,7 +2245,8 @@ failed: return err; } -static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev) +static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) { struct pending_cmd *cmd; int err; @@ -2718,6 +2724,53 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, return 0; } +struct mgmt_handler { + int (*func) (struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len); +} mgmt_handlers[] = { + { NULL }, /* 0x0000 (no command) */ + { read_version, }, + { read_commands, }, + { read_index_list, }, + { read_controller_info, }, + { set_powered, }, + { set_discoverable, }, + { set_connectable, }, + { set_fast_connectable, }, + { set_pairable, }, + { set_link_security, }, + { set_ssp, }, + { set_hs, }, + { set_le, }, + { set_dev_class, }, + { set_local_name, }, + { add_uuid, }, + { remove_uuid, }, + { load_link_keys, }, + { load_long_term_keys, }, + { disconnect, }, + { get_connections, }, + { pin_code_reply, }, + { pin_code_neg_reply, }, + { set_io_capability, }, + { pair_device, }, + { cancel_pair_device, }, + { unpair_device, }, + { user_confirm_reply, }, + { user_confirm_neg_reply, }, + { user_passkey_reply, }, + { user_passkey_neg_reply, }, + { read_local_oob_data, }, + { add_remote_oob_data, }, + { remove_remote_oob_data, }, + { start_discovery, }, + { stop_discovery, }, + { confirm_name, }, + { block_device, }, + { unblock_device, }, +}; + + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { void *buf; @@ -2751,150 +2804,36 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } - if (opcode < MGMT_OP_READ_INFO) { - if (index != MGMT_INDEX_NONE) { - err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); - goto done; - } - } else { + if (index != MGMT_INDEX_NONE) { hdev = hci_dev_get(index); if (!hdev) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto done; } - - mgmt_init_hdev(sk, hdev); } - cp = buf + sizeof(*hdr); - - switch (opcode) { - case MGMT_OP_READ_VERSION: - err = read_version(sk); - break; - case MGMT_OP_READ_COMMANDS: - err = read_commands(sk); - break; - case MGMT_OP_READ_INDEX_LIST: - err = read_index_list(sk); - break; - case MGMT_OP_READ_INFO: - err = read_controller_info(sk, hdev); - break; - case MGMT_OP_SET_POWERED: - err = set_powered(sk, hdev, cp, len); - break; - case MGMT_OP_SET_DISCOVERABLE: - err = set_discoverable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_CONNECTABLE: - err = set_connectable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_PAIRABLE: - err = set_pairable(sk, hdev, cp, len); - break; - case MGMT_OP_SET_LINK_SECURITY: - err = set_link_security(sk, hdev, cp, len); - break; - case MGMT_OP_SET_SSP: - err = set_ssp(sk, hdev, cp, len); - break; - case MGMT_OP_SET_HS: - err = set_hs(sk, hdev, cp, len); - break; - case MGMT_OP_SET_LE: - err = set_le(sk, hdev, cp, len); - break; - case MGMT_OP_ADD_UUID: - err = add_uuid(sk, hdev, cp, len); - break; - case MGMT_OP_REMOVE_UUID: - err = remove_uuid(sk, hdev, cp, len); - break; - case MGMT_OP_SET_DEV_CLASS: - err = set_dev_class(sk, hdev, cp, len); - break; - case MGMT_OP_LOAD_LINK_KEYS: - err = load_link_keys(sk, hdev, cp, len); - break; - case MGMT_OP_DISCONNECT: - err = disconnect(sk, hdev, cp, len); - break; - case MGMT_OP_GET_CONNECTIONS: - err = get_connections(sk, hdev); - break; - case MGMT_OP_PIN_CODE_REPLY: - err = pin_code_reply(sk, hdev, cp, len); - break; - case MGMT_OP_PIN_CODE_NEG_REPLY: - err = pin_code_neg_reply(sk, hdev, cp, len); - break; - case MGMT_OP_SET_IO_CAPABILITY: - err = set_io_capability(sk, hdev, cp, len); - break; - case MGMT_OP_PAIR_DEVICE: - err = pair_device(sk, hdev, cp, len); - break; - case MGMT_OP_CANCEL_PAIR_DEVICE: - err = cancel_pair_device(sk, hdev, buf + sizeof(*hdr), len); - break; - case MGMT_OP_UNPAIR_DEVICE: - err = unpair_device(sk, hdev, cp, len); - break; - case MGMT_OP_USER_CONFIRM_REPLY: - err = user_confirm_reply(sk, hdev, cp, len); - break; - case MGMT_OP_USER_CONFIRM_NEG_REPLY: - err = user_confirm_neg_reply(sk, hdev, cp, len); - break; - case MGMT_OP_USER_PASSKEY_REPLY: - err = user_passkey_reply(sk, hdev, cp, len); - break; - case MGMT_OP_USER_PASSKEY_NEG_REPLY: - err = user_passkey_neg_reply(sk, hdev, cp, len); - break; - case MGMT_OP_SET_LOCAL_NAME: - err = set_local_name(sk, hdev, cp, len); - break; - case MGMT_OP_READ_LOCAL_OOB_DATA: - err = read_local_oob_data(sk, hdev); - break; - case MGMT_OP_ADD_REMOTE_OOB_DATA: - err = add_remote_oob_data(sk, hdev, cp, len); - break; - case MGMT_OP_REMOVE_REMOTE_OOB_DATA: - err = remove_remote_oob_data(sk, hdev, cp, len); - break; - case MGMT_OP_START_DISCOVERY: - err = start_discovery(sk, hdev, cp, len); - break; - case MGMT_OP_STOP_DISCOVERY: - err = stop_discovery(sk, hdev, cp, len); - break; - case MGMT_OP_CONFIRM_NAME: - err = confirm_name(sk, hdev, cp, len); - break; - case MGMT_OP_BLOCK_DEVICE: - err = block_device(sk, hdev, cp, len); - break; - case MGMT_OP_UNBLOCK_DEVICE: - err = unblock_device(sk, hdev, cp, len); - break; - case MGMT_OP_LOAD_LONG_TERM_KEYS: - err = load_long_term_keys(sk, hdev, cp, len); - break; - default: + if (opcode >= ARRAY_SIZE(mgmt_handlers) || + mgmt_handlers[opcode].func == NULL) { BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, MGMT_STATUS_UNKNOWN_COMMAND); - break; + goto done; + } + + if ((hdev && opcode < MGMT_OP_READ_INFO) || + (!hdev && opcode >= MGMT_OP_READ_INFO)) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; } + if (hdev) + mgmt_init_hdev(sk, hdev); + + cp = buf + sizeof(*hdr); + + err = mgmt_handlers[opcode].func(sk, hdev, cp, len); if (err < 0) goto done; -- cgit v1.2.3 From be22b54e8711734f4cb93ac31723b955fe9dbbe0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 1 Mar 2012 22:24:41 +0200 Subject: Bluetooth: mgmt: Centralize message length checks This patch moves the command length information into the command handler table allowing the removal of length checks from the handler functions and doing the check in a single place before calling the handler function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 220 ++++++++++++--------------------------------------- 1 file changed, 52 insertions(+), 168 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 88a342a12593..7bd7d57a8775 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -751,10 +751,6 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { @@ -846,10 +842,6 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); - timeout = get_unaligned_le16(&cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, @@ -945,10 +937,6 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1019,10 +1007,6 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (cp->val) @@ -1051,10 +1035,6 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1115,10 +1095,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { @@ -1181,10 +1157,6 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, - MGMT_STATUS_INVALID_PARAMS); - if (!enable_hs) return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, MGMT_STATUS_NOT_SUPPORTED); @@ -1207,10 +1179,6 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!enable_le || !(hdev->features[4] & LMP_LE)) { @@ -1280,10 +1248,6 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { @@ -1353,10 +1317,6 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { @@ -1430,10 +1390,6 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { @@ -1486,10 +1442,6 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 key_count, expected_len; int i; - if (len < sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); - key_count = get_unaligned_le16(&cp->key_count); expected_len = sizeof(*cp) + key_count * @@ -1551,10 +1503,6 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_conn *conn; int err; - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); memset(&rp, 0, sizeof(rp)); @@ -1627,10 +1575,6 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { @@ -1781,10 +1725,6 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1842,10 +1782,6 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -1868,10 +1804,6 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; @@ -1949,10 +1881,6 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2029,10 +1957,6 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*addr)) - return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2153,10 +2077,6 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY, - MGMT_STATUS_INVALID_PARAMS); - return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_CONFIRM_NEG_REPLY, HCI_OP_USER_CONFIRM_NEG_REPLY, 0); @@ -2169,10 +2089,6 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY, - EINVAL); - return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_REPLY, HCI_OP_USER_PASSKEY_REPLY, @@ -2186,10 +2102,6 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, BT_DBG(""); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY, - EINVAL); - return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, MGMT_OP_USER_PASSKEY_NEG_REPLY, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); @@ -2205,10 +2117,6 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); - if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); memcpy(hdev->short_name, mgmt_cp->short_name, @@ -2297,10 +2205,6 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s ", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2334,10 +2238,6 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2388,10 +2288,6 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { @@ -2463,10 +2359,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*mgmt_cp)) - return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { @@ -2529,10 +2421,6 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { @@ -2572,10 +2460,6 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2601,10 +2485,6 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, - MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); @@ -2631,10 +2511,6 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (len != sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_INVALID_PARAMS); - if (!hdev_is_powered(hdev)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_NOT_POWERED); @@ -2684,10 +2560,6 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, u16 key_count, expected_len; int i; - if (len < sizeof(*cp)) - return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, - EINVAL); - key_count = get_unaligned_le16(&cp->key_count); expected_len = sizeof(*cp) + key_count * @@ -2727,47 +2599,49 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); + bool var_len; + size_t data_len; } mgmt_handlers[] = { { NULL }, /* 0x0000 (no command) */ - { read_version, }, - { read_commands, }, - { read_index_list, }, - { read_controller_info, }, - { set_powered, }, - { set_discoverable, }, - { set_connectable, }, - { set_fast_connectable, }, - { set_pairable, }, - { set_link_security, }, - { set_ssp, }, - { set_hs, }, - { set_le, }, - { set_dev_class, }, - { set_local_name, }, - { add_uuid, }, - { remove_uuid, }, - { load_link_keys, }, - { load_long_term_keys, }, - { disconnect, }, - { get_connections, }, - { pin_code_reply, }, - { pin_code_neg_reply, }, - { set_io_capability, }, - { pair_device, }, - { cancel_pair_device, }, - { unpair_device, }, - { user_confirm_reply, }, - { user_confirm_neg_reply, }, - { user_passkey_reply, }, - { user_passkey_neg_reply, }, - { read_local_oob_data, }, - { add_remote_oob_data, }, - { remove_remote_oob_data, }, - { start_discovery, }, - { stop_discovery, }, - { confirm_name, }, - { block_device, }, - { unblock_device, }, + { read_version, false, MGMT_READ_VERSION_SIZE }, + { read_commands, false, MGMT_READ_COMMANDS_SIZE }, + { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE }, + { read_controller_info, false, MGMT_READ_INFO_SIZE }, + { set_powered, false, MGMT_SETTING_SIZE }, + { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, + { set_connectable, false, MGMT_SETTING_SIZE }, + { set_fast_connectable, false, MGMT_SETTING_SIZE }, + { set_pairable, false, MGMT_SETTING_SIZE }, + { set_link_security, false, MGMT_SETTING_SIZE }, + { set_ssp, false, MGMT_SETTING_SIZE }, + { set_hs, false, MGMT_SETTING_SIZE }, + { set_le, false, MGMT_SETTING_SIZE }, + { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE }, + { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE }, + { add_uuid, false, MGMT_ADD_UUID_SIZE }, + { remove_uuid, false, MGMT_REMOVE_UUID_SIZE }, + { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE }, + { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE }, + { disconnect, false, MGMT_DISCONNECT_SIZE }, + { get_connections, false, MGMT_GET_CONNECTIONS_SIZE }, + { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE }, + { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE }, + { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE }, + { pair_device, false, MGMT_PAIR_DEVICE_SIZE }, + { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE }, + { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE }, + { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE }, + { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE }, + { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE }, + { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE }, + { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE }, + { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, + { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE }, + { start_discovery, false, MGMT_START_DISCOVERY_SIZE }, + { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE }, + { confirm_name, false, MGMT_CONFIRM_NAME_SIZE }, + { block_device, false, MGMT_BLOCK_DEVICE_SIZE }, + { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE }, }; @@ -2778,6 +2652,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) struct mgmt_hdr *hdr; u16 opcode, index, len; struct hci_dev *hdev = NULL; + struct mgmt_handler *handler; int err; BT_DBG("got %zu bytes", msglen); @@ -2828,12 +2703,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } + handler = &mgmt_handlers[opcode]; + + if ((handler->var_len && len < handler->data_len) || + (!handler->var_len && len != handler->data_len)) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_PARAMS); + goto done; + } + if (hdev) mgmt_init_hdev(sk, hdev); cp = buf + sizeof(*hdr); - err = mgmt_handlers[opcode].func(sk, hdev, cp, len); + err = handler->func(sk, hdev, cp, len); if (err < 0) goto done; -- cgit v1.2.3 From ba13ccd9b911e043c0f11e60cbb72bd4de194205 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 1 Mar 2012 14:25:33 -0800 Subject: Bluetooth: Update L2CAP timeout constants to use msecs_to_jiffies The L2CAP timeout constants are always used in form of jiffies. So just include the conversion from msecs in the define itself. This has the advantage of making the code where the timeout is used more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 10 +++++----- net/bluetooth/l2cap_core.c | 18 ++++++------------ net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 12 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3732a4849f2e..e4669d0230c5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -45,11 +45,11 @@ #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF -#define L2CAP_DISC_TIMEOUT (100) -#define L2CAP_DISC_REJ_TIMEOUT (5000) /* 5 seconds */ -#define L2CAP_ENC_TIMEOUT (5000) /* 5 seconds */ -#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ -#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ +#define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100) +#define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000) +#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000) +#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000) +#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000) /* L2CAP socket address */ struct sockaddr_l2 { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bc8d558b01f6..0b1aabff8649 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -700,8 +700,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - schedule_delayed_work(&conn->info_timer, - msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ, sizeof(req), &req); @@ -2741,8 +2740,7 @@ sendresp: conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - schedule_delayed_work(&conn->info_timer, - msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); + schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ, sizeof(info), &info); @@ -3028,8 +3026,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: l2cap_chan_set_err(chan, ECONNRESET); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); + __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -4539,8 +4536,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __clear_chan_timer(chan); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_ENC_TIMEOUT)); + __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); } else { @@ -4598,8 +4594,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) l2cap_send_conn_req(chan); } else { __clear_chan_timer(chan); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); } } else if (chan->state == BT_CONNECT2) { struct sock *sk = chan->sk; @@ -4622,8 +4617,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } } else { __l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, - msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 52c94c765779..3da56c5c1fc9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1039,7 +1039,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = l2cap_sock_destruct; - sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); + sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; sock_reset_flag(sk, SOCK_ZAPPED); -- cgit v1.2.3 From 17b02e625662906f370a3eb5e7495cf06ed7d4a4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 1 Mar 2012 14:32:37 -0800 Subject: Bluetooth: Update MGMT and SMP timeout constants to use msecs_to_jiffies The MGMT and SMP timeout constants are always used in form of jiffies. So just include the conversion from msecs in the define itself. This has the advantage of making the code where the timeout is used more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 5 ++--- net/bluetooth/smp.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7bd7d57a8775..40b3da3d5e62 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -116,7 +116,7 @@ static const u16 mgmt_events[] = { #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ #define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */ -#define SERVICE_CACHE_TIMEOUT (5 * 1000) +#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) #define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) @@ -1298,8 +1298,7 @@ static bool enable_service_cache(struct hci_dev *hdev) return false; if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { - schedule_delayed_work(&hdev->service_cache, - msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); + schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT); return true; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f6a6d8be3051..75937d73d8ae 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -29,7 +29,7 @@ #include #include -#define SMP_TIMEOUT 30000 /* 30 seconds */ +#define SMP_TIMEOUT msecs_to_jiffies(30000) static inline void swap128(u8 src[16], u8 dst[16]) { @@ -186,8 +186,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) hci_send_acl(conn->hchan, skb, 0); cancel_delayed_work_sync(&conn->security_timer); - schedule_delayed_work(&conn->security_timer, - msecs_to_jiffies(SMP_TIMEOUT)); + schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT); } static __u8 authreq_to_seclevel(__u8 authreq) -- cgit v1.2.3 From 9f8ce967caed427f78d00bb6b07d79cb040a88bd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 03:06:04 +0200 Subject: Bluetooth: Fix clearing of HCI_PENDING_CLASS flag When doing reset HCI_PENDING_CLASS is one of the flags that should be cleared (since it's used for a pending HCI command and a reset clear all pending commands). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index aee9556e1039..d6c41bbfe759 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -193,7 +193,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); /* Reset all non-persistent flags */ - hdev->dev_flags &= ~(BIT(HCI_LE_SCAN)); + hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS)); hdev->discovery.state = DISCOVERY_STOPPED; } -- cgit v1.2.3 From d4f68526e438dbb7d194b08499a96c733131ad72 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 03:07:07 +0200 Subject: Bluetooth: mgmt: Fix command status error code values Error codes in the command status should always be from the set of values defined for mgmt and never e.g. POSIX error codes. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 40b3da3d5e62..bd01e4a4784e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2745,7 +2745,7 @@ int mgmt_index_added(struct hci_dev *hdev) int mgmt_index_removed(struct hci_dev *hdev) { - u8 status = ENODEV; + u8 status = MGMT_STATUS_INVALID_PARAMS; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); @@ -2798,7 +2798,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) update_class(hdev); update_eir(hdev); } else { - u8 status = ENETDOWN; + u8 status = MGMT_STATUS_NOT_POWERED; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } -- cgit v1.2.3 From 5f15903279143eb640f9ba1c0e72b52fe9e9e2a6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 03:13:19 +0200 Subject: Bluetooth: mgmt: Add new error code for invalid index The index is part of the command header and not its parameters so it makes sense to distinguish this from the invalid parameters error. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index d33457d657c3..0ca3519e08bd 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -41,6 +41,7 @@ #define MGMT_STATUS_DISCONNECTED 0x0e #define MGMT_STATUS_NOT_POWERED 0x0f #define MGMT_STATUS_CANCELLED 0x10 +#define MGMT_STATUS_INVALID_INDEX 0x11 struct mgmt_hdr { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bd01e4a4784e..fa9a58964278 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2682,7 +2682,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) hdev = hci_dev_get(index); if (!hdev) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_INDEX); goto done; } } @@ -2698,7 +2698,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if ((hdev && opcode < MGMT_OP_READ_INFO) || (!hdev && opcode >= MGMT_OP_READ_INFO)) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_INDEX); goto done; } @@ -2745,7 +2745,7 @@ int mgmt_index_added(struct hci_dev *hdev) int mgmt_index_removed(struct hci_dev *hdev) { - u8 status = MGMT_STATUS_INVALID_PARAMS; + u8 status = MGMT_STATUS_INVALID_INDEX; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); -- cgit v1.2.3 From 4f87da80a5210e66fb47b0e839f4d05016986f78 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 19:55:56 +0200 Subject: Bluetooth: Remove HCI_PI_MGMT_INIT flag for sockets This flag is of no use right now and is in fact harmful in that it prevents the HCI_MGMT flag to be set for any controllers that may need it after the first one that bluetoothd takes into use (the flag is cleared for the first controller so any subsequent ones through the same bluetoothd mgmt socket never get the HCI_MGMT flag set). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ---- net/bluetooth/hci_sock.c | 1 - net/bluetooth/mgmt.c | 18 ++++++++---------- 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index facd7ed32b74..25cb0a15b579 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1034,16 +1034,12 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) -/* HCI socket flags */ -#define HCI_PI_MGMT_INIT 0 - struct hci_pinfo { struct bt_sock bt; struct hci_dev *hdev; struct hci_filter filter; __u32 cmsg_mask; unsigned short channel; - unsigned long flags; }; /* HCI security filter */ diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 8a814bca00d7..63afd234283e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -659,7 +659,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } - set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; case HCI_CHANNEL_MONITOR: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fa9a58964278..4b1efedc18c5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -615,19 +615,17 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) { - if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) return; - if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { - INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); - /* Non-mgmt controlled devices get this bit set - * implicitly so that pairing works for them, however - * for mgmt we require user-space to explicitly enable - * it - */ - clear_bit(HCI_PAIRABLE, &hdev->dev_flags); - } + /* Non-mgmt controlled devices get this bit set + * implicitly so that pairing works for them, however + * for mgmt we require user-space to explicitly enable + * it + */ + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, -- cgit v1.2.3 From 2b4bf3974249da74f4aef1e9180d4beaf6332515 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 3 Mar 2012 00:19:06 +0200 Subject: Bluetooth: mgmt: Fix updating local name when powering on When powering on we need to apply whatever name has been set through mgmt_set_local_name. The appropriate place for this is mgmt_powered() and not hci_setup() since this needs to be applied also if the HCI init sequence was already completed but the adapter was still "powered off" from a mgmt perspective due the the HCI_AUTO_OFF still being set. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 8 -------- net/bluetooth/mgmt.c | 22 ++++++++++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d6c41bbfe759..6a817daf095b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -552,14 +552,6 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (!test_bit(HCI_SETUP, &hdev->dev_flags) && - test_bit(HCI_MGMT, &hdev->dev_flags)) { - struct hci_cp_write_local_name cp; - - memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); - hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); - } - if (hdev->features[6] & LMP_SIMPLE_PAIR) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4b1efedc18c5..4ca009268afb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2104,11 +2104,19 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } +static int update_name(struct hci_dev *hdev, const char *name) +{ + struct hci_cp_write_local_name cp; + + memcpy(cp.name, name, sizeof(cp.name)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); +} + static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct mgmt_cp_set_local_name *mgmt_cp = data; - struct hci_cp_write_local_name hci_cp; + struct mgmt_cp_set_local_name *cp = data; struct pending_cmd *cmd; int err; @@ -2116,11 +2124,10 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - memcpy(hdev->short_name, mgmt_cp->short_name, - sizeof(hdev->short_name)); + memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name)); if (!hdev_is_powered(hdev)) { - memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name)); + memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name)); err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, data, len); @@ -2139,9 +2146,7 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); - err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), - &hci_cp); + err = update_name(hdev, cp->name); if (err < 0) mgmt_pending_remove(cmd); @@ -2794,6 +2799,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); update_class(hdev); + update_name(hdev, hdev->dev_name); update_eir(hdev); } else { u8 status = MGMT_STATUS_NOT_POWERED; -- cgit v1.2.3 From 74fe619ef96466d562a1a13e7cbab783624ec2f3 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 1 Mar 2012 18:19:57 -0300 Subject: Bluetooth: Don't force DISCOVERY_STOPPED state in inquiry_cache_flush We are not supposed to force DISCOVERY_STOPPED in inquiry_cache_flush because we may break the discovery state machine. For instance, during interleaved discovery, when we are about to start inquiry, the state machine forcibly goes to DISCOVERY_STOPPED while it should stay in DISCOVERY_FINDING state. This problem results in unexpected behaviors such as sending two mgmt_discovering events to userspace (when only one event is expected) and Stop Discovery failures. Signed-off-by: Andre Guedes Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d3ddc0ba9cd4..661d65fc487b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -413,7 +413,6 @@ static void inquiry_cache_flush(struct hci_dev *hdev) INIT_LIST_HEAD(&cache->unknown); INIT_LIST_HEAD(&cache->resolve); - cache->state = DISCOVERY_STOPPED; } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) -- cgit v1.2.3 From 04124681f104c1980024ff249a34a77a249fd2bc Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 8 Mar 2012 01:25:00 -0300 Subject: Bluetooth: fix conding style issues all over the tree Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btmrvl_debugfs.c | 23 +- include/net/bluetooth/hci_core.h | 67 +++-- net/bluetooth/hci_core.c | 49 ++-- net/bluetooth/hci_event.c | 110 ++++----- net/bluetooth/l2cap_core.c | 11 +- net/bluetooth/l2cap_sock.c | 3 +- net/bluetooth/mgmt.c | 489 ++++++++++++++++++------------------- net/bluetooth/smp.c | 30 +-- 8 files changed, 384 insertions(+), 398 deletions(-) (limited to 'net/bluetooth') diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 3497347e6dbb..6c20bbb54b71 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -401,28 +401,29 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - priv, &btmrvl_psmode_fops); + priv, &btmrvl_psmode_fops); dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, - priv, &btmrvl_pscmd_fops); + priv, &btmrvl_pscmd_fops); dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, - priv, &btmrvl_gpiogap_fops); + priv, &btmrvl_gpiogap_fops); dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, - priv, &btmrvl_hsmode_fops); + priv, &btmrvl_hsmode_fops); dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, - priv, &btmrvl_hscmd_fops); + priv, &btmrvl_hscmd_fops); dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, - priv, &btmrvl_hscfgcmd_fops); + priv, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); dbg->curpsmode = debugfs_create_file("curpsmode", 0444, - dbg->status_dir, priv, &btmrvl_curpsmode_fops); + dbg->status_dir, priv, + &btmrvl_curpsmode_fops); dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, - priv, &btmrvl_psstate_fops); + priv, &btmrvl_psstate_fops); dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, - priv, &btmrvl_hsstate_fops); + priv, &btmrvl_hsstate_fops); dbg->txdnldready = debugfs_create_file("txdnldready", 0444, - dbg->status_dir, priv, - &btmrvl_txdnldready_fops); + dbg->status_dir, priv, + &btmrvl_txdnldready_fops); } void btmrvl_debugfs_remove(struct hci_dev *hdev) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cbbf68a8510d..daefaac51131 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -398,16 +398,16 @@ static inline long inquiry_entry_age(struct inquiry_entry *e) } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr); + bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, - bdaddr_t *bdaddr); + bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, - bdaddr_t *bdaddr, - int state); + bdaddr_t *bdaddr, + int state); void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, - struct inquiry_entry *ie); + struct inquiry_entry *ie); bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known, bool *ssp); + bool name_known, bool *ssp); /* ----- HCI Connections ----- */ enum { @@ -669,13 +669,13 @@ int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, - bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], - u8 enc_size, u16 ediv, u8 rand[8]); + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv, + u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type); + u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); @@ -931,7 +931,7 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) } static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, - u8 data_len) + u8 data_len) { eir[eir_len++] = sizeof(type) + data_len; eir[eir_len++] = type; @@ -978,50 +978,49 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); int mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, - u8 persistent); + u8 persistent); int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u32 flags, u8 *name, - u8 name_len, u8 *dev_class); + u8 addr_type, u32 flags, u8 *name, u8 name_len, + u8 *dev_class); int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type); + u8 link_type, u8 addr_type); int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status); + u8 addr_type, u8 status); int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure); int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); + u8 status); int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status); + u8 status); int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, __le32 value, - u8 confirm_hint); + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint); int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type); + u8 link_type, u8 addr_type); int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status); + u8 link_type, u8 addr_type, u8 status); int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status); + u8 addr_type, u8 status); int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, - u8 status); + u8 status); 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); + u8 *randomizer, u8 status); int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, 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 cfm_name, u8 ssp, u8 *eir, - u16 eir_len); + u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, + u8 ssp, u8 *eir, u16 eir_len); int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, s8 rssi, u8 *name, u8 name_len); + u8 addr_type, s8 rssi, u8 *name, u8 name_len); int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); int mgmt_discovering(struct hci_dev *hdev, u8 discovering); @@ -1071,6 +1070,6 @@ void hci_le_ltk_neg_reply(struct hci_conn *conn); int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, - int timeout); + int timeout); #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 661d65fc487b..59ec99eb739b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -431,7 +431,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b } struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, - bdaddr_t *bdaddr) + bdaddr_t *bdaddr) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; @@ -447,8 +447,8 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, } struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, - bdaddr_t *bdaddr, - int state) + bdaddr_t *bdaddr, + int state) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; @@ -466,7 +466,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, } void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, - struct inquiry_entry *ie) + struct inquiry_entry *ie) { struct discovery_state *cache = &hdev->discovery; struct list_head *pos = &cache->resolve; @@ -485,7 +485,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, } bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known, bool *ssp) + bool name_known, bool *ssp) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; @@ -1264,7 +1264,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) EXPORT_SYMBOL(hci_find_ltk); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type) + u8 addr_type) { struct smp_ltk *k; @@ -1278,7 +1278,7 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, EXPORT_SYMBOL(hci_find_ltk_by_addr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, - bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; u8 old_key_type, persistent; @@ -1333,8 +1333,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], - u8 enc_size, u16 ediv, u8 rand[8]) + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 + ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; @@ -1413,7 +1413,7 @@ static void hci_cmd_timer(unsigned long arg) } struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, - bdaddr_t *bdaddr) + bdaddr_t *bdaddr) { struct oob_data *data; @@ -1453,7 +1453,7 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) } int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer) + u8 *randomizer) { struct oob_data *data; @@ -1476,8 +1476,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, return 0; } -struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr) +struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct bdaddr_list *b; @@ -1545,7 +1544,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) static void hci_clear_adv_cache(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - adv_work.work); + adv_work.work); hci_dev_lock(hdev); @@ -1588,11 +1587,7 @@ static inline int is_connectable_adv(u8 evt_type) } 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)) + 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 @@ -1639,7 +1634,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) } static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, - u16 window, int timeout) + u16 window, int timeout) { long timeo = msecs_to_jiffies(3000); struct le_scan_params param; @@ -1657,7 +1652,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, hci_req_lock(hdev); err = __hci_request(hdev, le_scan_param_req, (unsigned long) ¶m, - timeo); + timeo); if (!err) err = __hci_request(hdev, le_scan_enable_req, 0, timeo); @@ -1667,7 +1662,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, return err; schedule_delayed_work(&hdev->le_scan_disable, - msecs_to_jiffies(timeout)); + msecs_to_jiffies(timeout)); return 0; } @@ -1675,7 +1670,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, static void le_scan_disable_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - le_scan_disable.work); + le_scan_disable.work); struct hci_cp_le_set_scan_enable cp; BT_DBG("%s", hdev->name); @@ -1692,12 +1687,12 @@ static void le_scan_work(struct work_struct *work) BT_DBG("%s", hdev->name); - hci_do_le_scan(hdev, param->type, param->interval, - param->window, param->timeout); + hci_do_le_scan(hdev, param->type, param->interval, param->window, + param->timeout); } int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, - int timeout) + int timeout) { struct le_scan_params *param = &hdev->le_scan_params; @@ -2558,7 +2553,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev) skb = skb_dequeue(&chan->data_q); hci_conn_enter_active_mode(chan->conn, - bt_cb(skb)->force_active); + bt_cb(skb)->force_active); hci_send_frame(skb); hdev->acl_last_tx = jiffies; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6a817daf095b..badb7851d116 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -556,7 +556,7 @@ static void hci_setup(struct hci_dev *hdev) if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, - sizeof(mode), &mode); + sizeof(mode), &mode); } else { struct hci_cp_write_eir cp; @@ -577,14 +577,14 @@ static void hci_setup(struct hci_dev *hdev) struct hci_cp_read_local_ext_features cp; cp.page = 0x01; - hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), + &cp); } if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) { u8 enable = 1; - hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, - sizeof(enable), &enable); + hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable), + &enable); } } @@ -628,8 +628,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev) link_policy |= HCI_LP_PARK; link_policy = cpu_to_le16(link_policy); - hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, - sizeof(link_policy), &link_policy); + hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy), + &link_policy); } static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) @@ -717,8 +717,8 @@ static void hci_set_le_support(struct hci_dev *hdev) } if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE)) - hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), + &cp); } static void hci_cc_read_local_ext_features(struct hci_dev *hdev, @@ -976,8 +976,8 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, - 0, rp->status); + mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0, + rp->status); hci_dev_unlock(hdev); } @@ -993,8 +993,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, - ACL_LINK, 0, - rp->status); + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); } @@ -1009,7 +1008,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK, - 0, rp->status); + 0, rp->status); hci_dev_unlock(hdev); } @@ -1025,8 +1024,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr, - ACL_LINK, 0, - rp->status); + ACL_LINK, 0, rp->status); hci_dev_unlock(hdev); } @@ -1337,7 +1335,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, } static inline int hci_resolve_name(struct hci_dev *hdev, - struct inquiry_entry *e) + struct inquiry_entry *e) { struct hci_cp_remote_name_req cp; @@ -1369,14 +1367,14 @@ static bool hci_resolve_next_name(struct hci_dev *hdev) } static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, - bdaddr_t *bdaddr, u8 *name, u8 name_len) + bdaddr_t *bdaddr, u8 *name, u8 name_len) { struct discovery_state *discov = &hdev->discovery; struct inquiry_entry *e; if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, - name, name_len, conn->dev_class); + mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name, + name_len, conn->dev_class); if (discov->state == DISCOVERY_STOPPED) return; @@ -1393,7 +1391,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, list_del(&e->list); if (name) mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, - e->data.rssi, name, name_len); + e->data.rssi, name, name_len); } if (hci_resolve_next_name(hdev)) @@ -1602,7 +1600,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) mgmt_disconnect_failed(hdev, &conn->dst, conn->type, - conn->dst_type, status); + conn->dst_type, status); hci_dev_unlock(hdev); } @@ -1718,8 +1716,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, ssp, - NULL, 0); + info->dev_class, 0, !name_known, ssp, NULL, + 0); } hci_dev_unlock(hdev); @@ -1770,7 +1768,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s struct hci_cp_read_remote_features cp; cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, - sizeof(cp), &cp); + sizeof(cp), &cp); } /* Set packet type for incoming connection */ @@ -1778,14 +1776,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s struct hci_cp_change_conn_ptype cp; cp.handle = ev->handle; cp.pkt_type = cpu_to_le16(conn->pkt_type); - hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), + &cp); } } else { conn->state = BT_CLOSED; if (conn->type == ACL_LINK) mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, - conn->dst_type, ev->status); + conn->dst_type, ev->status); } if (conn->type == ACL_LINK) @@ -1850,8 +1848,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk else cp.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, - sizeof(cp), &cp); + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), + &cp); } else { struct hci_cp_accept_sync_conn_req cp; @@ -1865,7 +1863,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk cp.retrans_effort = 0xff; hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, - sizeof(cp), &cp); + sizeof(cp), &cp); } } else { /* Connection rejected */ @@ -1900,7 +1898,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff conn->dst_type, ev->status); else mgmt_device_disconnected(hdev, &conn->dst, conn->type, - conn->dst_type); + conn->dst_type); } if (ev->status == 0) { @@ -1935,7 +1933,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s } } else { mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, - ev->status); + ev->status); } clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); @@ -1996,7 +1994,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb if (ev->status == 0) hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name, - strnlen(ev->name, HCI_MAX_NAME_LENGTH)); + strnlen(ev->name, HCI_MAX_NAME_LENGTH)); else hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0); @@ -2111,8 +2109,8 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, 0, NULL, 0, - conn->dev_class); + conn->dst_type, 0, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -2524,7 +2522,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_ev_num_comp_blocks *ev = (void *) skb->data; int i; @@ -2816,10 +2814,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false, &ssp); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, - !name_known, ssp, NULL, 0); + info->dev_class, info->rssi, + !name_known, ssp, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); @@ -2834,10 +2832,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.rssi = info->rssi; data.ssp_mode = 0x00; name_known = hci_inquiry_cache_update(hdev, &data, - false, &ssp); + false, &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, - !name_known, ssp, NULL, 0); + info->dev_class, info->rssi, + !name_known, ssp, NULL, 0); } } @@ -2879,8 +2877,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &conn->dst, conn->type, - conn->dst_type, 0, NULL, 0, - conn->dev_class); + conn->dst_type, 0, NULL, 0, + conn->dev_class); if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; @@ -2986,17 +2984,16 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct if (test_bit(HCI_MGMT, &hdev->dev_flags)) name_known = eir_has_data_type(info->data, - sizeof(info->data), - EIR_NAME_COMPLETE); + sizeof(info->data), + EIR_NAME_COMPLETE); else name_known = true; name_known = hci_inquiry_cache_update(hdev, &data, name_known, - &ssp); + &ssp); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, - !name_known, ssp, info->data, - sizeof(info->data)); + info->dev_class, info->rssi, !name_known, + ssp, info->data, sizeof(info->data)); } hci_dev_unlock(hdev); @@ -3157,7 +3154,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, confirm: mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey, - confirm_hint); + confirm_hint); unlock: hci_dev_unlock(hdev); @@ -3198,7 +3195,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_ * the mgmt_auth_failed event */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0) mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, - ev->status); + ev->status); hci_conn_put(conn); @@ -3223,7 +3220,7 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ } static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; struct oob_data *data; @@ -3289,7 +3286,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, - conn->dst_type, 0, NULL, 0, NULL); + conn->dst_type, 0, NULL, 0, NULL); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); @@ -3320,8 +3317,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, - NULL, rssi, 0, 1, ev->data, - ev->length); + NULL, rssi, 0, 1, ev->data, ev->length); ptr += sizeof(*ev) + ev->length + 1; } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0b1aabff8649..3e450f4a3125 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1546,7 +1546,9 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); } -static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb) +static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, + struct msghdr *msg, int len, + int count, struct sk_buff *skb) { struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; @@ -1564,7 +1566,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr count = min_t(unsigned int, conn->mtu, len); *frag = chan->ops->alloc_skb(chan, count, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, + &err); if (!*frag) return err; @@ -1596,7 +1599,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return ERR_PTR(err); @@ -1631,7 +1634,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return ERR_PTR(err); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3da56c5c1fc9..c4fe583b0af6 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -926,7 +926,8 @@ static void l2cap_sock_state_change_cb(void *data, int state) } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, - unsigned long len, int nb, int *err) + unsigned long len, int nb, + int *err) { struct sock *sk = chan->sk; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4ca009268afb..7fcff8887131 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -234,7 +234,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) } static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, - void *rp, size_t rp_len) + void *rp, size_t rp_len) { struct sk_buff *skb; struct mgmt_hdr *hdr; @@ -267,8 +267,8 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, return err; } -static int read_version(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_read_version rp; @@ -278,11 +278,11 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, put_unaligned_le16(MGMT_REVISION, &rp.revision); return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, - sizeof(rp)); + sizeof(rp)); } -static int read_commands(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_read_commands *rp; u16 num_commands = ARRAY_SIZE(mgmt_commands); @@ -309,14 +309,14 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, put_unaligned_le16(mgmt_events[i], opcode); err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp, - rp_size); + rp_size); kfree(rp); return err; } -static int read_index_list(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_read_index_list *rp; struct list_head *p; @@ -355,7 +355,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, read_unlock(&hci_dev_list_lock); err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp, - rp_len); + rp_len); kfree(rp); @@ -600,7 +600,7 @@ static int update_class(struct hci_dev *hdev) static void service_cache_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - service_cache.work); + service_cache.work); if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) return; @@ -629,7 +629,7 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) + void *data, u16 data_len) { struct mgmt_rp_read_info rp; @@ -656,7 +656,7 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev, hci_dev_unlock(hdev); return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp, - sizeof(rp)); + sizeof(rp)); } static void mgmt_pending_free(struct pending_cmd *cmd) @@ -667,8 +667,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd) } static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, - struct hci_dev *hdev, - void *data, u16 len) + struct hci_dev *hdev, void *data, + u16 len) { struct pending_cmd *cmd; @@ -697,8 +697,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, } static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, - void (*cb)(struct pending_cmd *cmd, void *data), - void *data) + void (*cb)(struct pending_cmd *cmd, void *data), + void *data) { struct list_head *p, *n; @@ -737,11 +737,11 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) __le32 settings = cpu_to_le32(get_current_settings(hdev)); return cmd_complete(sk, hdev->id, opcode, 0, &settings, - sizeof(settings)); + sizeof(settings)); } static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; @@ -768,7 +768,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -790,8 +790,8 @@ failed: return err; } -static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, - u16 data_len, struct sock *skip_sk) +static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, + struct sock *skip_sk) { struct sk_buff *skb; struct mgmt_hdr *hdr; @@ -830,7 +830,7 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip) } static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_set_discoverable *cp = data; struct pending_cmd *cmd; @@ -843,26 +843,26 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, timeout = get_unaligned_le16(&cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (!hdev_is_powered(hdev) && timeout > 0) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, - MGMT_STATUS_REJECTED); + MGMT_STATUS_REJECTED); goto failed; } @@ -926,7 +926,7 @@ failed: } static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; @@ -963,7 +963,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -998,7 +998,7 @@ failed: } static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_mode *cp = data; int err; @@ -1023,8 +1023,8 @@ failed: return err; } -static int set_link_security(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_mode *cp = data; struct pending_cmd *cmd; @@ -1056,7 +1056,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -1097,7 +1097,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); goto failed; } @@ -1122,8 +1122,8 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_BUSY); goto failed; } @@ -1157,7 +1157,7 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!enable_hs) return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); if (cp->val) set_bit(HCI_HS_ENABLED, &hdev->dev_flags); @@ -1181,7 +1181,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!enable_le || !(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); goto unlock; } @@ -1208,7 +1208,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -1225,8 +1225,8 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } - err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(hci_cp), &hci_cp); + err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), + &hci_cp); if (err < 0) { mgmt_pending_remove(cmd); goto unlock; @@ -1250,7 +1250,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -1275,7 +1275,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto failed; } @@ -1318,7 +1318,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -1327,7 +1327,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, if (enable_service_cache(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, - 0, hdev->dev_class, 3); + 0, hdev->dev_class, 3); goto unlock; } @@ -1348,7 +1348,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, if (found == 0) { err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -1363,7 +1363,7 @@ update_class: if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto unlock; } @@ -1379,7 +1379,7 @@ unlock: } static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_set_dev_class *cp = data; struct pending_cmd *cmd; @@ -1391,7 +1391,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -1400,7 +1400,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto unlock; } @@ -1417,7 +1417,7 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, - hdev->dev_class, 3); + hdev->dev_class, 3); goto unlock; } @@ -1447,7 +1447,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, BT_ERR("load_link_keys: expected %u bytes, got %u bytes", len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); } BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, @@ -1468,7 +1468,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_link_key_info *key = &cp->keys[i]; hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val, - key->type, key->pin_len); + key->type, key->pin_len); } cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); @@ -1479,7 +1479,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, } static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, struct sock *skip_sk) + u8 addr_type, struct sock *skip_sk) { struct mgmt_ev_device_unpaired ev; @@ -1487,11 +1487,11 @@ static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr, ev.addr.type = addr_type; return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev), - skip_sk); + skip_sk); } static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_unpair_device *cp = data; struct mgmt_rp_unpair_device rp; @@ -1508,8 +1508,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_NOT_POWERED, - &rp, sizeof(rp)); + MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); goto unlock; } @@ -1520,8 +1519,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (err < 0) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, - MGMT_STATUS_NOT_PAIRED, - &rp, sizeof(rp)); + MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp)); goto unlock; } @@ -1538,13 +1536,13 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (!conn) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0, - &rp, sizeof(rp)); + &rp, sizeof(rp)); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk); goto unlock; } cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp, - sizeof(*cp)); + sizeof(*cp)); if (!cmd) { err = -ENOMEM; goto unlock; @@ -1562,7 +1560,7 @@ unlock: } static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_disconnect *cp = data; struct hci_cp_disconnect dc; @@ -1576,13 +1574,13 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -1593,7 +1591,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, if (!conn) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, - MGMT_STATUS_NOT_CONNECTED); + MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1634,8 +1632,8 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } -static int get_connections(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) +static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len) { struct mgmt_rp_get_connections *rp; struct hci_conn *c; @@ -1649,7 +1647,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -1683,7 +1681,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp, - rp_len); + rp_len); kfree(rp); @@ -1693,18 +1691,18 @@ unlock: } static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, - struct mgmt_cp_pin_code_neg_reply *cp) + struct mgmt_cp_pin_code_neg_reply *cp) { struct pending_cmd *cmd; int err; cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp, - sizeof(*cp)); + sizeof(*cp)); if (!cmd) return -ENOMEM; err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, - sizeof(cp->addr.bdaddr), &cp->addr.bdaddr); + sizeof(cp->addr.bdaddr), &cp->addr.bdaddr); if (err < 0) mgmt_pending_remove(cmd); @@ -1712,7 +1710,7 @@ static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, } static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct hci_conn *conn; struct mgmt_cp_pin_code_reply *cp = data; @@ -1726,14 +1724,14 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); if (!conn) { err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_NOT_CONNECTED); + MGMT_STATUS_NOT_CONNECTED); goto failed; } @@ -1747,7 +1745,7 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data, err = send_pin_code_neg_reply(sk, hdev, &ncp); if (err >= 0) err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto failed; } @@ -1772,7 +1770,7 @@ failed: } static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_pin_code_neg_reply *cp = data; int err; @@ -1783,7 +1781,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } @@ -1794,8 +1792,8 @@ failed: return err; } -static int set_io_capability(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_set_io_capability *cp = data; @@ -1810,8 +1808,8 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, hci_dev_unlock(hdev); - return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, - NULL, 0); + return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, + 0); } static inline struct pending_cmd *find_pairing(struct hci_conn *conn) @@ -1841,7 +1839,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status, - &rp, sizeof(rp)); + &rp, sizeof(rp)); /* So we don't get further callbacks for this connection */ conn->connect_cfm_cb = NULL; @@ -1867,7 +1865,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) } static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_pair_device *cp = data; struct mgmt_rp_pair_device rp; @@ -1882,7 +1880,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } @@ -1894,10 +1892,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->addr.type == MGMT_ADDR_BREDR) conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + auth_type); else conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + auth_type); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -1905,15 +1903,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (IS_ERR(conn)) { err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_CONNECT_FAILED, - &rp, sizeof(rp)); + MGMT_STATUS_CONNECT_FAILED, &rp, + sizeof(rp)); goto unlock; } if (conn->connect_cfm_cb) { hci_conn_put(conn); err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_BUSY, &rp, sizeof(rp)); + MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } @@ -1944,8 +1942,8 @@ unlock: return err; } -static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_addr_info *addr = data; struct pending_cmd *cmd; @@ -1958,14 +1956,14 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev); if (!cmd) { err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto unlock; } @@ -1973,22 +1971,22 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, if (bacmp(&addr->bdaddr, &conn->dst) != 0) { err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto unlock; } pairing_complete(cmd, MGMT_STATUS_CANCELLED); err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0, - addr, sizeof(*addr)); + addr, sizeof(*addr)); unlock: hci_dev_unlock(hdev); return err; } static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type, u16 mgmt_op, - u16 hci_op, __le32 passkey) + bdaddr_t *bdaddr, u8 type, u16 mgmt_op, + u16 hci_op, __le32 passkey) { struct pending_cmd *cmd; struct hci_conn *conn; @@ -1998,7 +1996,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto done; } @@ -2009,7 +2007,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, if (!conn) { err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_NOT_CONNECTED); + MGMT_STATUS_NOT_CONNECTED); goto done; } @@ -2019,10 +2017,10 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, if (!err) err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_SUCCESS); + MGMT_STATUS_SUCCESS); else err = cmd_status(sk, hdev->id, mgmt_op, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto done; } @@ -2051,8 +2049,8 @@ done: return err; } -static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_user_confirm_reply *cp = data; @@ -2060,48 +2058,47 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, if (len != sizeof(*cp)) return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_CONFIRM_REPLY, - HCI_OP_USER_CONFIRM_REPLY, 0); + MGMT_OP_USER_CONFIRM_REPLY, + HCI_OP_USER_CONFIRM_REPLY, 0); } static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_user_confirm_neg_reply *cp = data; BT_DBG(""); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_CONFIRM_NEG_REPLY, - HCI_OP_USER_CONFIRM_NEG_REPLY, 0); + MGMT_OP_USER_CONFIRM_NEG_REPLY, + HCI_OP_USER_CONFIRM_NEG_REPLY, 0); } -static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) { struct mgmt_cp_user_passkey_reply *cp = data; BT_DBG(""); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_PASSKEY_REPLY, - HCI_OP_USER_PASSKEY_REPLY, - cp->passkey); + MGMT_OP_USER_PASSKEY_REPLY, + HCI_OP_USER_PASSKEY_REPLY, cp->passkey); } static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_user_passkey_neg_reply *cp = data; BT_DBG(""); return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, - MGMT_OP_USER_PASSKEY_NEG_REPLY, - HCI_OP_USER_PASSKEY_NEG_REPLY, 0); + MGMT_OP_USER_PASSKEY_NEG_REPLY, + HCI_OP_USER_PASSKEY_NEG_REPLY, 0); } static int update_name(struct hci_dev *hdev, const char *name) @@ -2114,7 +2111,7 @@ static int update_name(struct hci_dev *hdev, const char *name) } static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_set_local_name *cp = data; struct pending_cmd *cmd; @@ -2130,12 +2127,12 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name)); err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, - data, len); + data, len); if (err < 0) goto failed; err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len, - sk); + sk); goto failed; } @@ -2156,7 +2153,7 @@ failed: } static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len) + void *data, u16 data_len) { struct pending_cmd *cmd; int err; @@ -2167,19 +2164,19 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto unlock; } if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_NOT_SUPPORTED); + MGMT_STATUS_NOT_SUPPORTED); goto unlock; } if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto unlock; } @@ -2199,7 +2196,7 @@ unlock: } static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_add_remote_oob_data *cp = data; u8 status; @@ -2211,20 +2208,20 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->addr, sizeof(cp->addr)); + MGMT_STATUS_NOT_POWERED, &cp->addr, + sizeof(cp->addr)); goto unlock; } err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, - cp->randomizer); + cp->randomizer); if (err < 0) status = MGMT_STATUS_FAILED; else status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, - &cp->addr, sizeof(cp->addr)); + &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); @@ -2244,9 +2241,9 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_complete(sk, hdev->id, - MGMT_OP_REMOVE_REMOTE_OOB_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->addr, sizeof(cp->addr)); + MGMT_OP_REMOVE_REMOTE_OOB_DATA, + MGMT_STATUS_NOT_POWERED, &cp->addr, + sizeof(cp->addr)); goto unlock; } @@ -2257,7 +2254,7 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, - status, &cp->addr, sizeof(cp->addr)); + status, &cp->addr, sizeof(cp->addr)); unlock: hci_dev_unlock(hdev); @@ -2282,7 +2279,7 @@ int mgmt_interleaved_discovery(struct hci_dev *hdev) } static int start_discovery(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; struct pending_cmd *cmd; @@ -2294,13 +2291,13 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); goto failed; } if (hdev->discovery.state != DISCOVERY_STOPPED) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_BUSY); + MGMT_STATUS_BUSY); goto failed; } @@ -2323,7 +2320,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, case DISCOV_TYPE_LE: if (lmp_host_le_capable(hdev)) err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, - LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); + LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); else err = -ENOTSUPP; break; @@ -2331,7 +2328,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, case DISCOV_TYPE_INTERLEAVED: if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, - LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE); + LE_SCAN_WIN, + LE_SCAN_TIMEOUT_BREDR_LE); else err = -ENOTSUPP; break; @@ -2351,7 +2349,7 @@ failed: } static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_stop_discovery *mgmt_cp = data; struct pending_cmd *cmd; @@ -2365,15 +2363,15 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, if (!hci_discovery_active(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_REJECTED, - &mgmt_cp->type, sizeof(mgmt_cp->type)); + MGMT_STATUS_REJECTED, &mgmt_cp->type, + sizeof(mgmt_cp->type)); goto unlock; } if (hdev->discovery.type != mgmt_cp->type) { err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, - MGMT_STATUS_INVALID_PARAMS, - &mgmt_cp->type, sizeof(mgmt_cp->type)); + MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type, + sizeof(mgmt_cp->type)); goto unlock; } @@ -2396,14 +2394,14 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, if (!e) { mgmt_pending_remove(cmd); err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0, - &mgmt_cp->type, sizeof(mgmt_cp->type)); + &mgmt_cp->type, sizeof(mgmt_cp->type)); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); goto unlock; } bacpy(&cp.bdaddr, &e->data.bdaddr); - err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, - sizeof(cp), &cp); + err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), + &cp); if (err < 0) mgmt_pending_remove(cmd); else @@ -2415,7 +2413,7 @@ unlock: } static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_confirm_name *cp = data; struct inquiry_entry *e; @@ -2427,14 +2425,14 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, if (!hci_discovery_active(hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto failed; } e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto failed; } @@ -2454,7 +2452,7 @@ failed: } static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_block_device *cp = data; u8 status; @@ -2471,7 +2469,7 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, - &cp->addr, sizeof(cp->addr)); + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); @@ -2479,7 +2477,7 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, } static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_unblock_device *cp = data; u8 status; @@ -2496,7 +2494,7 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, status = 0; err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, - &cp->addr, sizeof(cp->addr)); + &cp->addr, sizeof(cp->addr)); hci_dev_unlock(hdev); @@ -2504,7 +2502,7 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, } static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_mode *cp = data; struct hci_cp_write_page_scan_activity acp; @@ -2515,11 +2513,11 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_NOT_POWERED); + MGMT_STATUS_NOT_POWERED); if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_REJECTED); + MGMT_STATUS_REJECTED); hci_dev_lock(hdev); @@ -2533,30 +2531,30 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, acp.window = 0x0012; /* default 11.25 msec page scan window */ - err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, - sizeof(acp), &acp); + err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), + &acp); if (err < 0) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto done; } err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); if (err < 0) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_STATUS_FAILED); + MGMT_STATUS_FAILED); goto done; } err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0, - NULL, 0); + NULL, 0); done: hci_dev_unlock(hdev); return err; } static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, - void *cp_data, u16 len) + void *cp_data, u16 len) { struct mgmt_cp_load_long_term_keys *cp = cp_data; u16 key_count, expected_len; @@ -2570,7 +2568,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, BT_ERR("load_keys: expected %u bytes, got %u bytes", len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, - EINVAL); + EINVAL); } BT_DBG("%s key_count %u", hdev->name, key_count); @@ -2589,8 +2587,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, type = HCI_SMP_LTK_SLAVE; hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, - type, 0, key->authenticated, key->val, - key->enc_size, key->ediv, key->rand); + type, 0, key->authenticated, key->val, + key->enc_size, key->ediv, key->rand); } hci_dev_unlock(hdev); @@ -2599,8 +2597,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, } struct mgmt_handler { - int (*func) (struct sock *sk, struct hci_dev *hdev, - void *data, u16 data_len); + int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, + u16 data_len); bool var_len; size_t data_len; } mgmt_handlers[] = { @@ -2685,7 +2683,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) hdev = hci_dev_get(index); if (!hdev) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_INDEX); + MGMT_STATUS_INVALID_INDEX); goto done; } } @@ -2694,14 +2692,14 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) mgmt_handlers[opcode].func == NULL) { BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, - MGMT_STATUS_UNKNOWN_COMMAND); + MGMT_STATUS_UNKNOWN_COMMAND); goto done; } if ((hdev && opcode < MGMT_OP_READ_INFO) || (!hdev && opcode >= MGMT_OP_READ_INFO)) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_INDEX); + MGMT_STATUS_INVALID_INDEX); goto done; } @@ -2710,7 +2708,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if ((handler->var_len && len < handler->data_len) || (!handler->var_len && len != handler->data_len)) { err = cmd_status(sk, index, opcode, - MGMT_STATUS_INVALID_PARAMS); + MGMT_STATUS_INVALID_PARAMS); goto done; } @@ -2829,7 +2827,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) } mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, - &match); + &match); if (changed) err = new_settings(hdev, match.sk); @@ -2855,7 +2853,7 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) } mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, - &match); + &match); if (changed) err = new_settings(hdev, match.sk); @@ -2872,17 +2870,16 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) if (scan & SCAN_PAGE) mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); if (scan & SCAN_INQUIRY) mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); return 0; } -int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, - u8 persistent) +int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent) { struct mgmt_ev_new_link_key ev; @@ -2917,13 +2914,13 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) memcpy(ev.key.rand, key->rand, sizeof(key->rand)); memcpy(ev.key.val, key->val, sizeof(key->val)); - return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, - &ev, sizeof(ev), NULL); + return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), + NULL); } int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u32 flags, u8 *name, - u8 name_len, u8 *dev_class) + u8 addr_type, u32 flags, u8 *name, u8 name_len, + u8 *dev_class) { char buf[512]; struct mgmt_ev_device_connected *ev = (void *) buf; @@ -2936,16 +2933,16 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (name_len > 0) eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, - name, name_len); + name, name_len); if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) eir_len = eir_append_data(&ev->eir[eir_len], eir_len, - EIR_CLASS_OF_DEV, dev_class, 3); + EIR_CLASS_OF_DEV, dev_class, 3); put_unaligned_le16(eir_len, &ev->eir_len); return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, - sizeof(*ev) + eir_len, NULL); + sizeof(*ev) + eir_len, NULL); } static void disconnect_rsp(struct pending_cmd *cmd, void *data) @@ -2958,7 +2955,7 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) rp.addr.type = cp->addr.type; cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp, - sizeof(rp)); + sizeof(rp)); *sk = cmd->sk; sock_hold(*sk); @@ -2984,7 +2981,7 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) } int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type) + u8 link_type, u8 addr_type) { struct mgmt_addr_info ev; struct sock *sk = NULL; @@ -2996,19 +2993,19 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, ev.type = link_to_mgmt(link_type, addr_type); err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), - sk); + sk); if (sk) - sock_put(sk); + sock_put(sk); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, - hdev); + hdev); return err; } int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { struct mgmt_rp_disconnect rp; struct pending_cmd *cmd; @@ -3022,7 +3019,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, rp.addr.type = link_to_mgmt(link_type, addr_type); err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3032,7 +3029,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status) + u8 addr_type, u8 status) { struct mgmt_ev_connect_failed ev; @@ -3052,11 +3049,11 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), - NULL); + NULL); } int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 status) { struct pending_cmd *cmd; struct mgmt_rp_pin_code_reply rp; @@ -3070,7 +3067,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, rp.addr.type = MGMT_ADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3078,7 +3075,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 status) + u8 status) { struct pending_cmd *cmd; struct mgmt_rp_pin_code_reply rp; @@ -3092,7 +3089,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, rp.addr.type = MGMT_ADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - mgmt_status(status), &rp, sizeof(rp)); + mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3100,8 +3097,8 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, __le32 value, - u8 confirm_hint) + u8 link_type, u8 addr_type, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; @@ -3113,7 +3110,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, put_unaligned_le32(value, &ev.value); return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev), - NULL); + NULL); } int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -3127,7 +3124,7 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, ev.addr.type = link_to_mgmt(link_type, addr_type); return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), - NULL); + NULL); } static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -3145,7 +3142,7 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&rp.addr.bdaddr, bdaddr); rp.addr.type = link_to_mgmt(link_type, addr_type); err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status), - &rp, sizeof(rp)); + &rp, sizeof(rp)); mgmt_pending_remove(cmd); @@ -3153,35 +3150,35 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_CONFIRM_REPLY); + status, MGMT_OP_USER_CONFIRM_REPLY); } int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_CONFIRM_NEG_REPLY); + status, MGMT_OP_USER_CONFIRM_NEG_REPLY); } int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_PASSKEY_REPLY); + status, MGMT_OP_USER_PASSKEY_REPLY); } int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status) + u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_PASSKEY_NEG_REPLY); + status, MGMT_OP_USER_PASSKEY_NEG_REPLY); } int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status) + u8 addr_type, u8 status) { struct mgmt_ev_auth_failed ev; @@ -3201,7 +3198,7 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); return 0; } @@ -3214,7 +3211,7 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) } mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, - &match); + &match); if (changed) err = new_settings(hdev, match.sk); @@ -3249,11 +3246,11 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) u8 mgmt_err = mgmt_status(status); if (enable && test_and_clear_bit(HCI_SSP_ENABLED, - &hdev->dev_flags)) + &hdev->dev_flags)) err = new_settings(hdev, NULL); - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, - cmd_status_rsp, &mgmt_err); + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, + &mgmt_err); return err; } @@ -3287,7 +3284,7 @@ static void class_rsp(struct pending_cmd *cmd, void *data) struct cmd_lookup *match = data; cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status, - match->hdev->dev_class, 3); + match->hdev->dev_class, 3); list_del(&cmd->list); @@ -3300,7 +3297,7 @@ static void class_rsp(struct pending_cmd *cmd, void *data) } int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, - u8 status) + u8 status) { struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; int err = 0; @@ -3312,8 +3309,8 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match); if (!status) - err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, - dev_class, 3, NULL); + err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, + 3, NULL); if (match.sk) sock_put(match.sk); @@ -3347,19 +3344,19 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) if (status) { err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, - mgmt_status(status)); + mgmt_status(status)); goto failed; } err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev, - sizeof(ev)); + sizeof(ev)); if (err < 0) goto failed; send_event: if (changed) err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, - sizeof(ev), cmd ? cmd->sk : NULL); + sizeof(ev), cmd ? cmd->sk : NULL); update_eir(hdev); @@ -3370,7 +3367,7 @@ failed: } int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status) + u8 *randomizer, u8 status) { struct pending_cmd *cmd; int err; @@ -3382,9 +3379,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, return -ENOENT; if (status) { - err = cmd_status(cmd->sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_DATA, - mgmt_status(status)); + err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, + mgmt_status(status)); } else { struct mgmt_rp_read_local_oob_data rp; @@ -3392,8 +3388,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); err = cmd_complete(cmd->sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_DATA, - 0, &rp, sizeof(rp)); + MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp, + sizeof(rp)); } mgmt_pending_remove(cmd); @@ -3411,11 +3407,11 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) u8 mgmt_err = mgmt_status(status); if (enable && test_and_clear_bit(HCI_LE_ENABLED, - &hdev->dev_flags)) - err = new_settings(hdev, NULL); + &hdev->dev_flags)) + err = new_settings(hdev, NULL); mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, - cmd_status_rsp, &mgmt_err); + cmd_status_rsp, &mgmt_err); return err; } @@ -3440,8 +3436,8 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, 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 cfm_name, u8 ssp, u8 *eir, u16 eir_len) + u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 + ssp, u8 *eir, u16 eir_len) { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; @@ -3466,7 +3462,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV)) eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, - dev_class, 3); + dev_class, 3); put_unaligned_le16(eir_len, &ev->eir_len); @@ -3476,7 +3472,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, } int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, s8 rssi, u8 *name, u8 name_len) + u8 addr_type, s8 rssi, u8 *name, u8 name_len) { struct mgmt_ev_device_found *ev; char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2]; @@ -3491,12 +3487,12 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev->rssi = rssi; eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, - name_len); + name_len); put_unaligned_le16(eir_len, &ev->eir_len); return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, - sizeof(*ev) + eir_len, NULL); + sizeof(*ev) + eir_len, NULL); } int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) @@ -3514,7 +3510,7 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) type = hdev->discovery.type; err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), - &type, sizeof(type)); + &type, sizeof(type)); mgmt_pending_remove(cmd); return err; @@ -3530,8 +3526,7 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) return -ENOENT; err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status), - &hdev->discovery.type, - sizeof(hdev->discovery.type)); + &hdev->discovery.type, sizeof(hdev->discovery.type)); mgmt_pending_remove(cmd); return err; @@ -3552,8 +3547,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering) if (cmd != NULL) { u8 type = hdev->discovery.type; - cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, - &type, sizeof(type)); + cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type, + sizeof(type)); mgmt_pending_remove(cmd); } @@ -3575,7 +3570,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); + cmd ? cmd->sk : NULL); } int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) @@ -3589,7 +3584,7 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ev.addr.type = type; return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); + cmd ? cmd->sk : NULL); } module_param(enable_hs, bool, 0644); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 75937d73d8ae..8f56282c247d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -264,7 +264,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags); mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type, - hcon->dst_type, reason); + hcon->dst_type, reason); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { cancel_delayed_work_sync(&conn->security_timer); @@ -384,12 +384,11 @@ static void confirm_work(struct work_struct *work) if (conn->hcon->out) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0, - conn->src, conn->hcon->dst_type, conn->dst, - res); + conn->src, conn->hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, - conn->hcon->dst_type, conn->dst, 0, conn->src, - res); + conn->hcon->dst_type, conn->dst, 0, conn->src, + res); if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -424,12 +423,10 @@ static void random_work(struct work_struct *work) if (hcon->out) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0, - conn->src, hcon->dst_type, conn->dst, - res); + conn->src, hcon->dst_type, conn->dst, res); else ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, - hcon->dst_type, conn->dst, 0, conn->src, - res); + hcon->dst_type, conn->dst, 0, conn->src, res); if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -454,7 +451,7 @@ static void random_work(struct work_struct *work) swap128(key, stk); memset(stk + smp->enc_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); + SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) { reason = SMP_UNSPECIFIED; @@ -480,8 +477,8 @@ static void random_work(struct work_struct *work) SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type, - HCI_SMP_STK_SLAVE, 0, 0, stk, - smp->enc_key_size, ediv, rand); + HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size, + ediv, rand); } return; @@ -829,8 +826,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH); hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, - HCI_SMP_LTK, 1, authenticated, smp->tk, - smp->enc_key_size, rp->ediv, rp->rand); + HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size, + rp->ediv, rp->rand); smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); @@ -954,9 +951,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) authenticated = hcon->sec_level == BT_SECURITY_HIGH; hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, 1, authenticated, - enc.ltk, smp->enc_key_size, - ediv, ident.rand); + HCI_SMP_LTK_SLAVE, 1, authenticated, + enc.ltk, smp->enc_key_size, ediv, ident.rand); ident.ediv = cpu_to_le16(ediv); -- cgit v1.2.3 From e57d758ae8e8f00e80f233c823aeeef34bd92796 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 7 Mar 2012 20:20:14 +0200 Subject: Bluetooth: Fix using uninitialized variable + src/net/bluetooth/rfcomm/tty.c: warning: 'p' is used uninitialized in this function: => 218 + src/net/bluetooth/rfcomm/tty.c: warning: 'p' may be used uninitialized in this function: => 218 Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/tty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a2d4f5122a6a..c179734f143f 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -196,7 +196,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL); static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) { struct rfcomm_dev *dev, *entry; - struct list_head *head = &rfcomm_dev_list, *p; + struct list_head *head = &rfcomm_dev_list; int err = 0; BT_DBG("id %d channel %d", req->dev_id, req->channel); @@ -215,7 +215,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) break; dev->id++; - head = p; + head = &entry->list; } } else { dev->id = req->dev_id; @@ -229,7 +229,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) if (entry->id > dev->id - 1) break; - head = p; + head = &entry->list; } } -- cgit v1.2.3 From b3ff53ff006b7906c88adf9d0fccc06a8877fae1 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 5 Mar 2012 20:07:08 +0200 Subject: Bluetooth: Fix access to the STK generation methods matrix The major index of the table is actually the remote I/O capabilities, not the local ones. As a result, devices with different I/O capabilities could have used wrong or even unsupported generation methods. Signed-off-by: Ido Yariv CC: Brian Gix Acked-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8f56282c247d..9883d673873c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -310,7 +310,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, remote_io > SMP_IO_KEYBOARD_DISPLAY) method = JUST_WORKS; else - method = gen_method[local_io][remote_io]; + method = gen_method[remote_io][local_io]; /* If not bonding, don't ask user to confirm a Zero TK */ if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) -- cgit v1.2.3 From fdde0a26a218d95e2ea38c0838ab6f24040af14c Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 5 Mar 2012 20:09:38 +0200 Subject: Bluetooth: Set security level on incoming pairing request If a master would like to raise the security level, it will send a pairing request. While the pending security level is set on an incoming security request (from a slave), it is not set on a pairing request. As a result, the security level would not be raised on the slave in such case. Fix this by setting the pending security when receiving pairing requests according to the requested authorization. Signed-off-by: Ido Yariv Acked-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/smp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9883d673873c..deb119875fd9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -589,6 +589,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (req->auth_req & SMP_AUTH_BONDING) auth = req->auth_req; + conn->hcon->pending_sec_level = authreq_to_seclevel(auth); + build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); -- cgit v1.2.3