From 152d386e111fed3fee5fe888f38b0ae73ea15400 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Wed, 11 Feb 2015 12:31:40 +0100 Subject: Bluetooth: Do not allow LE connection if LE is not enabled Kernel gives possibility to enable/disable LE host support. There is flag HCI_LE_ENABLED which is set when this support is enabled and some parts of the code checks this flag e.g. SMP However it is still possible to make LE connection if LE Host support is disabled, what might be confused for remote device. This patch makes sure that kernel will not send HCI LE Create Connection if LE HOST support is not enabled. Signed-off-by: Lukasz Rymanowski Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index c9b8fa544785..409c05e9e00a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -733,6 +733,14 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, struct hci_request req; int err; + /* Let's make sure that le is enabled.*/ + if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + if (lmp_le_capable(hdev)) + return ERR_PTR(-ECONNREFUSED); + + return ERR_PTR(-EOPNOTSUPP); + } + /* Some devices send ATT messages as soon as the physical link is * established. To be able to handle these ATT messages, the user- * space first establishes the connection and then starts the pairing -- cgit v1.2.3 From c411110e1f13abd64886c8abdf6f31c10136969f Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Wed, 11 Feb 2015 12:31:41 +0100 Subject: Bluetooth: Improve error handling in connect acl With this patch -EOPNOTSUPP will be returned by hci_connect_acl for LE only controllers. If it is dual device with disabled BREDR -ECONNREFUSED will be returned Signed-off-by: Lukasz Rymanowski Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 409c05e9e00a..e3263b61bcf3 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -864,8 +864,12 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, { struct hci_conn *acl; - if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { + if (lmp_bredr_capable(hdev)) + return ERR_PTR(-ECONNREFUSED); + return ERR_PTR(-EOPNOTSUPP); + } acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { -- cgit v1.2.3 From faa810303d4141de335a8b29ec7fba8d653903fc Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Wed, 11 Feb 2015 12:31:42 +0100 Subject: Bluetooth: Enhance error codes pair device command If user space is trying to pair on not enabled transport MGMT_STATUS_REJECT will be returned. If user space is trying to pair on transport which controller does not support, MGMT_STATUS_NOT_SUPPORTED will be returned. Having separate error code for that scenario might be useful for debugging at least. Signed-off-by: Lukasz Rymanowski Signed-off-by: Johan Hedberg --- 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 9ec5390c85eb..1b528dea9844 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3249,6 +3249,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (PTR_ERR(conn) == -EBUSY) status = MGMT_STATUS_BUSY; + else if (PTR_ERR(conn) == -EOPNOTSUPP) + status = MGMT_STATUS_NOT_SUPPORTED; + else if (PTR_ERR(conn) == -ECONNREFUSED) + status = MGMT_STATUS_REJECTED; else status = MGMT_STATUS_CONNECT_FAILED; -- cgit v1.2.3 From a44fecbd52a4d9c36f07eb2161c153047d8765d4 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Fri, 13 Feb 2015 09:20:50 -0800 Subject: Bluetooth: Add shutdown callback before closing the device This callback allows a vendor to send the vendor specific commands before cloing the hci interface. Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3322d3f4c85a..4135a4406aed 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1591,6 +1591,12 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); + if (!test_bit(HCI_UNREGISTER, &hdev->dev_flags)) { + /* Execute vendor specific shutdown routine */ + if (hdev->shutdown) + hdev->shutdown(hdev); + } + cancel_delayed_work(&hdev->power_off); hci_req_cancel(hdev, ENODEV); -- cgit v1.2.3 From 055540a176c48b33dbb4d756e80e1e301ef86a42 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 14 Feb 2015 13:36:03 -0800 Subject: Bluetooth: Move A2MP_FEAT_EXT declaration into A2MP source The A2MP_FEAT_EXT declaration has a single user in a2mp.c and thus just move it there. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/a2mp.c | 2 ++ net/bluetooth/a2mp.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index cedfbda15dad..6baa78a4e76c 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -19,6 +19,8 @@ #include "a2mp.h" #include "amp.h" +#define A2MP_FEAT_EXT 0x8000 + /* Global AMP Manager list */ LIST_HEAD(amp_mgr_list); DEFINE_MUTEX(amp_mgr_list_lock); diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h index 487b54c1308f..5c0a36b7ecc4 100644 --- a/net/bluetooth/a2mp.h +++ b/net/bluetooth/a2mp.h @@ -17,8 +17,6 @@ #include -#define A2MP_FEAT_EXT 0x8000 - enum amp_mgr_state { READ_LOC_AMP_INFO, READ_LOC_AMP_ASSOC, -- cgit v1.2.3 From 59d4d0863e2e87cbdc089bd446754d64a010d29c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 14 Feb 2015 13:36:04 -0800 Subject: Bluetooth: Make amp_mgr_list and amp_mgr_list_lock static There is no reason to have amp_mgr_list and amp_mgr_list_lock exported from a2mp.c and thus make both of them static. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/a2mp.c | 4 ++-- net/bluetooth/a2mp.h | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 6baa78a4e76c..e4f179117ae2 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -22,8 +22,8 @@ #define A2MP_FEAT_EXT 0x8000 /* Global AMP Manager list */ -LIST_HEAD(amp_mgr_list); -DEFINE_MUTEX(amp_mgr_list_lock); +static LIST_HEAD(amp_mgr_list); +static DEFINE_MUTEX(amp_mgr_list_lock); /* A2MP build & send command helper functions */ static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data) diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h index 5c0a36b7ecc4..883266602cbc 100644 --- a/net/bluetooth/a2mp.h +++ b/net/bluetooth/a2mp.h @@ -129,9 +129,6 @@ struct a2mp_physlink_rsp { #define A2MP_STATUS_PHYS_LINK_EXISTS 0x05 #define A2MP_STATUS_SECURITY_VIOLATION 0x06 -extern struct list_head amp_mgr_list; -extern struct mutex amp_mgr_list_lock; - struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); int amp_mgr_put(struct amp_mgr *mgr); u8 __next_ident(struct amp_mgr *mgr); -- cgit v1.2.3 From 469cd4c5a6ace7c6285d8708709d0002b8984d47 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 14 Feb 2015 13:36:05 -0800 Subject: Bluetooth: Make amp_mgr_lookup_by_state function static The amp_mgr_lookup_by_state function does not need to be exported. So just move it to a different location and make it static. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/a2mp.c | 34 +++++++++++++++++----------------- net/bluetooth/a2mp.h | 1 - 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index e4f179117ae2..6bba3044dc7f 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -77,6 +77,23 @@ u8 __next_ident(struct amp_mgr *mgr) return mgr->ident; } +static struct amp_mgr *amp_mgr_lookup_by_state(u8 state) +{ + struct amp_mgr *mgr; + + mutex_lock(&_mgr_list_lock); + list_for_each_entry(mgr, &_mgr_list, list) { + if (test_and_clear_bit(state, &mgr->state)) { + amp_mgr_get(mgr); + mutex_unlock(&_mgr_list_lock); + return mgr; + } + } + mutex_unlock(&_mgr_list_lock); + + return NULL; +} + /* hci_dev_list shall be locked */ static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl) { @@ -862,23 +879,6 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, return mgr->a2mp_chan; } -struct amp_mgr *amp_mgr_lookup_by_state(u8 state) -{ - struct amp_mgr *mgr; - - mutex_lock(&_mgr_list_lock); - list_for_each_entry(mgr, &_mgr_list, list) { - if (test_and_clear_bit(state, &mgr->state)) { - amp_mgr_get(mgr); - mutex_unlock(&_mgr_list_lock); - return mgr; - } - } - mutex_unlock(&_mgr_list_lock); - - return NULL; -} - void a2mp_send_getinfo_rsp(struct hci_dev *hdev) { struct amp_mgr *mgr; diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h index 883266602cbc..652117ebf2a5 100644 --- a/net/bluetooth/a2mp.h +++ b/net/bluetooth/a2mp.h @@ -134,7 +134,6 @@ int amp_mgr_put(struct amp_mgr *mgr); u8 __next_ident(struct amp_mgr *mgr); struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, struct sk_buff *skb); -struct amp_mgr *amp_mgr_lookup_by_state(u8 state); void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); void a2mp_discover_amp(struct l2cap_chan *chan); void a2mp_send_getinfo_rsp(struct hci_dev *hdev); -- cgit v1.2.3 From bc333cc4659b2f4614783154aca638a2adcf1264 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 14 Feb 2015 13:36:06 -0800 Subject: Bluetooth: Make a2mp_send function static The a2mp_send function is a local function and so do not export it and make it static. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/a2mp.c | 2 +- net/bluetooth/a2mp.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 6bba3044dc7f..cfc8fe1ee09b 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -45,7 +45,7 @@ static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data) return cmd; } -void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) +static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) { struct l2cap_chan *chan = mgr->a2mp_chan; struct a2mp_cmd *cmd; diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h index 652117ebf2a5..41f9fbc26c29 100644 --- a/net/bluetooth/a2mp.h +++ b/net/bluetooth/a2mp.h @@ -134,7 +134,6 @@ int amp_mgr_put(struct amp_mgr *mgr); u8 __next_ident(struct amp_mgr *mgr); struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, struct sk_buff *skb); -void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); void a2mp_discover_amp(struct l2cap_chan *chan); void a2mp_send_getinfo_rsp(struct hci_dev *hdev); void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); -- cgit v1.2.3 From 87e2a020cac29fba4a35e681392ba0d1f7e21ba9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 14 Feb 2015 13:36:07 -0800 Subject: Bluetooth: Make __next_ident function static. The __next_ident function is a local function and so do not export it and make it static. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/a2mp.c | 2 +- net/bluetooth/a2mp.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index cfc8fe1ee09b..5a04eb1a7e57 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -69,7 +69,7 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *dat kfree(cmd); } -u8 __next_ident(struct amp_mgr *mgr) +static u8 __next_ident(struct amp_mgr *mgr) { if (++mgr->ident == 0) mgr->ident = 1; diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h index 41f9fbc26c29..296f665adb09 100644 --- a/net/bluetooth/a2mp.h +++ b/net/bluetooth/a2mp.h @@ -131,7 +131,6 @@ struct a2mp_physlink_rsp { struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); int amp_mgr_put(struct amp_mgr *mgr); -u8 __next_ident(struct amp_mgr *mgr); struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, struct sk_buff *skb); void a2mp_discover_amp(struct l2cap_chan *chan); -- cgit v1.2.3 From 035a07d5df7003bc6954f0aa42174416b775021c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 14 Feb 2015 13:40:06 -0800 Subject: Bluetooth: Provide option to enable/disable debugfs information The Bluetooth controllers can export extensive information about internal states via debugfs. This patch provides an option to choose if these information are provided or not. For backwards compatibility with existing kernel configuration, this option defaults to yes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/Kconfig | 8 ++++++++ net/bluetooth/Makefile | 3 ++- net/bluetooth/hci_debugfs.h | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 7de74635a110..b8c794b87523 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -91,4 +91,12 @@ config BT_SELFTEST_SMP Run test cases for SMP cryptographic functionality, including both legacy SMP as well as the Secure Connections features. +config BT_DEBUGFS + bool "Export Bluetooth internals in debugfs" + depends on BT && DEBUG_FS + default y + help + Provide extensive information about internal Bluetooth states + in debugfs. + source "drivers/bluetooth/Kconfig" diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 8e96e3072266..5d608799717e 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -13,8 +13,9 @@ bluetooth_6lowpan-y := 6lowpan.o bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ - a2mp.o amp.o ecc.o hci_request.o hci_debugfs.o + a2mp.o amp.o ecc.o hci_request.o +bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o subdir-ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/bluetooth/hci_debugfs.h b/net/bluetooth/hci_debugfs.h index fb68efe083c5..4444dc8cedc2 100644 --- a/net/bluetooth/hci_debugfs.h +++ b/net/bluetooth/hci_debugfs.h @@ -20,7 +20,29 @@ SOFTWARE IS DISCLAIMED. */ +#if IS_ENABLED(CONFIG_BT_DEBUGFS) + void hci_debugfs_create_common(struct hci_dev *hdev); void hci_debugfs_create_bredr(struct hci_dev *hdev); void hci_debugfs_create_le(struct hci_dev *hdev); void hci_debugfs_create_conn(struct hci_conn *conn); + +#else + +static inline void hci_debugfs_create_common(struct hci_dev *hdev) +{ +} + +static inline void hci_debugfs_create_bredr(struct hci_dev *hdev) +{ +} + +static inline void hci_debugfs_create_le(struct hci_dev *hdev) +{ +} + +static inline void hci_debugfs_create_conn(struct hci_conn *conn) +{ +} + +#endif -- cgit v1.2.3 From 315917e0a6d552a33f774935d8897ec1697605dd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Feb 2015 11:42:11 +0200 Subject: Bluetooth: Fix accepting early data on fixed channels On BR/EDR the L2CAP channel instances for fixed channels have so far been marked as ready only once the L2CAP information req/rsp procedure is complete and we have the fixed channel mask. This could however lead to data being dropped if we receive it on the channel before knowing the remote mask. Since it is valid for a remote to send data this early, simply assume that the channel is supported when we receive data on it. So far this hasn't been noticed much because of limited use of fixed channels on BR/EDR, but e.g. with SMP over BR/EDR this is already now visible with automated tests failing randomly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6ba33f9631e8..ec6f78e481dc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1244,6 +1244,13 @@ static void l2cap_move_done(struct l2cap_chan *chan) static void l2cap_chan_ready(struct l2cap_chan *chan) { + /* The channel may have already been flagged as connected in + * case of receiving data before the L2CAP info req/rsp + * procedure is complete. + */ + if (chan->state == BT_CONNECTED) + return; + /* This clears all conf flags, including CONF_NOT_COMPLETE */ chan->conf_state = 0; __clear_chan_timer(chan); @@ -6785,6 +6792,13 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, BT_DBG("chan %p, len %d", chan, skb->len); + /* If we receive data on a fixed channel before the info req/rsp + * procdure is done simply assume that the channel is supported + * and mark it as ready. + */ + if (chan->chan_type == L2CAP_CHAN_FIXED) + l2cap_chan_ready(chan); + if (chan->state != BT_CONNECTED) goto drop; -- cgit v1.2.3 From 0af801b9bf34e3eb9f86a210e9928d42922f6631 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 17 Feb 2015 15:05:21 +0200 Subject: Bluetooth: Fix AMP init for certain AMP controllers Some AMP controllers do not support the Read Local Features HCI commands (even though according to the spec they should). Luckily they at least correctly omit this from the supported commands bitmask, so we can work around the issue by creating a second AMP init phase and issuing the HCI command conditionally there. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4135a4406aed..980260846d25 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -390,7 +390,7 @@ static void bredr_init(struct hci_request *req) hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL); } -static void amp_init(struct hci_request *req) +static void amp_init1(struct hci_request *req) { req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED; @@ -400,9 +400,6 @@ static void amp_init(struct hci_request *req) /* Read Local Supported Commands */ hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - /* Read Local Supported Features */ - hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); - /* Read Local AMP Info */ hci_req_add(req, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); @@ -416,6 +413,16 @@ static void amp_init(struct hci_request *req) hci_req_add(req, HCI_OP_READ_LOCATION_DATA, 0, NULL); } +static void amp_init2(struct hci_request *req) +{ + /* Read Local Supported Features. Not all AMP controllers + * support this so it's placed conditionally in the second + * stage init. + */ + if (req->hdev->commands[14] & 0x20) + hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); +} + static void hci_init1_req(struct hci_request *req, unsigned long opt) { struct hci_dev *hdev = req->hdev; @@ -432,7 +439,7 @@ static void hci_init1_req(struct hci_request *req, unsigned long opt) break; case HCI_AMP: - amp_init(req); + amp_init1(req); break; default: @@ -578,6 +585,9 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) { struct hci_dev *hdev = req->hdev; + if (hdev->dev_type == HCI_AMP) + return amp_init2(req); + if (lmp_bredr_capable(hdev)) bredr_setup(req); else @@ -896,17 +906,17 @@ static int __hci_init(struct hci_dev *hdev) &dut_mode_fops); } + err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT); + if (err < 0) + return err; + /* HCI_BREDR covers both single-mode LE, BR/EDR and dual-mode * BR/EDR/LE type controllers. AMP controllers only need the - * first stage init. + * first two stages of init. */ if (hdev->dev_type != HCI_BREDR) return 0; - err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT); - if (err < 0) - return err; - err = __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT); if (err < 0) return err; -- cgit v1.2.3 From 00629e0fd56d528f0da4d9606726a4e22e576ace Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:54 +0200 Subject: Bluetooth: Add new hci_cb entries to the tail rather than the head When processing hci_cb entries we want first registered callbacks to be called first and later ones later. This is because eventually the L2CAP callbacks that are part of the core will use this list and get registered first. To keep the same order of calling L2CAP callbacks before e.g. RFCOMM the order of elements needs to be this way. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- 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 980260846d25..91f557b0318a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3465,7 +3465,7 @@ int hci_register_cb(struct hci_cb *cb) BT_DBG("%p name %s", cb, cb->name); write_lock(&hci_cb_list_lock); - list_add(&cb->list, &hci_cb_list); + list_add_tail(&cb->list, &hci_cb_list); write_unlock(&hci_cb_list_lock); return 0; -- cgit v1.2.3 From fba7ecf09bc458b15f9d578e4213c8c349f9592d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:55 +0200 Subject: Bluetooth: Convert hci_cb_list_lock to a mutex We'll soon need to be able to sleep inside the loops that iterate the hci_cb list, so neither a spinlock, rwlock or rcu are usable. This patch changes the lock to a mutex which permits sleeping while holding the lock. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 91f557b0318a..dbd26bcb9210 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -51,7 +51,7 @@ DEFINE_RWLOCK(hci_dev_list_lock); /* HCI callback list */ LIST_HEAD(hci_cb_list); -DEFINE_RWLOCK(hci_cb_list_lock); +DEFINE_MUTEX(hci_cb_list_lock); /* HCI ID Numbering */ static DEFINE_IDA(hci_index_ida); @@ -3464,9 +3464,9 @@ int hci_register_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); - write_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_add_tail(&cb->list, &hci_cb_list); - write_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); return 0; } @@ -3476,9 +3476,9 @@ int hci_unregister_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); - write_lock(&hci_cb_list_lock); + mutex_lock(&hci_cb_list_lock); list_del(&cb->list); - write_unlock(&hci_cb_list_lock); + mutex_unlock(&hci_cb_list_lock); return 0; } -- cgit v1.2.3 From 354fe804edb29625eee6dd7b1f3c72b43392704d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:56 +0200 Subject: Bluetooth: Convert L2CAP security callback to use hci_cb There's no reason to have the custom hci_proto_auth/encrypt_cfm helpers when the hci_cb list works equally well. This patch adds L2CAP to the hci_cb list and makes l2cap_security_cfm a private function of l2cap_core.c. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ec6f78e481dc..424fcc5c4980 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7345,13 +7345,13 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) } } -int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) +static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan; if (!conn) - return 0; + return; BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); @@ -7434,8 +7434,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } mutex_unlock(&conn->chan_lock); - - return 0; } int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) @@ -7543,6 +7541,11 @@ drop: return 0; } +static struct hci_cb l2cap_cb = { + .name = "L2CAP", + .security_cfm = l2cap_security_cfm, +}; + static int l2cap_debugfs_show(struct seq_file *f, void *p) { struct l2cap_chan *c; @@ -7584,6 +7587,8 @@ int __init l2cap_init(void) if (err < 0) return err; + hci_register_cb(&l2cap_cb); + if (IS_ERR_OR_NULL(bt_debugfs)) return 0; @@ -7601,6 +7606,7 @@ int __init l2cap_init(void) void l2cap_exit(void) { debugfs_remove(l2cap_debugfs); + hci_unregister_cb(&l2cap_cb); l2cap_cleanup_sockets(); } -- cgit v1.2.3 From 539c496d88f7f96d42abde4e9d901c8f8167d615 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:57 +0200 Subject: Bluetooth: Convert connect_cfm to be triggered through hci_cb This patch moves all the connect_cfm callbacks to be based on the hci_cb list. This means making l2cap_connect_cfm private to l2cap_core.c and sco_connect_cb private to sco.c respectively. Since the hci_conn type filtering isn't done any more on the wrapper level the callbacks themselves need to check that they were passed a relevant type of connection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_event.c | 36 ++++++++++++++++++------------------ net/bluetooth/l2cap_core.c | 6 +++++- net/bluetooth/sco.c | 15 ++++++++++++++- 4 files changed, 39 insertions(+), 22 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e3263b61bcf3..e9206734e024 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -309,7 +309,7 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) else hci_add_sco(sco, conn->handle); } else { - hci_proto_connect_cfm(sco, status); + hci_connect_cfm(sco, status); hci_conn_del(sco); } } @@ -618,7 +618,7 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, status); - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_del(conn); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a3fb094822b6..0b599129c64c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1537,7 +1537,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (conn && conn->state == BT_CONNECT) { if (status != 0x0c || conn->attempt > 2) { conn->state = BT_CLOSED; - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_del(conn); } else conn->state = BT_CONNECT2; @@ -1581,7 +1581,7 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) if (sco) { sco->state = BT_CLOSED; - hci_proto_connect_cfm(sco, status); + hci_connect_cfm(sco, status); hci_conn_del(sco); } } @@ -1608,7 +1608,7 @@ static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1635,7 +1635,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1811,7 +1811,7 @@ static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1838,7 +1838,7 @@ static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { if (conn->state == BT_CONFIG) { - hci_proto_connect_cfm(conn, status); + hci_connect_cfm(conn, status); hci_conn_drop(conn); } } @@ -1873,7 +1873,7 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) if (sco) { sco->state = BT_CLOSED; - hci_proto_connect_cfm(sco, status); + hci_connect_cfm(sco, status); hci_conn_del(sco); } } @@ -2255,10 +2255,10 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_sco_setup(conn, ev->status); if (ev->status) { - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_del(conn); } else if (ev->link_type != ACL_LINK) - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); unlock: hci_dev_unlock(hdev); @@ -2366,7 +2366,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) &cp); } else { conn->state = BT_CONNECT2; - hci_proto_connect_cfm(conn, 0); + hci_connect_cfm(conn, 0); } } @@ -2501,7 +2501,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) &cp); } else { conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } } else { @@ -2629,12 +2629,12 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && (!test_bit(HCI_CONN_AES_CCM, &conn->flags) || conn->key_type != HCI_LK_AUTH_COMBINATION_P256)) { - hci_proto_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE); + hci_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE); hci_conn_drop(conn); goto unlock; } - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } else hci_encrypt_cfm(conn, ev->status, ev->encrypt); @@ -2707,7 +2707,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } @@ -3679,7 +3679,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, if (!hci_outgoing_auth_needed(hdev, conn)) { conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } @@ -3738,7 +3738,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, break; } - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); if (ev->status) hci_conn_del(conn); @@ -3849,7 +3849,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, if (!ev->status) conn->state = BT_CONNECTED; - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); hci_conn_drop(conn); } else { hci_auth_cfm(conn, ev->status); @@ -4512,7 +4512,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); - hci_proto_connect_cfm(conn, ev->status); + hci_connect_cfm(conn, ev->status); params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, conn->dst_type); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 424fcc5c4980..6e2c3bdda7d3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7252,13 +7252,16 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, return NULL; } -void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) +static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) { struct hci_dev *hdev = hcon->hdev; struct l2cap_conn *conn; struct l2cap_chan *pchan; u8 dst_type; + if (hcon->type != ACL_LINK && hcon->type != LE_LINK) + return; + BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); if (status) { @@ -7543,6 +7546,7 @@ drop: static struct hci_cb l2cap_cb = { .name = "L2CAP", + .connect_cfm = l2cap_connect_cfm, .security_cfm = l2cap_security_cfm, }; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 76321b546e84..3c2e36f94b65 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1083,9 +1083,13 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) return lm; } -void sco_connect_cfm(struct hci_conn *hcon, __u8 status) +static void sco_connect_cfm(struct hci_conn *hcon, __u8 status) { + if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) + return; + BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); + if (!status) { struct sco_conn *conn; @@ -1122,6 +1126,11 @@ drop: return 0; } +static struct hci_cb sco_cb = { + .name = "SCO", + .connect_cfm = sco_connect_cfm, +}; + static int sco_debugfs_show(struct seq_file *f, void *p) { struct sock *sk; @@ -1203,6 +1212,8 @@ int __init sco_init(void) BT_INFO("SCO socket layer initialized"); + hci_register_cb(&sco_cb); + if (IS_ERR_OR_NULL(bt_debugfs)) return 0; @@ -1222,6 +1233,8 @@ void __exit sco_exit(void) debugfs_remove(sco_debugfs); + hci_unregister_cb(&sco_cb); + bt_sock_unregister(BTPROTO_SCO); proto_unregister(&sco_proto); -- cgit v1.2.3 From 3a6d576be9fe02b0c3ffa89ef6eac048e14eec84 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Feb 2015 14:53:58 +0200 Subject: Bluetooth: Convert disconn_cfm to be triggered through hci_cb This patch moves all the disconn_cfm callbacks to be based on the hci_cb list. This means making l2cap_disconn_cfm private to l2cap_core.c and sco_conn_cb private to sco.c respectively. Since the hci_conn type filtering isn't done any more on the wrapper level the callbacks themselves need to check that they were passed a relevant type of connection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_event.c | 2 +- net/bluetooth/l2cap_core.c | 6 +++++- net/bluetooth/sco.c | 6 +++++- 4 files changed, 12 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e9206734e024..91ebb9cb31de 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1151,7 +1151,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev) list_for_each_entry_safe(c, n, &h->list, list) { c->state = BT_CLOSED; - hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); + hci_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); hci_conn_del(c); } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0b599129c64c..e9b17b585ee8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2444,7 +2444,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) type = conn->type; - hci_proto_disconn_cfm(conn, ev->reason); + hci_disconn_cfm(conn, ev->reason); hci_conn_del(conn); /* Re-enable advertising if necessary, since it might diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6e2c3bdda7d3..91c682846bcf 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7324,8 +7324,11 @@ int l2cap_disconn_ind(struct hci_conn *hcon) return conn->disc_reason; } -void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) +static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) { + if (hcon->type != ACL_LINK && hcon->type != LE_LINK) + return; + BT_DBG("hcon %p reason %d", hcon, reason); l2cap_conn_del(hcon, bt_to_errno(reason)); @@ -7547,6 +7550,7 @@ drop: static struct hci_cb l2cap_cb = { .name = "L2CAP", .connect_cfm = l2cap_connect_cfm, + .disconn_cfm = l2cap_disconn_cfm, .security_cfm = l2cap_security_cfm, }; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 3c2e36f94b65..b94c3151896e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1100,8 +1100,11 @@ static void sco_connect_cfm(struct hci_conn *hcon, __u8 status) sco_conn_del(hcon, bt_to_errno(status)); } -void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) +static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) { + if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) + return; + BT_DBG("hcon %p reason %d", hcon, reason); sco_conn_del(hcon, bt_to_errno(reason)); @@ -1129,6 +1132,7 @@ drop: static struct hci_cb sco_cb = { .name = "SCO", .connect_cfm = sco_connect_cfm, + .disconn_cfm = sco_disconn_cfm, }; static int sco_debugfs_show(struct seq_file *f, void *p) -- cgit v1.2.3 From 94d52dad9ef31e178ccc141dfd8feb84cccde581 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 19 Feb 2015 17:38:06 +0200 Subject: Bluetooth: Remove bogus check for pending mgmt Set HS command The command handler for Set HS doesn't use mgmt_pending_add() so we can never have a pending Set HS command that mgmt_pending_find() would return. This patch removes an unnecessary lookup for it in the set_ssp() handler function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1b528dea9844..cc67d19a7cb8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2116,8 +2116,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) goto failed; } - if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) || - mgmt_pending_find(MGMT_OP_SET_HS, hdev)) { + if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY); goto failed; -- cgit v1.2.3 From a2cb01de1cb1db05b946e0132aeecbb514c57024 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 19 Feb 2015 17:38:07 +0200 Subject: Bluetooth: Fix checking for pending Set SSP in Set HS handler Changing the HS setting requires that SSP is enabled, however so far the code only checked for the SSP flag but not a potentially ongoing Set SSP operation. This patch adds a check for a pending Set SSP command in the Set HS handler, and returns a 'busy' error if one is found. Signed-off-by: Johan Hedberg Signed-off-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 cc67d19a7cb8..3a1b537c9aa6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2175,6 +2175,12 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_dev_lock(hdev); + if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { + err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS, + MGMT_STATUS_BUSY); + goto unlock; + } + if (cp->val) { changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags); } else { -- cgit v1.2.3 From 39e3e74423a35bfc95b077fb65acaa00d1d39d64 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 20 Feb 2015 13:48:24 +0200 Subject: Bluetooth: Use hci_copy_identity_addr() helper for SMP chan creation The only reason the SMP code is essentially duplicating the hci_copy_identity_addr() function is that the helper returns the address type in the HCI format rather than the three-value format expected by l2cap_chan. This patch converts the SMP code to use the helper and then do a simple conversion from one address type to another. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c09a821f381d..b2803bd6e0d8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2951,24 +2951,14 @@ create_chan: l2cap_chan_set_defaults(chan); if (cid == L2CAP_CID_SMP) { - /* If usage of static address is forced or if the devices - * does not have a public address, then listen on the static - * address. - * - * In case BR/EDR has been disabled on a dual-mode controller - * and a static address has been configued, then listen on - * the static address instead. - */ - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY) || - (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && - bacmp(&hdev->static_addr, BDADDR_ANY))) { - bacpy(&chan->src, &hdev->static_addr); - chan->src_type = BDADDR_LE_RANDOM; - } else { - bacpy(&chan->src, &hdev->bdaddr); + u8 bdaddr_type; + + hci_copy_identity_address(hdev, &chan->src, &bdaddr_type); + + if (bdaddr_type == ADDR_LE_DEV_PUBLIC) chan->src_type = BDADDR_LE_PUBLIC; - } + else + chan->src_type = BDADDR_LE_RANDOM; } else { bacpy(&chan->src, &hdev->bdaddr); chan->src_type = BDADDR_BREDR; -- cgit v1.2.3 From 7129069e84056ba28954550beb208b2645863299 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 20 Feb 2015 13:26:23 +0200 Subject: Bluetooth: Rename hci_send_to_control to hci_send_to_channel The hci_send_to_control() can be made more general purpose with a small change of passing the desired HCI channel as a parameter to it. This allows using it for the monitor channel as well as e.g. 6lowpan in the future. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 9 +++++---- net/bluetooth/mgmt.c | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1d65c5be7c82..ba5d45f8aac1 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -183,12 +183,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb_copy); } -/* Send frame to control socket */ -void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) +/* Send frame to sockets with specific channel */ +void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, + struct sock *skip_sk) { struct sock *sk; - BT_DBG("len %d", skb->len); + BT_DBG("channel %u len %d", channel, skb->len); read_lock(&hci_sk_list.lock); @@ -202,7 +203,7 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) if (sk->sk_state != BT_BOUND) continue; - if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) + if (hci_pi(sk)->channel != channel) continue; nskb = skb_clone(skb, GFP_ATOMIC); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3a1b537c9aa6..d5d46e7676f1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -242,7 +243,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, /* Time stamp */ __net_timestamp(skb); - hci_send_to_control(skb, skip_sk); + hci_send_to_channel(HCI_CHANNEL_CONTROL, skb, skip_sk); kfree_skb(skb); return 0; -- cgit v1.2.3 From 03f310efd4b19ddc2cca15ae67f48295554adbfe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 20 Feb 2015 13:26:24 +0200 Subject: Bluetooth: Remove unnecessary queue_monitor_skb() function Now that there's the general purpose hci_send_to_channel() API it will do the exact same thing as queue_monitor_skb() when passed the monitor HCI channel. This patch removes queue_monitor_skb() and replaces any users of it with calls to hci_send_to_channel(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index ba5d45f8aac1..c73a61ce4893 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -217,34 +217,6 @@ void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, read_unlock(&hci_sk_list.lock); } -static void queue_monitor_skb(struct sk_buff *skb) -{ - struct sock *sk; - - BT_DBG("len %d", skb->len); - - read_lock(&hci_sk_list.lock); - - sk_for_each(sk, &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); -} - /* Send frame to monitor socket */ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) { @@ -291,7 +263,7 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) hdr->index = cpu_to_le16(hdev->id); hdr->len = cpu_to_le16(skb->len); - queue_monitor_skb(skb_copy); + hci_send_to_channel(HCI_CHANNEL_MONITOR, skb_copy, NULL); kfree_skb(skb_copy); } @@ -398,7 +370,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) skb = create_monitor_event(hdev, event); if (skb) { - queue_monitor_skb(skb); + hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, NULL); kfree_skb(skb); } } -- cgit v1.2.3 From 4cd3928a8bee83d86fb3865bb243ab2ff1dd0eb6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Feb 2015 10:11:13 +0200 Subject: Bluetooth: Update New CSRK event to match latest specification The 'master' parameter of the New CSRK event was recently renamed to 'type', with the old values kept for backwards compatibility as unauthenticated local/remote keys. This patch updates the code to take into account the two new (authenticated) values and ensures they get used based on the security level of the connection that the respective keys get distributed over. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- net/bluetooth/smp.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d5d46e7676f1..1e4635a3374d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6664,7 +6664,7 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type); - ev.key.master = csrk->master; + ev.key.type = csrk->type; memcpy(ev.key.val, csrk->val, sizeof(csrk->val)); mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b2803bd6e0d8..c91c19bfc0a8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1252,7 +1252,10 @@ static void smp_distribute_keys(struct smp_chan *smp) csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); if (csrk) { - csrk->master = 0x00; + if (hcon->sec_level > BT_SECURITY_MEDIUM) + csrk->type = MGMT_CSRK_LOCAL_AUTHENTICATED; + else + csrk->type = MGMT_CSRK_LOCAL_UNAUTHENTICATED; memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); } smp->slave_csrk = csrk; @@ -2352,7 +2355,10 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); if (csrk) { - csrk->master = 0x01; + if (conn->hcon->sec_level > BT_SECURITY_MEDIUM) + csrk->type = MGMT_CSRK_REMOTE_AUTHENTICATED; + else + csrk->type = MGMT_CSRK_REMOTE_UNAUTHENTICATED; memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; -- cgit v1.2.3 From 9391976a4da0d2a30abdb8d2704cfc7bf4bf9aab Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 19 Feb 2015 15:20:43 +0100 Subject: Bluetooth: make hci_test_bit's addr const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc5 warns about passing a const array to hci_test_bit which takes a non-const pointer: net/bluetooth/hci_sock.c: In function ‘hci_sock_sendmsg’: net/bluetooth/hci_sock.c:955:8: warning: passing argument 2 of ‘hci_test_bit’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-array-qualifiers] &hci_sec_filter.ocf_mask[ogf])) && ^ net/bluetooth/hci_sock.c:49:19: note: expected ‘void *’ but argument is of type ‘const __u32 (*)[4] {aka const unsigned int (*)[4]}’ static inline int hci_test_bit(int nr, void *addr) ^ So make 'addr' 'const void *'. Signed-off-by: Jiri Slaby Signed-off-by: Marcel Holtmann Cc: Gustavo Padovan Cc: Johan Hedberg --- net/bluetooth/hci_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c73a61ce4893..3f8f69239e41 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -46,9 +46,9 @@ struct hci_pinfo { unsigned short channel; }; -static inline int hci_test_bit(int nr, void *addr) +static inline int hci_test_bit(int nr, const void *addr) { - return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); + return *((const __u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); } /* Security filter */ -- cgit v1.2.3