Hi,
Following patches add support for OOB in mgmt interface. New commands added:
- mgmt_read_local_oob_data - read local oob data from chip and forward it to
userspace
- mgmt_add/remote_oob_data - allow to store(or remove) remote oob data in
kernel, this data is then used by kernel while pairing, storing that data
in kernel minimize kernel<->userpace interaction on pairing (approche
suggested by Johan on irc)
There are also patches that do some clean up work on files touched by new mgmt
commands (mostly issues reported by checkpatch).
"Add optional data parameter to mgmt_ev_cmd_status event" and
"Use EIO code to report HCI error to userpace." touch some issues with mgmt
interface that I've mentioned already on irc:
- On error mgmt_read_local_oob_data needs to report to userspace on which
adapter request failed. In mgmt cmd_status is used to report errors so this
adds optional data[0] parameter to it. This may also be usefull for other
commands as well.
- It is not possible to distinguish in cmd status if error was from kernel
or from HCI. Since in mgmt only kernel sends HCI commands their errors
shouldn't be needed for userspace so report EIO to userspace on HCI error
(if HCI error is needed for debugging, logs can be added on kernel side)
When mgmt interface to OOB will be agreed, I'll prepare patches for bluetoothd
as well.
Comments are welcome.
BR,
Szymon Janc
on behalf of ST-Ericsson
Szymon Janc (10):
Bluetooth: Use #include <linux/uaccess.h> instead of <asm/uaccess.h>
Bluetooth: Clean up hci_sniff_subrate_evt function
Bluetooth: Add optional data parameter to mgmt_ev_cmd_status event
Bluetooth: Use EIO code to report HCI error to userpace
Bluetooth: Add read_local_oob_data management command
Bluetooth: Add add/remove_remote_oob_data management commands
Bluetooth: Fix code style issues and make checkpatch silent about
hci_core.h
Bluetooth: Fix code style issues and make checkpatch silent about
hci_core.c
Bluetooth: Fix code style issues, make checkpatch less noisy about
hci_event.c
Bluetooth: Log command and status parameters in command status event
include/net/bluetooth/hci.h | 24 ++++
include/net/bluetooth/hci_core.h | 109 ++++++++++------
include/net/bluetooth/mgmt.h | 29 ++++
net/bluetooth/hci_core.c | 106 +++++++++++++--
net/bluetooth/hci_event.c | 201 +++++++++++++++++++++--------
net/bluetooth/mgmt.c | 263 ++++++++++++++++++++++++++++++++------
6 files changed, 580 insertions(+), 152 deletions(-)
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/hci_event.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index abaa905..a7c7349 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2335,9 +2335,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.capability = conn->io_capability;
- cp.oob_data = 0;
cp.authentication = hci_get_auth_req(conn);
+ if ((conn->out == 1 || conn->remote_oob == 0x01) &&
+ hci_find_remote_oob_data(hdev, &conn->dst))
+ cp.oob_data = 0x01;
+ else
+ cp.oob_data = 0x00;
+
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
sizeof(cp), &cp);
} else {
--
1.7.0.4
This patch adds commands to add and remove remote OOB data to the managment
interface. Remote data is stored in kernel and used by corresponding HCI
commands and events (also implemented in this patch) when needed.
This patch does not enable OOB support.
Signed-off-by: Szymon Janc <[email protected]>
---
include/net/bluetooth/hci.h | 17 ++++++++
include/net/bluetooth/hci_core.h | 16 ++++++++
include/net/bluetooth/mgmt.h | 14 +++++++
net/bluetooth/hci_core.c | 76 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 34 +++++++++++++++++
net/bluetooth/mgmt.c | 73 ++++++++++++++++++++++++++++++++++++
6 files changed, 230 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7d1aef9..d1dd7dc 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -415,6 +415,18 @@ struct hci_cp_io_capability_reply {
__u8 authentication;
} __packed;
+#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
+struct hci_cp_remote_oob_data_reply {
+ bdaddr_t bdaddr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
+#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433
+struct hci_cp_remote_oob_data_neg_reply {
+ bdaddr_t bdaddr;
+} __packed;
+
#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434
struct hci_cp_io_capability_neg_reply {
bdaddr_t bdaddr;
@@ -943,6 +955,11 @@ struct hci_ev_io_capa_reply {
__u8 authentication;
} __packed;
+#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
+struct hci_ev_remote_oob_data_request {
+ bdaddr_t bdaddr;
+} __packed;
+
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete {
__u8 status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6be278b..2893288 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -82,6 +82,13 @@ struct link_key {
u8 pin_len;
};
+struct oob_data {
+ struct list_head list;
+ bdaddr_t bdaddr;
+ u8 hash[16];
+ u8 randomizer[16];
+};
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -169,6 +176,8 @@ struct hci_dev {
struct list_head link_keys;
+ struct list_head remote_oob_data;
+
struct hci_dev_stats stat;
struct sk_buff_head driver_init;
@@ -501,6 +510,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_remote_oob_data_clear(struct hci_dev *hdev);
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+ bdaddr_t *bdaddr);
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+ u8 *randomizer);
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
+
void hci_del_off_timer(struct hci_dev *hdev);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 18e2fb6..9bfd30f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -174,6 +174,20 @@ struct mgmt_rp_read_local_oob_data_failed {
__le16 index;
} __packed;
+#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0018
+struct mgmt_cp_add_remote_oob_data {
+ __le16 index;
+ bdaddr_t bdaddr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0019
+struct mgmt_cp_remove_remote_oob_data {
+ __le16 index;
+ bdaddr_t bdaddr;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b372fb8..a1d2263 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1077,6 +1077,79 @@ static void hci_cmd_timer(unsigned long arg)
tasklet_schedule(&hdev->cmd_task);
}
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+ bdaddr_t *bdaddr)
+{
+ struct list_head *p;
+
+ list_for_each(p, &hdev->remote_oob_data) {
+ struct oob_data *data;
+
+ data = list_entry(p, struct oob_data, list);
+
+ if (bacmp(bdaddr, &data->bdaddr) == 0)
+ return data;
+ }
+
+ return NULL;
+}
+
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct oob_data *data;
+
+ data = hci_find_remote_oob_data(hdev, bdaddr);
+ if (!data)
+ return -ENOENT;
+
+ BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+ list_del(&data->list);
+ kfree(data);
+
+ return 0;
+}
+
+int hci_remote_oob_data_clear(struct hci_dev *hdev)
+{
+ struct list_head *p, *n;
+
+ list_for_each_safe(p, n, &hdev->remote_oob_data) {
+ struct oob_data *data;
+
+ data = list_entry(p, struct oob_data, list);
+
+ list_del(p);
+ kfree(data);
+ }
+
+ return 0;
+}
+
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+ u8 *randomizer)
+{
+ struct oob_data *data;
+
+ data = hci_find_remote_oob_data(hdev, bdaddr);
+
+ if (!data) {
+ data = kmalloc(sizeof(*data), GFP_ATOMIC);
+ if (!data)
+ return -ENOMEM;
+
+ bacpy(&data->bdaddr, bdaddr);
+ list_add(&data->list, &hdev->remote_oob_data);
+ }
+
+ memcpy(data->hash, hash, 16);
+ memcpy(data->randomizer, randomizer, 16);
+
+ BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
+
+ return 0;
+}
+
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1141,6 +1214,8 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->link_keys);
+ INIT_LIST_HEAD(&hdev->remote_oob_data);
+
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1220,6 +1295,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev);
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
+ hci_remote_oob_data_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0c351d9..abaa905 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2409,6 +2409,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
hci_dev_unlock(hdev);
}
+static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+ struct oob_data *data;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
+ if (data) {
+ struct hci_cp_remote_oob_data_reply cp;
+
+ bacpy(&cp.bdaddr, &ev->bdaddr);
+ memcpy(cp.hash, data->hash, 16);
+ memcpy(cp.randomizer, data->randomizer, 16);
+
+ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
+ &cp);
+ } else {
+ struct hci_cp_remote_oob_data_neg_reply cp;
+
+ bacpy(&cp.bdaddr, &ev->bdaddr);
+ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
+ &cp);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -2605,6 +2636,9 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_EV_LE_META:
hci_le_meta_evt(hdev, skb);
+
+ case HCI_EV_REMOTE_OOB_DATA_REQUEST:
+ hci_remote_oob_data_request_evt(hdev, skb);
break;
default:
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2847934..571cbcf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1112,6 +1112,73 @@ unlock:
return err;
}
+static int add_remote_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_add_remote_oob_data *cp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+
+ BT_DBG("hci%u ", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, ENODEV, NULL,
+ 0);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
+ cp->randomizer);
+ if (err < 0)
+ err = cmd_status(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, -err, NULL,
+ 0);
+ else
+ err = cmd_complete(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, &dev_id,
+ sizeof(dev_id));
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int remove_remote_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_remove_remote_oob_data *cp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+
+ BT_DBG("hci%u ", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ENODEV,
+ NULL, 0);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+ if (err < 0)
+ err = cmd_status(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, -err, NULL,
+ 0);
+ else
+ err = cmd_complete(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, &dev_id,
+ sizeof(dev_id));
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -1200,6 +1267,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_READ_LOCAL_OOB_DATA:
err = read_local_oob_data(sk, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_ADD_REMOTE_OOB_DATA:
+ err = add_remote_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
+ case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
+ err = remove_remote_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, opcode, 0x01, NULL, 0);
--
1.7.0.4
It is not possible to distinguish in cmd_status if error was from kernel or
from HCI (because HCI status codes and kernel error codes overlaps). Since
in mgmt only kernel sends HCI commands HCI errors shouldn't be needed for
userspace at all so report EIO to userspace on HCI error.
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/mgmt.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index aee1da6..dee82fe 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1372,8 +1372,7 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status, NULL,
- 0);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, EIO, NULL, 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
bdaddr, sizeof(*bdaddr));
@@ -1394,8 +1393,8 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status,
- NULL, 0);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, EIO, NULL,
+ 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
bdaddr, sizeof(*bdaddr));
--
1.7.0.4
Hi,
On Thu, Feb 17, 2011 at 03:23:10PM +0100, ext Szymon Janc wrote:
> Hi,
>
> > On Thu, Feb 17, 2011 at 02:16:35PM +0100, ext Szymon Janc wrote:
> > > Signed-off-by: Szymon Janc <[email protected]>
> > > ---
> > > net/bluetooth/mgmt.c | 7 +++----
> > > 1 files changed, 3 insertions(+), 4 deletions(-)
> >
> > Some kind of explanation why EIO is better than status would be nice.
>
> As I've mentioned in cover letter:
Cover letters does not end up to git log. Proper description helps debugging
later a much if we can easily determine why this was needed and what was the
motivation for this patch.
> It is not possible to distinguish in cmd status if error was from kernel
> or from HCI. Since in mgmt only kernel sends HCI commands their errors
> shouldn't be needed for userspace so report EIO to userspace on HCI error
> (if HCI error is needed for debugging, logs can be added on kernel side)
>
> HCI status codes and kernel error codes overlaps i.e. one can't distinguish
> if error was ENOMEM or HCI Command Disallowed as both have value 12.
>
> For userspace is should be enough to just know that HCI failed, not why.
> (in fact, currently userspace is not able to determine error too...)
This sounds reasonable to me.
--
Ville
Hi Szymon,
* Szymon Janc <[email protected]> [2011-02-17 16:44:23 +0100]:
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> net/bluetooth/hci_event.c | 18 ++++++++++--------
> 1 files changed, 10 insertions(+), 8 deletions(-)
Applied, thanks.
--
Gustavo F. Padovan
http://profusion.mobi
Hi Szymon,
* Szymon Janc <[email protected]> [2011-02-17 16:46:47 +0100]:
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> net/bluetooth/hci_core.c | 7 +++----
> 1 files changed, 3 insertions(+), 4 deletions(-)
Applied also. Thanks.
--
Gustavo F. Padovan
http://profusion.mobi
Hi Szymon,
* Szymon Janc <[email protected]> [2011-02-17 16:42:00 +0100]:
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 58 +++++++++++++++++++-------------------
> 1 files changed, 29 insertions(+), 29 deletions(-)
It is now applied. Thanks.
--
Gustavo F. Padovan
http://profusion.mobi
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/hci_core.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0f5bbb0..a1d2263 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -124,7 +124,7 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
/* Execute request and wait for completion. */
static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+ unsigned long opt, __u32 timeout)
{
DECLARE_WAITQUEUE(wait, current);
int err = 0;
@@ -166,7 +166,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
}
static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+ unsigned long opt, __u32 timeout)
{
int ret;
@@ -465,7 +465,7 @@ int hci_inquiry(void __user *arg)
/* cache_dump can't sleep. Therefore we allocate temp buffer and then
* copy it to the user space.
*/
- buf = kmalloc(sizeof(struct inquiry_info) *max_rsp, GFP_KERNEL);
+ buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto done;
@@ -534,7 +534,6 @@ int hci_dev_open(__u16 dev)
set_bit(HCI_INIT, &hdev->flags);
hdev->init_last_cmd = 0;
- //__hci_request(hdev, hci_reset_req, 0, HZ);
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/hci_event.c | 18 ++++++++++--------
1 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b39c9bb..a7c7349 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -949,7 +949,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
}
static int hci_outgoing_auth_needed(struct hci_dev *hdev,
- struct hci_conn *conn)
+ struct hci_conn *conn)
{
if (conn->state != BT_CONFIG || !conn->out)
return 0;
@@ -1304,7 +1304,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
- if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
+ if ((mask & HCI_LM_ACCEPT) &&
+ !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
/* Connection accepted */
struct inquiry_entry *ie;
struct hci_conn *conn;
@@ -2116,7 +2117,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev);
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
- struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
+ struct inquiry_info_with_rssi_and_pscan_mode *info;
+ info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
@@ -2276,12 +2278,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = 0x00;
+ data.pscan_rep_mode = info->pscan_rep_mode;
+ data.pscan_period_mode = info->pscan_period_mode;
+ data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
+ data.clock_offset = info->clock_offset;
+ data.rssi = info->rssi;
data.ssp_mode = 0x01;
info++;
hci_inquiry_cache_update(hdev, &data);
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
include/net/bluetooth/hci_core.h | 58 +++++++++++++++++++-------------------
1 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e4f370f..2893288 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -208,37 +208,37 @@ struct hci_dev {
struct hci_conn {
struct list_head list;
- atomic_t refcnt;
- spinlock_t lock;
-
- bdaddr_t dst;
- __u16 handle;
- __u16 state;
- __u8 mode;
- __u8 type;
- __u8 out;
- __u8 attempt;
- __u8 dev_class[3];
- __u8 features[8];
- __u8 ssp_mode;
- __u16 interval;
- __u16 pkt_type;
- __u16 link_policy;
- __u32 link_mode;
- __u8 auth_type;
- __u8 sec_level;
- __u8 pending_sec_level;
- __u8 pin_length;
- __u8 io_capability;
- __u8 power_save;
- __u16 disc_timeout;
- unsigned long pend;
+ atomic_t refcnt;
+ spinlock_t lock;
+
+ bdaddr_t dst;
+ __u16 handle;
+ __u16 state;
+ __u8 mode;
+ __u8 type;
+ __u8 out;
+ __u8 attempt;
+ __u8 dev_class[3];
+ __u8 features[8];
+ __u8 ssp_mode;
+ __u16 interval;
+ __u16 pkt_type;
+ __u16 link_policy;
+ __u32 link_mode;
+ __u8 auth_type;
+ __u8 sec_level;
+ __u8 pending_sec_level;
+ __u8 pin_length;
+ __u8 io_capability;
+ __u8 power_save;
+ __u16 disc_timeout;
+ unsigned long pend;
__u8 remote_cap;
__u8 remote_oob;
__u8 remote_auth;
- unsigned int sent;
+ unsigned int sent;
struct sk_buff_head data_q;
@@ -356,7 +356,7 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
}
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
- __u16 handle)
+ __u16 handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
@@ -371,7 +371,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
}
static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
- __u8 type, bdaddr_t *ba)
+ __u8 type, bdaddr_t *ba)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
@@ -386,7 +386,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
}
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
- __u8 type, __u16 state)
+ __u8 type, __u16 state)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
--
1.7.0.4
Hi Szymon,
* Szymon Janc <[email protected]> [2011-02-17 14:16:38 +0100]:
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 91 +++++++++++++++++++++-----------------
> 1 files changed, 51 insertions(+), 40 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index e4f370f..a8a5ecb 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -208,37 +208,37 @@ struct hci_dev {
> struct hci_conn {
> struct list_head list;
>
> - atomic_t refcnt;
> - spinlock_t lock;
> -
> - bdaddr_t dst;
> - __u16 handle;
> - __u16 state;
> - __u8 mode;
> - __u8 type;
> - __u8 out;
> - __u8 attempt;
> - __u8 dev_class[3];
> - __u8 features[8];
> - __u8 ssp_mode;
> - __u16 interval;
> - __u16 pkt_type;
> - __u16 link_policy;
> - __u32 link_mode;
> - __u8 auth_type;
> - __u8 sec_level;
> - __u8 pending_sec_level;
> - __u8 pin_length;
> - __u8 io_capability;
> - __u8 power_save;
> - __u16 disc_timeout;
> - unsigned long pend;
> + atomic_t refcnt;
> + spinlock_t lock;
> +
> + bdaddr_t dst;
> + __u16 handle;
> + __u16 state;
> + __u8 mode;
> + __u8 type;
> + __u8 out;
> + __u8 attempt;
> + __u8 dev_class[3];
> + __u8 features[8];
> + __u8 ssp_mode;
> + __u16 interval;
> + __u16 pkt_type;
> + __u16 link_policy;
> + __u32 link_mode;
> + __u8 auth_type;
> + __u8 sec_level;
> + __u8 pending_sec_level;
> + __u8 pin_length;
> + __u8 io_capability;
> + __u8 power_save;
> + __u16 disc_timeout;
> + unsigned long pend;
>
> __u8 remote_cap;
> __u8 remote_oob;
> __u8 remote_auth;
>
> - unsigned int sent;
> + unsigned int sent;
>
> struct sk_buff_head data_q;
>
> @@ -298,7 +298,8 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)
> return jiffies - e->timestamp;
> }
>
> -struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
> +struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
> + bdaddr_t *bdaddr);
Leave the line over 80 fix out of this patches, I'm not sure if I want to fix
that now.
--
Gustavo F. Padovan
http://profusion.mobi
Hi Szymon,
* Szymon Janc <[email protected]> [2011-02-17 14:16:33 +0100]:
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> net/bluetooth/hci_event.c | 9 ---------
> 1 files changed, 0 insertions(+), 9 deletions(-)
Good catch, applied as well. Thanks.
--
Gustavo F. Padovan
http://profusion.mobi
Hi Szymon,
* Szymon Janc <[email protected]> [2011-02-17 14:16:32 +0100]:
> As warned by checkpatch.pl, use #include <linux/uaccess.h> instead of
> <asm/uaccess.h>.
>
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> net/bluetooth/mgmt.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
Applied, thanks.
--
Gustavo F. Padovan
http://profusion.mobi
Hi,
> On Thu, Feb 17, 2011 at 02:16:35PM +0100, ext Szymon Janc wrote:
> > Signed-off-by: Szymon Janc <[email protected]>
> > ---
> > net/bluetooth/mgmt.c | 7 +++----
> > 1 files changed, 3 insertions(+), 4 deletions(-)
>
> Some kind of explanation why EIO is better than status would be nice.
As I've mentioned in cover letter:
It is not possible to distinguish in cmd status if error was from kernel
or from HCI. Since in mgmt only kernel sends HCI commands their errors
shouldn't be needed for userspace so report EIO to userspace on HCI error
(if HCI error is needed for debugging, logs can be added on kernel side)
HCI status codes and kernel error codes overlaps i.e. one can't distinguish
if error was ENOMEM or HCI Command Disallowed as both have value 12.
For userspace is should be enough to just know that HCI failed, not why.
(in fact, currently userspace is not able to determine error too...)
--
br
Szymon Janc
Hi,
On Thu, Feb 17, 2011 at 02:16:35PM +0100, ext Szymon Janc wrote:
> Signed-off-by: Szymon Janc <[email protected]>
> ---
> net/bluetooth/mgmt.c | 7 +++----
> 1 files changed, 3 insertions(+), 4 deletions(-)
Some kind of explanation why EIO is better than status would be nice.
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index aee1da6..dee82fe 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -1372,8 +1372,7 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
> return -ENOENT;
>
> if (status != 0)
> - err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status, NULL,
> - 0);
> + err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, EIO, NULL, 0);
> else
> err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
> bdaddr, sizeof(*bdaddr));
> @@ -1394,8 +1393,8 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
> return -ENOENT;
>
> if (status != 0)
> - err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status,
> - NULL, 0);
> + err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, EIO, NULL,
> + 0);
> else
> err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
> bdaddr, sizeof(*bdaddr));
--
Ville
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/hci_event.c | 9 ---------
1 files changed, 0 insertions(+), 9 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 09cb29e..1741936 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2242,17 +2242,8 @@ static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buf
static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_sniff_subrate *ev = (void *) skb->data;
- struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- }
-
- hci_dev_unlock(hdev);
}
static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
--
1.7.0.4
In managment interface command status event is used to report command failure.
Some commands (i.e. Read Local Oob Data) should be able to provide extra data
on failure.
Signed-off-by: Szymon Janc <[email protected]>
---
include/net/bluetooth/mgmt.h | 1 +
net/bluetooth/mgmt.c | 95 ++++++++++++++++++++++++------------------
2 files changed, 56 insertions(+), 40 deletions(-)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 44ac55c..a5cc1e0 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -170,6 +170,7 @@ struct mgmt_ev_cmd_complete {
struct mgmt_ev_cmd_status {
__u8 status;
__le16 opcode;
+ __u8 data[0];
} __packed;
#define MGMT_EV_CONTROLLER_ERROR 0x0003
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f5ef7a3..aee1da6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -42,7 +42,8 @@ struct pending_cmd {
LIST_HEAD(cmd_list);
-static int cmd_status(struct sock *sk, u16 cmd, u8 status)
+static int cmd_status(struct sock *sk, u16 cmd, u8 status, void *data,
+ size_t data_len)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
@@ -50,19 +51,22 @@ static int cmd_status(struct sock *sk, u16 cmd, u8 status)
BT_DBG("sock %p", sk);
- skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
+ skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + data_len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
- hdr->len = cpu_to_le16(sizeof(*ev));
+ hdr->len = cpu_to_le16(sizeof(*ev) + data_len);
- ev = (void *) skb_put(skb, sizeof(*ev));
+ ev = (void *) skb_put(skb, sizeof(*ev) + data_len);
ev->status = status;
put_unaligned_le16(cmd, &ev->opcode);
+ if (data)
+ memcpy(ev->data, data, data_len);
+
if (sock_queue_rcv_skb(sk, skb) < 0)
kfree_skb(skb);
@@ -168,7 +172,7 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
BT_DBG("sock %p", sk);
if (len != 2)
- return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
+ return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL, NULL, 0);
dev_id = get_unaligned_le16(&cp->index);
@@ -176,7 +180,7 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
+ return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV, NULL, 0);
hci_del_off_timer(hdev);
@@ -315,18 +319,18 @@ static int set_powered(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
up = test_bit(HCI_UP, &hdev->flags);
if ((cp->val && up) || (!cp->val && !up)) {
- ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
+ ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY, NULL, 0);
goto failed;
}
if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
- ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
+ ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY, NULL, 0);
goto failed;
}
@@ -362,24 +366,27 @@ static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV, NULL,
+ 0);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
+ err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN, NULL,
+ 0);
goto failed;
}
if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
- err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
+ err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY, NULL, 0);
goto failed;
}
if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
test_bit(HCI_PSCAN, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
+ err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY, NULL,
+ 0);
goto failed;
}
@@ -418,23 +425,25 @@ static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
+ err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN, NULL,
+ 0);
goto failed;
}
if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
- err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
+ err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY, NULL, 0);
goto failed;
}
if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
+ err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY, NULL,
+ 0);
goto failed;
}
@@ -505,7 +514,7 @@ static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
@@ -578,7 +587,7 @@ static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
+ return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
@@ -622,7 +631,7 @@ static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
+ return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
@@ -644,7 +653,7 @@ static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
}
if (found == 0) {
- err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
+ err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT, NULL, 0);
goto unlock;
}
@@ -675,7 +684,7 @@ static int set_dev_class(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_DEV_CLASS, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
@@ -706,7 +715,8 @@ static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_SERVICE_CACHE, ENODEV, NULL,
+ 0);
hci_dev_lock_bh(hdev);
@@ -750,7 +760,7 @@ static int load_keys(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
+ return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV, NULL, 0);
BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
key_count);
@@ -792,13 +802,13 @@ static int remove_key(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
+ return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
- err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
+ err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err, NULL, 0);
goto unlock;
}
@@ -839,23 +849,23 @@ static int disconnect(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
+ return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN);
+ err = cmd_status(sk, MGMT_OP_DISCONNECT, ENETDOWN, NULL, 0);
goto failed;
}
if (mgmt_pending_find(MGMT_OP_DISCONNECT, dev_id)) {
- err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY);
+ err = cmd_status(sk, MGMT_OP_DISCONNECT, EBUSY, NULL, 0);
goto failed;
}
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (!conn) {
- err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN);
+ err = cmd_status(sk, MGMT_OP_DISCONNECT, ENOTCONN, NULL, 0);
goto failed;
}
@@ -894,7 +904,7 @@ static int get_connections(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV);
+ return cmd_status(sk, MGMT_OP_GET_CONNECTIONS, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
@@ -948,12 +958,12 @@ static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
+ return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV, NULL, 0);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
+ err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN, NULL, 0);
goto failed;
}
@@ -990,12 +1000,14 @@ static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
+ return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV, NULL,
+ 0);
hci_dev_lock_bh(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
- err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
+ err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN, NULL,
+ 0);
goto failed;
}
@@ -1029,7 +1041,8 @@ static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
hdev = hci_dev_get(dev_id);
if (!hdev)
- return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
+ return cmd_status(sk, MGMT_OP_SET_IO_CAPABILITY, ENODEV, NULL,
+ 0);
hci_dev_lock_bh(hdev);
@@ -1132,7 +1145,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
break;
default:
BT_DBG("Unknown op %u", opcode);
- err = cmd_status(sk, opcode, 0x01);
+ err = cmd_status(sk, opcode, 0x01, NULL, 0);
break;
}
@@ -1320,7 +1333,7 @@ int mgmt_disconnect_failed(u16 index)
if (!cmd)
return -ENOENT;
- err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO);
+ err = cmd_status(cmd->sk, MGMT_OP_DISCONNECT, EIO, NULL, 0);
list_del(&cmd->list);
mgmt_pending_free(cmd);
@@ -1359,7 +1372,8 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status, NULL,
+ 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
bdaddr, sizeof(*bdaddr));
@@ -1380,7 +1394,8 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status,
+ NULL, 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
bdaddr, sizeof(*bdaddr));
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/mgmt.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index aee1da6..dee82fe 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1372,8 +1372,7 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status, NULL,
- 0);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, EIO, NULL, 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
bdaddr, sizeof(*bdaddr));
@@ -1394,8 +1393,8 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return -ENOENT;
if (status != 0)
- err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status,
- NULL, 0);
+ err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, EIO, NULL,
+ 0);
else
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
bdaddr, sizeof(*bdaddr));
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/hci_core.c | 30 +++++++++++++++++-------------
1 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0f5bbb0..60581b7 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -123,8 +123,9 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
}
/* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+static int __hci_request(struct hci_dev *hdev,
+ void (*req)(struct hci_dev *hdev, unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
DECLARE_WAITQUEUE(wait, current);
int err = 0;
@@ -165,8 +166,9 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
return err;
}
-static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+static inline int hci_request(struct hci_dev *hdev,
+ void (*req)(struct hci_dev *hdev, unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
int ret;
@@ -351,7 +353,8 @@ 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_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
+ bdaddr_t *bdaddr)
{
struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *e;
@@ -459,13 +462,13 @@ int hci_inquiry(void __user *arg)
goto done;
}
- /* for unlimited number of responses we will use buffer with 255 entries */
+ /* for unlimited number of responses use buffer with 255 entries */
max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
/* cache_dump can't sleep. Therefore we allocate temp buffer and then
* copy it to the user space.
*/
- buf = kmalloc(sizeof(struct inquiry_info) *max_rsp, GFP_KERNEL);
+ buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto done;
@@ -534,7 +537,6 @@ int hci_dev_open(__u16 dev)
set_bit(HCI_INIT, &hdev->flags);
hdev->init_last_cmd = 0;
- //__hci_request(hdev, hci_reset_req, 0, HZ);
ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT));
@@ -1748,7 +1750,8 @@ EXPORT_SYMBOL(hci_send_sco);
/* ---- HCI TX task (outgoing data) ---- */
/* HCI Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
+ int *quote)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *conn = NULL;
@@ -1833,7 +1836,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 + HZ * 45))
hci_link_tx_to(hdev, ACL_LINK);
}
@@ -1881,7 +1885,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) {
+ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e)))
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
hci_send_frame(skb);
@@ -1890,7 +1894,6 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
if (conn->sent == ~0)
conn->sent = 0;
}
- }
}
static inline void hci_sched_le(struct hci_dev *hdev)
@@ -1969,7 +1972,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
flags = hci_flags(handle);
handle = hci_handle(handle);
- BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
+ BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle,
+ flags);
hdev->stat.acl_rx++;
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 571cbcf..208c211 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -49,7 +49,7 @@ static int cmd_status(struct sock *sk, u16 cmd, u8 status, void *data,
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_status *ev;
- BT_DBG("sock %p", sk);
+ BT_DBG("sock %p, cmd %u, status %u", sk, cmd, status);
skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + data_len, GFP_ATOMIC);
if (!skb)
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/hci_event.c | 136 +++++++++++++++++++++++++++++---------------
1 files changed, 89 insertions(+), 47 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b39c9bb..9fa91c8 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -77,7 +77,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
hci_conn_check_pending(hdev);
}
-static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
@@ -148,7 +149,8 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);
}
-static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
@@ -160,7 +162,8 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *sk
hdev->link_policy = __le16_to_cpu(rp->policy);
}
-static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
void *sent;
@@ -355,7 +358,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
}
}
-static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_write_voice_setting(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
__u16 setting;
@@ -574,7 +578,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
sizeof(link_policy), &link_policy);
}
-static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_local_commands(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_rp_read_local_commands *rp = (void *) skb->data;
@@ -592,7 +597,8 @@ done:
hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
}
-static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_local_features(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_rp_read_local_features *rp = (void *) skb->data;
@@ -1174,7 +1180,8 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev);
}
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -1187,7 +1194,8 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
hci_conn_check_pending(hdev);
}
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_result_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct inquiry_data data;
struct inquiry_info *info = (void *) (skb->data + 1);
@@ -1216,7 +1224,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev);
}
-static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_conn_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1294,7 +1303,8 @@ unlock:
hci_conn_check_pending(hdev);
}
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_conn_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_conn_request *ev = (void *) skb->data;
int mask = hdev->link_mode;
@@ -1304,7 +1314,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
- if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
+ if ((mask & HCI_LM_ACCEPT) &&
+ !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
/* Connection accepted */
struct inquiry_entry *ie;
struct hci_conn *conn;
@@ -1315,7 +1326,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
if (ie)
memcpy(ie->data.dev_class, ev->dev_class, 3);
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+ conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
+ &ev->bdaddr);
if (!conn) {
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
@@ -1367,7 +1379,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
}
}
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_disconn_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_disconn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1397,7 +1410,8 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_auth_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_auth_complete *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1454,7 +1468,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
hci_dev_unlock(hdev);
}
-static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_name_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_remote_name *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1475,7 +1490,8 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
hci_dev_unlock(hdev);
}
-static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_encrypt_change_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_encrypt_change *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1510,7 +1526,8 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev);
}
-static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1532,7 +1549,8 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
hci_dev_unlock(hdev);
}
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_features_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_remote_features *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1578,17 +1596,20 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_version_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
-static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
-static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_cmd_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_cmd_complete *ev = (void *) skb->data;
__u16 opcode;
@@ -1835,7 +1856,8 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
}
}
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_role_change_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_role_change *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1861,7 +1883,8 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
hci_dev_unlock(hdev);
}
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
__le16 *ptr;
@@ -1916,7 +1939,8 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
tasklet_enable(&hdev->tx_task);
}
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_mode_change_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_mode_change *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1944,7 +1968,8 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
hci_dev_unlock(hdev);
}
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_pin_code_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_pin_code_req *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -1970,7 +1995,8 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_unlock(hdev);
}
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_link_key_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_link_key_req *ev = (void *) skb->data;
struct hci_cp_link_key_reply cp;
@@ -2021,7 +2047,8 @@ not_found:
hci_dev_unlock(hdev);
}
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_link_key_notify_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_link_key_notify *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2046,7 +2073,8 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_unlock(hdev);
}
-static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_clock_offset_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_clock_offset *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2069,7 +2097,8 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_dev_unlock(hdev);
}
-static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_pkt_type_change_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_pkt_type_change *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2085,7 +2114,8 @@ static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_unlock(hdev);
}
-static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
struct inquiry_entry *ie;
@@ -2103,7 +2133,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev);
}
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct inquiry_data data;
int num_rsp = *((__u8 *) skb->data);
@@ -2116,7 +2147,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev);
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
- struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
+ struct inquiry_info_with_rssi_and_pscan_mode *info;
+ info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
@@ -2150,7 +2182,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
hci_dev_unlock(hdev);
}
-static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_ext_features_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_remote_ext_features *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2194,7 +2227,8 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2249,19 +2283,22 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
-static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_sniff_subrate_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_sniff_subrate *ev = (void *) skb->data;
BT_DBG("%s status %d", hdev->name, ev->status);
}
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct inquiry_data data;
struct extended_inquiry_info *info = (void *) (skb->data + 1);
@@ -2276,12 +2313,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = 0x00;
+ data.pscan_rep_mode = info->pscan_rep_mode;
+ data.pscan_period_mode = info->pscan_period_mode;
+ data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
+ data.clock_offset = info->clock_offset;
+ data.rssi = info->rssi;
data.ssp_mode = 0x01;
info++;
hci_inquiry_cache_update(hdev, &data);
@@ -2309,7 +2346,8 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
return conn->auth_type;
}
-static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_io_capa_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_io_capa_request *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2357,7 +2395,8 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_io_capa_reply_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_io_capa_reply *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2380,7 +2419,8 @@ unlock:
hci_dev_unlock(hdev);
}
-static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
struct hci_conn *conn;
@@ -2396,7 +2436,8 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
hci_dev_unlock(hdev);
}
-static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_host_features_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_remote_host_features *ev = (void *) skb->data;
struct inquiry_entry *ie;
@@ -2443,7 +2484,8 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
-static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_le_conn_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
--
1.7.0.4
Signed-off-by: Szymon Janc <[email protected]>
---
include/net/bluetooth/hci_core.h | 91 +++++++++++++++++++++-----------------
1 files changed, 51 insertions(+), 40 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e4f370f..a8a5ecb 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -208,37 +208,37 @@ struct hci_dev {
struct hci_conn {
struct list_head list;
- atomic_t refcnt;
- spinlock_t lock;
-
- bdaddr_t dst;
- __u16 handle;
- __u16 state;
- __u8 mode;
- __u8 type;
- __u8 out;
- __u8 attempt;
- __u8 dev_class[3];
- __u8 features[8];
- __u8 ssp_mode;
- __u16 interval;
- __u16 pkt_type;
- __u16 link_policy;
- __u32 link_mode;
- __u8 auth_type;
- __u8 sec_level;
- __u8 pending_sec_level;
- __u8 pin_length;
- __u8 io_capability;
- __u8 power_save;
- __u16 disc_timeout;
- unsigned long pend;
+ atomic_t refcnt;
+ spinlock_t lock;
+
+ bdaddr_t dst;
+ __u16 handle;
+ __u16 state;
+ __u8 mode;
+ __u8 type;
+ __u8 out;
+ __u8 attempt;
+ __u8 dev_class[3];
+ __u8 features[8];
+ __u8 ssp_mode;
+ __u16 interval;
+ __u16 pkt_type;
+ __u16 link_policy;
+ __u32 link_mode;
+ __u8 auth_type;
+ __u8 sec_level;
+ __u8 pending_sec_level;
+ __u8 pin_length;
+ __u8 io_capability;
+ __u8 power_save;
+ __u16 disc_timeout;
+ unsigned long pend;
__u8 remote_cap;
__u8 remote_oob;
__u8 remote_auth;
- unsigned int sent;
+ unsigned int sent;
struct sk_buff_head data_q;
@@ -298,7 +298,8 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)
return jiffies - e->timestamp;
}
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+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);
/* ----- HCI Connections ----- */
@@ -356,7 +357,7 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
}
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
- __u16 handle)
+ __u16 handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
@@ -371,7 +372,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
}
static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
- __u8 type, bdaddr_t *ba)
+ __u8 type, bdaddr_t *ba)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
@@ -386,7 +387,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
}
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
- __u8 type, __u16 state)
+ __u8 type, __u16 state)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
@@ -411,7 +412,8 @@ int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
+ __u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
int hci_conn_change_link_key(struct hci_conn *conn);
@@ -499,7 +501,8 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
int hci_inquiry(void __user *arg);
-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);
int hci_blacklist_clear(struct hci_dev *hdev);
int hci_uuids_clear(struct hci_dev *hdev);
@@ -551,16 +554,20 @@ struct hci_proto {
void *priv;
- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
+ int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr,
+ __u8 type);
int (*connect_cfm) (struct hci_conn *conn, __u8 status);
int (*disconn_ind) (struct hci_conn *conn);
int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
- int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+ int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb,
+ __u16 flags);
int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
- int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
+ int (*security_cfm) (struct hci_conn *conn, __u8 status,
+ __u8 encrypt);
};
-static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ __u8 type)
{
register struct hci_proto *hp;
int mask = 0;
@@ -637,7 +644,8 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
hp->security_cfm(conn, status, encrypt);
}
-static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
+static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status,
+ __u8 encrypt)
{
register struct hci_proto *hp;
@@ -659,7 +667,8 @@ struct hci_cb {
char *name;
- void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
+ void (*security_cfm) (struct hci_conn *conn, __u8 status,
+ __u8 encrypt);
void (*key_change_cfm) (struct hci_conn *conn, __u8 status);
void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
};
@@ -685,7 +694,8 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
read_unlock_bh(&hci_cb_list_lock);
}
-static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
+static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
+ __u8 encrypt)
{
struct list_head *p;
@@ -716,7 +726,8 @@ static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
read_unlock_bh(&hci_cb_list_lock);
}
-static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, __u8 role)
+static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
+ __u8 role)
{
struct list_head *p;
--
1.7.0.4
This patch adds a command to read local OOB data to the managment interface.
The command maps directly to the Read Local OOB Data HCI command.
Signed-off-by: Szymon Janc <[email protected]>
---
include/net/bluetooth/hci.h | 7 +++
include/net/bluetooth/hci_core.h | 2 +
include/net/bluetooth/mgmt.h | 14 ++++++
net/bluetooth/hci_event.c | 15 ++++++
net/bluetooth/mgmt.c | 92 ++++++++++++++++++++++++++++++++++++++
5 files changed, 130 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index a5f8c46..7d1aef9 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -600,6 +600,13 @@ struct hci_cp_write_ssp_mode {
__u8 mode;
} __packed;
+#define HCI_OP_READ_LOCAL_OOB_DATA 0x0c57
+struct hci_rp_read_local_oob_data {
+ __u8 status;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
#define HCI_OP_READ_LOCAL_VERSION 0x1001
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7ee921d..704f265 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -746,6 +746,8 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
+int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+ u8 status);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a5cc1e0..18e2fb6 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -160,6 +160,20 @@ struct mgmt_cp_set_io_capability {
__u8 io_capability;
} __packed;
+
+#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0017
+struct mgmt_cp_read_local_oob_data {
+ __le16 index;
+} __packed;
+struct mgmt_rp_read_local_oob_data {
+ __le16 index;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+struct mgmt_rp_read_local_oob_data_failed {
+ __le16 index;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1741936..053fcf7 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -796,6 +796,17 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
}
+static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+ mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+ rp->randomizer, rp->status);
+}
+
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1723,6 +1734,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_pin_code_neg_reply(hdev, skb);
break;
+ case HCI_OP_READ_LOCAL_OOB_DATA:
+ hci_cc_read_local_oob_data_reply(hdev, skb);
+ break;
+
case HCI_OP_LE_READ_BUFFER_SIZE:
hci_cc_le_read_buffer_size(hdev, skb);
break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index dee82fe..2847934 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1058,6 +1058,60 @@ static int set_io_capability(struct sock *sk, unsigned char *data, u16 len)
&dev_id, sizeof(dev_id));
}
+static int read_local_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_read_local_oob_data *cp;
+ struct mgmt_rp_read_local_oob_data_failed rp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+ rp.index = cp->index;
+
+ BT_DBG("hci%u", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_READ_LOCAL_OOB_DATA, ENODEV, &rp,
+ sizeof(rp));
+
+ hci_dev_lock_bh(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = -ENETDOWN;
+ goto unlock;
+ }
+
+ if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+ err = -EPERM;
+ goto unlock;
+ }
+
+ if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, dev_id)) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ err = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, dev_id, data,
+ len);
+ if (err == 0)
+ err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
+
+unlock:
+ if (err < 0) {
+ err = cmd_status(sk, MGMT_OP_READ_LOCAL_OOB_DATA, -err, &rp,
+ sizeof(rp));
+ mgmt_pending_remove(MGMT_OP_READ_LOCAL_OOB_DATA, dev_id);
+ }
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -1143,6 +1197,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_SET_IO_CAPABILITY:
err = set_io_capability(sk, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_READ_LOCAL_OOB_DATA:
+ err = read_local_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, opcode, 0x01, NULL, 0);
@@ -1404,3 +1461,38 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return err;
}
+
+int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+ u8 status)
+{
+ struct pending_cmd *cmd;
+ int err;
+
+ BT_DBG("hci%u status %u", index, status);
+
+ cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
+ if (!cmd)
+ return -ENOENT;
+
+ if (status) {
+ struct mgmt_rp_read_local_oob_data_failed rp;
+ put_unaligned_le16(index, &rp.index);
+
+ err = cmd_status(cmd->sk, MGMT_OP_READ_LOCAL_OOB_DATA, EIO, &rp,
+ sizeof(rp));
+ } else {
+ struct mgmt_rp_read_local_oob_data rp;
+
+ put_unaligned_le16(index, &rp.index);
+ memcpy(rp.hash, hash, 16);
+ memcpy(rp.randomizer, randomizer, 16);
+
+ err = cmd_complete(cmd->sk, MGMT_OP_READ_LOCAL_OOB_DATA, &rp,
+ sizeof(rp));
+ }
+
+ list_del(&cmd->list);
+ mgmt_pending_free(cmd);
+
+ return err;
+}
--
1.7.0.4
This patch adds commands to add and remove remote OOB data to the managment
interface. Remote data is stored in kernel and used by corresponding HCI
commands and events (also implemented in this patch) when needed.
Signed-off-by: Szymon Janc <[email protected]>
---
include/net/bluetooth/hci.h | 17 ++++++++
include/net/bluetooth/hci_core.h | 16 ++++++++
include/net/bluetooth/mgmt.h | 14 +++++++
net/bluetooth/hci_core.c | 76 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 41 ++++++++++++++++++++-
net/bluetooth/mgmt.c | 73 ++++++++++++++++++++++++++++++++++++
6 files changed, 236 insertions(+), 1 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7d1aef9..d1dd7dc 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -415,6 +415,18 @@ struct hci_cp_io_capability_reply {
__u8 authentication;
} __packed;
+#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
+struct hci_cp_remote_oob_data_reply {
+ bdaddr_t bdaddr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
+#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433
+struct hci_cp_remote_oob_data_neg_reply {
+ bdaddr_t bdaddr;
+} __packed;
+
#define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434
struct hci_cp_io_capability_neg_reply {
bdaddr_t bdaddr;
@@ -943,6 +955,11 @@ struct hci_ev_io_capa_reply {
__u8 authentication;
} __packed;
+#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
+struct hci_ev_remote_oob_data_request {
+ bdaddr_t bdaddr;
+} __packed;
+
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete {
__u8 status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 704f265..e4f370f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -82,6 +82,13 @@ struct link_key {
u8 pin_len;
};
+struct oob_data {
+ struct list_head list;
+ bdaddr_t bdaddr;
+ u8 hash[16];
+ u8 randomizer[16];
+};
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -169,6 +176,8 @@ struct hci_dev {
struct list_head link_keys;
+ struct list_head remote_oob_data;
+
struct hci_dev_stats stat;
struct sk_buff_head driver_init;
@@ -501,6 +510,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_remote_oob_data_clear(struct hci_dev *hdev);
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+ bdaddr_t *bdaddr);
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+ u8 *randomizer);
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
+
void hci_del_off_timer(struct hci_dev *hdev);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 18e2fb6..9bfd30f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -174,6 +174,20 @@ struct mgmt_rp_read_local_oob_data_failed {
__le16 index;
} __packed;
+#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0018
+struct mgmt_cp_add_remote_oob_data {
+ __le16 index;
+ bdaddr_t bdaddr;
+ __u8 hash[16];
+ __u8 randomizer[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0019
+struct mgmt_cp_remove_remote_oob_data {
+ __le16 index;
+ bdaddr_t bdaddr;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 702d565..0f5bbb0 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1078,6 +1078,79 @@ static void hci_cmd_timer(unsigned long arg)
tasklet_schedule(&hdev->cmd_task);
}
+struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
+ bdaddr_t *bdaddr)
+{
+ struct list_head *p;
+
+ list_for_each(p, &hdev->remote_oob_data) {
+ struct oob_data *data;
+
+ data = list_entry(p, struct oob_data, list);
+
+ if (bacmp(bdaddr, &data->bdaddr) == 0)
+ return data;
+ }
+
+ return NULL;
+}
+
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct oob_data *data;
+
+ data = hci_find_remote_oob_data(hdev, bdaddr);
+ if (!data)
+ return -ENOENT;
+
+ BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+ list_del(&data->list);
+ kfree(data);
+
+ return 0;
+}
+
+int hci_remote_oob_data_clear(struct hci_dev *hdev)
+{
+ struct list_head *p, *n;
+
+ list_for_each_safe(p, n, &hdev->remote_oob_data) {
+ struct oob_data *data;
+
+ data = list_entry(p, struct oob_data, list);
+
+ list_del(p);
+ kfree(data);
+ }
+
+ return 0;
+}
+
+int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
+ u8 *randomizer)
+{
+ struct oob_data *data;
+
+ data = hci_find_remote_oob_data(hdev, bdaddr);
+
+ if (!data) {
+ data = kmalloc(sizeof(*data), GFP_ATOMIC);
+ if (!data)
+ return -ENOMEM;
+
+ bacpy(&data->bdaddr, bdaddr);
+ list_add(&data->list, &hdev->remote_oob_data);
+ }
+
+ memcpy(data->hash, hash, 16);
+ memcpy(data->randomizer, randomizer, 16);
+
+ BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
+
+ return 0;
+}
+
/* Register HCI device */
int hci_register_dev(struct hci_dev *hdev)
{
@@ -1142,6 +1215,8 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->link_keys);
+ INIT_LIST_HEAD(&hdev->remote_oob_data);
+
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1221,6 +1296,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev);
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
+ hci_remote_oob_data_clear(hdev);
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 053fcf7..b39c9bb 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2333,9 +2333,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.capability = conn->io_capability;
- cp.oob_data = 0;
cp.authentication = hci_get_auth_req(conn);
+ if ((conn->out == 1 || conn->remote_oob == 0x01) &&
+ hci_find_remote_oob_data(hdev, &conn->dst))
+ cp.oob_data = 0x01;
+ else
+ cp.oob_data = 0x00;
+
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
sizeof(cp), &cp);
} else {
@@ -2407,6 +2412,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
hci_dev_unlock(hdev);
}
+static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+ struct oob_data *data;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
+ if (data) {
+ struct hci_cp_remote_oob_data_reply cp;
+
+ bacpy(&cp.bdaddr, &ev->bdaddr);
+ memcpy(cp.hash, data->hash, 16);
+ memcpy(cp.randomizer, data->randomizer, 16);
+
+ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
+ &cp);
+ } else {
+ struct hci_cp_remote_oob_data_neg_reply cp;
+
+ bacpy(&cp.bdaddr, &ev->bdaddr);
+ hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
+ &cp);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -2603,6 +2639,9 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_EV_LE_META:
hci_le_meta_evt(hdev, skb);
+
+ case HCI_EV_REMOTE_OOB_DATA_REQUEST:
+ hci_remote_oob_data_request_evt(hdev, skb);
break;
default:
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2847934..571cbcf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1112,6 +1112,73 @@ unlock:
return err;
}
+static int add_remote_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_add_remote_oob_data *cp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+
+ BT_DBG("hci%u ", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, ENODEV, NULL,
+ 0);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
+ cp->randomizer);
+ if (err < 0)
+ err = cmd_status(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, -err, NULL,
+ 0);
+ else
+ err = cmd_complete(sk, MGMT_OP_ADD_REMOTE_OOB_DATA, &dev_id,
+ sizeof(dev_id));
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int remove_remote_oob_data(struct sock *sk, unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_remove_remote_oob_data *cp;
+ u16 dev_id;
+ int err;
+
+ cp = (void *) data;
+ dev_id = get_unaligned_le16(&cp->index);
+
+ BT_DBG("hci%u ", dev_id);
+
+ hdev = hci_dev_get(dev_id);
+ if (!hdev)
+ return cmd_status(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ENODEV,
+ NULL, 0);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+ if (err < 0)
+ err = cmd_status(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, -err, NULL,
+ 0);
+ else
+ err = cmd_complete(sk, MGMT_OP_REMOVE_REMOTE_OOB_DATA, &dev_id,
+ sizeof(dev_id));
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -1200,6 +1267,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_READ_LOCAL_OOB_DATA:
err = read_local_oob_data(sk, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_ADD_REMOTE_OOB_DATA:
+ err = add_remote_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
+ case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
+ err = remove_remote_oob_data(sk, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, opcode, 0x01, NULL, 0);
--
1.7.0.4
As warned by checkpatch.pl, use #include <linux/uaccess.h> instead of
<asm/uaccess.h>.
Signed-off-by: Szymon Janc <[email protected]>
---
net/bluetooth/mgmt.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b2bda83..f5ef7a3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -22,7 +22,7 @@
/* Bluetooth HCI Management interface */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
--
1.7.0.4