summaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2008-07-14 20:13:50 +0200
committerMarcel Holtmann <marcel@holtmann.org>2008-07-14 20:13:50 +0200
commit40be492fe4fab829951681860c2bb26fa1d5fe4a (patch)
tree41b576692c2206c9a51e689f54170076ec95bc3a /net/bluetooth
parentf8558555f31e177e2644f3c8116801c3e5c29974 (diff)
downloadlinux-stable-40be492fe4fab829951681860c2bb26fa1d5fe4a.tar.gz
linux-stable-40be492fe4fab829951681860c2bb26fa1d5fe4a.tar.bz2
linux-stable-40be492fe4fab829951681860c2bb26fa1d5fe4a.zip
[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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_conn.c38
-rw-r--r--net/bluetooth/hci_sock.c18
-rw-r--r--net/bluetooth/l2cap.c14
-rw-r--r--net/bluetooth/rfcomm/core.c3
4 files changed, 51 insertions, 22 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 6f22533e7656..0d4b8aeb8e09 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -379,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn)
{
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 @@ int hci_conn_encrypt(struct hci_conn *conn)
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 @@ int hci_conn_encrypt(struct hci_conn *conn)
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 @@ int hci_conn_change_link_key(struct hci_conn *conn)
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 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
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 747fabd735d2..d62579b67959 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -193,19 +193,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
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 inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
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 252264062f59..30ad59b717d5 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2150,7 +2150,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
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 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
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 e7a6a03cea37..e56bcfc35a49 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1969,7 +1969,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
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))