Bluetooth: Introduce force_bredr_smp debugfs option for testing

Testing cross-transport pairing that starts on BR/EDR is only valid when
using a controller with BR/EDR Secure Connections. Devices will indicate
this by providing BR/EDR SMP fixed channel over L2CAP. To allow testing
of this feature on Bluetooth 4.0 controller or controllers without the
BR/EDR Secure Connections features, introduce a force_bredr_smp debugfs
option that allows faking the required AES connection.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Marcel Holtmann 2014-12-31 14:43:16 -08:00
parent e8768f9715
commit 300acfdec9
3 changed files with 76 additions and 5 deletions

View File

@ -174,6 +174,7 @@ enum {
HCI_DUT_MODE,
HCI_FORCE_SC,
HCI_FORCE_LESC,
HCI_FORCE_BREDR_SMP,
HCI_FORCE_STATIC_ADDR,
};

View File

@ -6968,7 +6968,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
if (test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags) &&
(bredr_sc_enabled(hcon->hdev) ||
test_bit(HCI_FORCE_LESC, &hcon->hdev->dbg_flags)))
test_bit(HCI_FORCE_BREDR_SMP, &hcon->hdev->dbg_flags)))
conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR;
mutex_init(&conn->ident_lock);

View File

@ -20,6 +20,7 @@
SOFTWARE IS DISCLAIMED.
*/
#include <linux/debugfs.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <crypto/b128ops.h>
@ -1675,7 +1676,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
if (conn->hcon->type == ACL_LINK) {
/* We must have a BR/EDR SC link */
if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) &&
!test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
!test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags))
return SMP_CROSS_TRANSP_NOT_ALLOWED;
set_bit(SMP_FLAG_SC, &smp->flags);
@ -2738,7 +2739,7 @@ static void bredr_pairing(struct l2cap_chan *chan)
/* BR/EDR must use Secure Connections for SMP */
if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) &&
!test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
!test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags))
return;
/* If our LE support is not enabled don't do anything */
@ -2976,6 +2977,66 @@ static void smp_del_chan(struct l2cap_chan *chan)
l2cap_chan_put(chan);
}
static ssize_t force_bredr_smp_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags) ? 'Y': 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t force_bredr_smp_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[32];
size_t buf_size = min(count, (sizeof(buf)-1));
bool enable;
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = '\0';
if (strtobool(buf, &enable))
return -EINVAL;
if (enable == test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags))
return -EALREADY;
if (enable) {
struct l2cap_chan *chan;
chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR);
if (IS_ERR(chan))
return PTR_ERR(chan);
hdev->smp_bredr_data = chan;
} else {
struct l2cap_chan *chan;
chan = hdev->smp_bredr_data;
hdev->smp_bredr_data = NULL;
smp_del_chan(chan);
}
change_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags);
return count;
}
static const struct file_operations force_bredr_smp_fops = {
.open = simple_open,
.read = force_bredr_smp_read,
.write = force_bredr_smp_write,
.llseek = default_llseek,
};
int smp_register(struct hci_dev *hdev)
{
struct l2cap_chan *chan;
@ -2988,9 +3049,18 @@ int smp_register(struct hci_dev *hdev)
hdev->smp_data = chan;
if (!lmp_sc_capable(hdev) &&
!test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
/* If the controller does not support BR/EDR Secure Connections
* feature, then the BR/EDR SMP channel shall not be present.
*
* To test this with Bluetooth 4.0 controllers, create a debugfs
* switch that allows forcing BR/EDR SMP support and accepting
* cross-transport pairing on non-AES encrypted connections.
*/
if (!lmp_sc_capable(hdev)) {
debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs,
hdev, &force_bredr_smp_fops);
return 0;
}
chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR);
if (IS_ERR(chan)) {