[Bluetooth] Export details about authentication requirements
With the Simple Pairing support, the authentication requirements are
an explicit setting during the bonding process. Track and enforce the
requirements and allow higher layers like L2CAP and RFCOMM to increase
them if needed.
This patch introduces a new IOCTL that allows to query the current
authentication requirements. It is also possible to detect Simple
Pairing support in the kernel this way.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 6f22533..0d4b8aeb 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -379,13 +379,21 @@
{
BT_DBG("conn %p", conn);
+ if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
+ if (!(conn->auth_type & 0x01)) {
+ conn->auth_type = HCI_AT_GENERAL_BONDING_MITM;
+ conn->link_mode &= ~HCI_LM_AUTH;
+ }
+ }
+
if (conn->link_mode & HCI_LM_AUTH)
return 1;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_auth_requested cp;
cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
+ hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
+ sizeof(cp), &cp);
}
return 0;
}
@@ -397,7 +405,7 @@
BT_DBG("conn %p", conn);
if (conn->link_mode & HCI_LM_ENCRYPT)
- return 1;
+ return hci_conn_auth(conn);
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;
@@ -406,7 +414,8 @@
struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1;
- hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+ hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
+ sizeof(cp), &cp);
}
return 0;
}
@@ -420,7 +429,8 @@
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_change_conn_link_key cp;
cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
+ hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
+ sizeof(cp), &cp);
}
return 0;
}
@@ -624,3 +634,23 @@
return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
}
+
+int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
+{
+ struct hci_auth_info_req req;
+ struct hci_conn *conn;
+
+ if (copy_from_user(&req, arg, sizeof(req)))
+ return -EFAULT;
+
+ hci_dev_lock_bh(hdev);
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
+ if (conn)
+ req.type = conn->auth_type;
+ hci_dev_unlock_bh(hdev);
+
+ if (!conn)
+ return -ENOENT;
+
+ return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
+}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 747fabd..d62579b 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -193,19 +193,11 @@
return 0;
- case HCISETSECMGR:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (arg)
- set_bit(HCI_SECMGR, &hdev->flags);
- else
- clear_bit(HCI_SECMGR, &hdev->flags);
-
- return 0;
-
case HCIGETCONNINFO:
- return hci_get_conn_info(hdev, (void __user *)arg);
+ return hci_get_conn_info(hdev, (void __user *) arg);
+
+ case HCIGETAUTHINFO:
+ return hci_get_auth_info(hdev, (void __user *) arg);
default:
if (hdev->ioctl)
@@ -217,7 +209,7 @@
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
- void __user *argp = (void __user *)arg;
+ void __user *argp = (void __user *) arg;
int err;
BT_DBG("cmd %x arg %lx", cmd, arg);
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 2522640..30ad59b 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2150,7 +2150,7 @@
static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
{
struct l2cap_chan_list *l;
- struct l2cap_conn *conn = conn = hcon->l2cap_data;
+ struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_conn_rsp rsp;
struct sock *sk;
int result;
@@ -2165,11 +2165,17 @@
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+
bh_lock_sock(sk);
- if (sk->sk_state != BT_CONNECT2 ||
- (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
- (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) {
+ if (sk->sk_state != BT_CONNECT2) {
+ bh_unlock_sock(sk);
+ continue;
+ }
+
+ if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
+ !(hcon->link_mode & HCI_LM_ENCRYPT)) {
bh_unlock_sock(sk);
continue;
}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index e7a6a03..e56bcfc 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1969,7 +1969,8 @@
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
- if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE))
+ if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
+ !(conn->link_mode & HCI_LM_ENCRYPT) && !status)
continue;
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))