diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 377379b8f6c..2ab6ba97011 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -384,12 +384,122 @@ void bt_conn_cb_register(struct bt_conn_cb *cb); /** Authenticated pairing callback structure */ struct bt_conn_auth_cb { + /** @brief Display a passkey to the user. + * + * When called the application is expected to display the given + * passkey to the user, with the expectation that the passkey will + * then be entered on the peer device. The passkey will be in the + * range of 0 - 999999, and is expected to be padded with zeroes so + * that six digits are always shown. E.g. the value 37 should be + * shown as 000037. + * + * This callback may be set to NULL, which means that the local + * device lacks the ability do display a passkey. If set + * to non-NULL the cancel callback must also be provided, since + * this is the only way the application can find out that it should + * stop displaying the passkey. + * + * @param conn Connection where pairing is currently active. + * @param passkey Passkey to show to the user. + */ void (*passkey_display)(struct bt_conn *conn, unsigned int passkey); + + /** @brief Request the user to enter a passkey. + * + * When called the user is expected to enter a passkey. The passkey + * must be in the range of 0 - 999999, and should be expected to + * be zero-padded, as that's how the peer device will typically be + * showing it (e.g. 37 would be shown as 000037). + * + * Once the user has entered the passkey its value should be given + * to the stack using the bt_conn_auth_passkey_entry() API. + * + * This callback may be set to NULL, which means that the local + * device lacks the ability to enter a passkey. If set to non-NULL + * the cancel callback must also be provided, since this is the + * only way the application can find out that it should stop + * requesting the user to enter a passkey. + * + * @param conn Connection where pairing is currently active. + */ void (*passkey_entry)(struct bt_conn *conn); + + /** @brief Request the user to confirm a passkey. + * + * When called the user is expected to confirm that the given + * passkey is also shown on the peer device.. The passkey will + * be in the range of 0 - 999999, and should be zero-padded to + * always be six digits (e.g. 37 would be shown as 000037). + * + * Once the user has confirmed the passkey to match, the + * bt_conn_auth_passkey_confirm() API should be called. If the + * user concluded that the passkey doesn't match the + * bt_conn_auth_cancel() API should be called. + * + * This callback may be set to NULL, which means that the local + * device lacks the ability to confirm a passkey. If set to non-NULL + * the cancel callback must also be provided, since this is the + * only way the application can find out that it should stop + * requesting the user to confirm a passkey. + * + * @param conn Connection where pairing is currently active. + * @param passkey Passkey to be confirmed. + */ void (*passkey_confirm)(struct bt_conn *conn, unsigned int passkey); + + /** @brief Cancel the ongoing user request. + * + * This callback will be called to notify the application that it + * should cancel any previous user request (passkey display, entry + * or confirmation). + * + * This may be set to NULL, but must always be provided whenever the + * passkey_display, passkey_entry passkey_confirm or pairing_confirm + * callback has been provided. + * + * @param conn Connection where pairing is currently active. + */ void (*cancel)(struct bt_conn *conn); + + /** @brief Request confirmation for an incoming pairing. + * + * This callback will be called to confirm an incoming pairing + * request where none of the other user callbacks is applicable. + * + * If the user decides to accept the pairing the + * bt_conn_auth_pairing_confirm() API should be called. If the + * user decides to reject the pairing the bt_conn_auth_cancel() API + * should be called. + * + * This callback may be set to NULL, which means that the local + * device lacks the ability to confirm a pairing request. If set + * to non-NULL the cancel callback must also be provided, since + * this is the only way the application can find out that it should + * stop requesting the user to confirm a pairing request. + * + * @param conn Connection where pairing is currently active. + */ void (*pairing_confirm)(struct bt_conn *conn); + #if defined(CONFIG_BT_BREDR) + /** @brief Request the user to enter a passkey. + * + * This callback will be called for a BR/EDR (Bluetooth Classic) + * connection where pairing is being performed. Once called the + * user is expected to enter a PIN code with a length between + * 1 and 16 digits. If the @a highsec parameter is set to true + * the PIN code must be 16 digits long. + * + * Once entered, the PIN code should be given to the stack using + * the bt_conn_auth_pincode_entry() API. + * + * This callback may be set to NULL, however in that case pairing + * over BR/EDR will not be possible. If provided, the cancel + * callback must be provided as well. + * + * @param conn Connection where pairing is currently active. + * @param highsec true if 16 digit PIN is required. + */ void (*pincode_entry)(struct bt_conn *conn, bool highsec); #endif @@ -412,8 +522,8 @@ struct bt_conn_auth_cb { /** @brief Register authentication callbacks. * - * Register callbacks to handle authenticated pairing. Passing NULL unregisters - * previous callbacks structure. + * Register callbacks to handle authenticated pairing. Passing NULL + * unregisters a previous callbacks structure. * * @param cb Callback struct. * diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 33835894ddb..b49b2986e46 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -1951,15 +1951,23 @@ int bt_conn_auth_cb_register(const struct bt_conn_auth_cb *cb) return 0; } - /* cancel callback should always be provided */ - if (!cb->cancel) { - return -EINVAL; - } - if (bt_auth) { return -EALREADY; } + /* The cancel callback must always be provided if the app provides + * interactive callbacks. + */ + if (!cb->cancel && + (cb->passkey_display || cb->passkey_entry || cb->passkey_confirm || +#if defined(CONFIG_BT_BREDR) + cb->pincode_entry || +#endif + cb->pairing_confirm)) { + return -EINVAL; + } + + bt_auth = cb; return 0; } diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 4e575c63799..eb6f52c4feb 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -100,6 +100,7 @@ enum { SMP_FLAG_DHKEY_PENDING, /* if waiting for local DHKey */ SMP_FLAG_DHKEY_SEND, /* if should generate and send DHKey Check */ SMP_FLAG_USER, /* if waiting for user input */ + SMP_FLAG_DISPLAY, /* if display_passkey() callback was called */ SMP_FLAG_BOND, /* if bonding */ SMP_FLAG_SC_DEBUG_KEY, /* if Secure Connection are using debug key */ SMP_FLAG_SEC_REQ, /* if Security Request was sent/received */ @@ -2591,6 +2592,8 @@ static u8_t smp_pairing_confirm(struct bt_smp *smp, struct net_buf *buf) BT_DBG(""); + atomic_clear_bit(smp->flags, SMP_FLAG_DISPLAY); + memcpy(smp->pcnf, req->val, sizeof(smp->pcnf)); if (IS_ENABLED(CONFIG_BT_CENTRAL) && @@ -2969,14 +2972,11 @@ static u8_t smp_pairing_failed(struct bt_smp *smp, struct net_buf *buf) */ ARG_UNUSED(req); - switch (smp->method) { - case PASSKEY_INPUT: - case PASSKEY_DISPLAY: - case PASSKEY_CONFIRM: - bt_auth->cancel(conn); - break; - default: - break; + if (atomic_test_and_clear_bit(smp->flags, SMP_FLAG_USER) || + atomic_test_and_clear_bit(smp->flags, SMP_FLAG_DISPLAY)) { + if (bt_auth && bt_auth->cancel) { + bt_auth->cancel(conn); + } } /* @@ -3230,6 +3230,7 @@ static u8_t display_passkey(struct bt_smp *smp) smp->passkey %= 1000000; smp->passkey_round = 0; + atomic_set_bit(smp->flags, SMP_FLAG_DISPLAY); bt_auth->passkey_display(smp->chan.chan.conn, smp->passkey); smp->passkey = sys_cpu_to_le32(smp->passkey);