|
@@ -32,7 +32,6 @@
|
|
|
#include "smp.h"
|
|
|
|
|
|
#define SMP_ALLOW_CMD(smp, code) set_bit(code, &smp->allow_cmd)
|
|
|
-#define SMP_DISALLOW_CMD(smp, code) clear_bit(code, &smp->allow_cmd)
|
|
|
|
|
|
#define SMP_TIMEOUT msecs_to_jiffies(30000)
|
|
|
|
|
@@ -949,20 +948,22 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (!smp)
|
|
|
return SMP_UNSPECIFIED;
|
|
|
|
|
|
+ /* We didn't start the pairing, so match remote */
|
|
|
+ auth = req->auth_req & AUTH_REQ_MASK;
|
|
|
+
|
|
|
if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) &&
|
|
|
- (req->auth_req & SMP_AUTH_BONDING))
|
|
|
+ (auth & SMP_AUTH_BONDING))
|
|
|
return SMP_PAIRING_NOTSUPP;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_REQ);
|
|
|
-
|
|
|
smp->preq[0] = SMP_CMD_PAIRING_REQ;
|
|
|
memcpy(&smp->preq[1], req, sizeof(*req));
|
|
|
skb_pull(skb, sizeof(*req));
|
|
|
|
|
|
- /* We didn't start the pairing, so match remote */
|
|
|
- auth = req->auth_req;
|
|
|
+ if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
|
|
|
+ sec_level = BT_SECURITY_MEDIUM;
|
|
|
+ else
|
|
|
+ sec_level = authreq_to_seclevel(auth);
|
|
|
|
|
|
- sec_level = authreq_to_seclevel(auth);
|
|
|
if (sec_level > conn->hcon->pending_sec_level)
|
|
|
conn->hcon->pending_sec_level = sec_level;
|
|
|
|
|
@@ -1003,7 +1004,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
|
|
|
struct l2cap_chan *chan = conn->smp;
|
|
|
struct smp_chan *smp = chan->data;
|
|
|
- u8 key_size, auth = SMP_AUTH_NONE;
|
|
|
+ u8 key_size, auth;
|
|
|
int ret;
|
|
|
|
|
|
BT_DBG("conn %p", conn);
|
|
@@ -1014,8 +1015,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (conn->hcon->role != HCI_ROLE_MASTER)
|
|
|
return SMP_CMD_NOTSUPP;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
|
|
|
-
|
|
|
skb_pull(skb, sizeof(*rsp));
|
|
|
|
|
|
req = (void *) &smp->preq[1];
|
|
@@ -1024,6 +1023,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (check_enc_key_size(conn, key_size))
|
|
|
return SMP_ENC_KEY_SIZE;
|
|
|
|
|
|
+ auth = rsp->auth_req & AUTH_REQ_MASK;
|
|
|
+
|
|
|
/* If we need MITM check that it can be acheived */
|
|
|
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
|
|
|
u8 method;
|
|
@@ -1044,11 +1045,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
*/
|
|
|
smp->remote_key_dist &= rsp->resp_key_dist;
|
|
|
|
|
|
- if ((req->auth_req & SMP_AUTH_BONDING) &&
|
|
|
- (rsp->auth_req & SMP_AUTH_BONDING))
|
|
|
- auth = SMP_AUTH_BONDING;
|
|
|
-
|
|
|
- auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
|
|
|
+ auth |= req->auth_req;
|
|
|
|
|
|
ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
|
|
|
if (ret)
|
|
@@ -1073,8 +1070,6 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (skb->len < sizeof(smp->pcnf))
|
|
|
return SMP_INVALID_PARAMS;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
|
|
|
-
|
|
|
memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
|
|
|
skb_pull(skb, sizeof(smp->pcnf));
|
|
|
|
|
@@ -1103,8 +1098,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (skb->len < sizeof(smp->rrnd))
|
|
|
return SMP_INVALID_PARAMS;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
|
|
|
-
|
|
|
memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
|
|
|
skb_pull(skb, sizeof(smp->rrnd));
|
|
|
|
|
@@ -1121,7 +1114,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
|
|
|
if (!key)
|
|
|
return false;
|
|
|
|
|
|
- if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated)
|
|
|
+ if (smp_ltk_sec_level(key) < sec_level)
|
|
|
return false;
|
|
|
|
|
|
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
|
|
@@ -1164,7 +1157,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
struct smp_cmd_pairing cp;
|
|
|
struct hci_conn *hcon = conn->hcon;
|
|
|
struct smp_chan *smp;
|
|
|
- u8 sec_level;
|
|
|
+ u8 sec_level, auth;
|
|
|
|
|
|
BT_DBG("conn %p", conn);
|
|
|
|
|
@@ -1174,7 +1167,13 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (hcon->role != HCI_ROLE_MASTER)
|
|
|
return SMP_CMD_NOTSUPP;
|
|
|
|
|
|
- sec_level = authreq_to_seclevel(rp->auth_req);
|
|
|
+ auth = rp->auth_req & AUTH_REQ_MASK;
|
|
|
+
|
|
|
+ if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
|
|
|
+ sec_level = BT_SECURITY_MEDIUM;
|
|
|
+ else
|
|
|
+ sec_level = authreq_to_seclevel(auth);
|
|
|
+
|
|
|
if (smp_sufficient_security(hcon, sec_level))
|
|
|
return 0;
|
|
|
|
|
@@ -1189,13 +1188,13 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
return SMP_UNSPECIFIED;
|
|
|
|
|
|
if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) &&
|
|
|
- (rp->auth_req & SMP_AUTH_BONDING))
|
|
|
+ (auth & SMP_AUTH_BONDING))
|
|
|
return SMP_PAIRING_NOTSUPP;
|
|
|
|
|
|
skb_pull(skb, sizeof(*rp));
|
|
|
|
|
|
memset(&cp, 0, sizeof(cp));
|
|
|
- build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
|
|
|
+ build_pairing_cmd(conn, &cp, NULL, auth);
|
|
|
|
|
|
smp->preq[0] = SMP_CMD_PAIRING_REQ;
|
|
|
memcpy(&smp->preq[1], &cp, sizeof(cp));
|
|
@@ -1293,7 +1292,6 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (skb->len < sizeof(*rp))
|
|
|
return SMP_INVALID_PARAMS;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO);
|
|
|
SMP_ALLOW_CMD(smp, SMP_CMD_MASTER_IDENT);
|
|
|
|
|
|
skb_pull(skb, sizeof(*rp));
|
|
@@ -1321,9 +1319,10 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
/* Mark the information as received */
|
|
|
smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_MASTER_IDENT);
|
|
|
if (smp->remote_key_dist & SMP_DIST_ID_KEY)
|
|
|
SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
|
|
|
+ else if (smp->remote_key_dist & SMP_DIST_SIGN)
|
|
|
+ SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
|
|
|
|
|
|
skb_pull(skb, sizeof(*rp));
|
|
|
|
|
@@ -1351,7 +1350,6 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
if (skb->len < sizeof(*info))
|
|
|
return SMP_INVALID_PARAMS;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
|
|
|
SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO);
|
|
|
|
|
|
skb_pull(skb, sizeof(*info));
|
|
@@ -1378,7 +1376,6 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
|
|
/* Mark the information as received */
|
|
|
smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO);
|
|
|
if (smp->remote_key_dist & SMP_DIST_SIGN)
|
|
|
SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
|
|
|
|
|
@@ -1434,8 +1431,6 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
/* Mark the information as received */
|
|
|
smp->remote_key_dist &= ~SMP_DIST_SIGN;
|
|
|
|
|
|
- SMP_DISALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
|
|
|
-
|
|
|
skb_pull(skb, sizeof(*rp));
|
|
|
|
|
|
hci_dev_lock(hdev);
|
|
@@ -1480,7 +1475,7 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
|
|
|
if (code > SMP_CMD_MAX)
|
|
|
goto drop;
|
|
|
|
|
|
- if (smp && !test_bit(code, &smp->allow_cmd))
|
|
|
+ if (smp && !test_and_clear_bit(code, &smp->allow_cmd))
|
|
|
goto drop;
|
|
|
|
|
|
/* If we don't have a context the only allowed commands are
|