Bluetooth: SMP: Fix SMP context init when sending security request

The code was not doing the right thing when we as peripheral would
send a security request to the central. First of all, the SEQ_REQ flag
was getting cleared by the pairing request handler, resulting in
pairing_confirm() callbacks for no reason. Secondly, the behavior in
encrypt_change() was not utilizing the smp_reset() helper as it should
have done.

Fix the situation by calling smp_init() when sending a security
request, and detect that this has been done when receiving a pairing
request. Also do the appropriate cleanup if the result is an encrypt
change instead of a pairing request (in case we were already paired
with the peer).

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2018-07-31 13:28:51 +03:00 committed by Johan Hedberg
commit ef70fc85a9

View file

@ -2311,6 +2311,10 @@ int bt_smp_send_security_req(struct bt_conn *conn)
return -EINVAL; return -EINVAL;
} }
if (smp_init(smp) != 0) {
return -ENOBUFS;
}
req_buf = smp_create_pdu(conn, BT_SMP_CMD_SECURITY_REQUEST, req_buf = smp_create_pdu(conn, BT_SMP_CMD_SECURITY_REQUEST,
sizeof(*req)); sizeof(*req));
if (!req_buf) { if (!req_buf) {
@ -2323,7 +2327,8 @@ int bt_smp_send_security_req(struct bt_conn *conn)
/* SMP timer is not restarted for SecRequest so don't use smp_send */ /* SMP timer is not restarted for SecRequest so don't use smp_send */
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, req_buf); bt_l2cap_send(conn, BT_L2CAP_CID_SMP, req_buf);
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_FAIL); atomic_set_bit(smp->flags, SMP_FLAG_SEC_REQ);
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_REQ);
return 0; return 0;
} }
@ -2332,7 +2337,6 @@ static u8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
{ {
struct bt_smp_pairing *req = (void *)buf->data; struct bt_smp_pairing *req = (void *)buf->data;
struct bt_smp_pairing *rsp; struct bt_smp_pairing *rsp;
int ret;
BT_DBG(""); BT_DBG("");
@ -2341,9 +2345,15 @@ static u8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
return BT_SMP_ERR_ENC_KEY_SIZE; return BT_SMP_ERR_ENC_KEY_SIZE;
} }
ret = smp_init(smp); /* If we already sent a security request then the SMP context
if (ret) { * is already initialized.
return ret; */
if (!atomic_test_bit(smp->flags, SMP_FLAG_SEC_REQ)) {
int ret = smp_init(smp);
if (ret) {
return ret;
}
} }
/* Store req for later use */ /* Store req for later use */
@ -3584,22 +3594,17 @@ static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan,
return; return;
} }
if (!atomic_test_and_clear_bit(smp->flags, SMP_FLAG_ENC_PENDING)) {
return;
}
/* We were waiting for encryption but with no pairing in progress. /* We were waiting for encryption but with no pairing in progress.
* This can happen if paired slave sent Security Request and we * This can happen if paired slave sent Security Request and we
* enabled encryption. * enabled encryption.
*
* Since it is possible that slave might sent another Security Request
* eg with different AuthReq we should allow it.
*/ */
if (!atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) { if (!atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) {
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SECURITY_REQUEST); smp_reset(smp);
return; return;
} }
atomic_clear_bit(smp->flags, SMP_FLAG_ENC_PENDING);
/* derive BR/EDR LinkKey if supported by both sides */ /* derive BR/EDR LinkKey if supported by both sides */
if (atomic_test_bit(smp->flags, SMP_FLAG_SC)) { if (atomic_test_bit(smp->flags, SMP_FLAG_SC)) {
if ((smp->local_dist & BT_SMP_DIST_LINK_KEY) && if ((smp->local_dist & BT_SMP_DIST_LINK_KEY) &&