Dear all,
I am trying to develop an application on Nordic nrf52840_dongle utilizing Bluetooth and Nordic Led Button Service. The application running on the dongle is supposed to notify button click on USB dongle and activate LED diode using Nordic Android Blinky application or nRF Connect application. Such a logic is very well working, but I wanted to implement sort of a security that not everyone is able to connect to the dongle (peripheral) and let the LED flash or have press button results available, so I wanted to base my secure connection on Zephyr example:
samples/bluetooth/peripheral_sc_only
Since my dongle is headless (I do not know any other better way, how to pair one headless device and Android phone) and I am a newbie in Zephyr, the only way which came to my mind was to set up fixed key.
When initiating the connection to the peripheral dongle pressing 'Connect' button in listed devices within nRF Connect window,the Android application correctly asks for a key and it gets paired and successfully connected when correct passkey is entered and disconnected when incorrect passkey is entered. The problem arises when I press connect button in nRF Connect application, dialog with pairing request pops up and I cancel the dialog.
The application gets connected to the dongle automatically and stays connected further if browsing services and tapping on their values, practically bypassing any security code I have added.
When I enter incorrect password in nRF Connect passkey input dialog, a callback called 'pairing_failed' is triggered, but when I only cancel the pairing request before the passkey input dialog pops up, no 'pairing_failed' is triggered, therefore I cannot disconnect explicitly within this callback which could potentially stop connecting automatically, but I wonder how it could even connect.
When being incorrectly connected it also somehow tries to automatically disconnect when cancelling the pairing pop up dialog, but when I click on any dongle service within the android nRF Connect app, the applications stays connected, but when I do not touch anything in the nRF Connect app, it automatically disconnects after few seconds, but it clearly shows on nRF Connect dongle TAB Bar: 'connected'. How could it even connect when I did not enter any passkey nor I did not even even confirm the pairing process, it was cancelled even before the dialog with passkey entering was initiated.
Could anyone help me with this issue?
Maybe there is a callback upon rejection of such a dialog, but I do not know where.
If possible, could anyone help me what is the recommended way to implement pairing with single headless BT device so far I cannot visualize the generated passkey on my peripheral devices in case of using anything more sophisticated than fixed passkey. The same way probably Bluetooth mouse and keyboards do, no way to enter any security passkey and their are secure and probably get paired automatically upon start.
I am enclosing modified 'samples/bluetooth/peripheral_sc_only' example.
I know it is pure Zephyr code, but since Nordic SDK is also based on Zephyr and maybe it relates to nRF Connect as well, it could potentially cause the same issue, but I guess I miss some important points in my code.
Thank you all
Ivo
/* main.c - Application main entry point */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
};
static void connected(struct bt_conn *conn, uint8_t err) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof (addr));
if (err) {
printk("Failed to connect to %s (%u)\n", addr, err);
return;
}
printk("Connected %s\n", addr);
if (bt_conn_set_security(conn, BT_SECURITY_L4)) {
printk("Failed to set security\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof (addr));
printk("Disconnected from %s (reason 0x%02x)\n", addr, reason);
}
static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
const bt_addr_le_t *identity) {
char addr_identity[BT_ADDR_LE_STR_LEN];
char addr_rpa[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(identity, addr_identity, sizeof (addr_identity));
bt_addr_le_to_str(rpa, addr_rpa, sizeof (addr_rpa));
printk("Identity resolved %s -> %s\n", addr_rpa, addr_identity);
}
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof (addr));
if (!err) {
printk("Security changed: %s level %u\n", addr, level);
} else {
printk("Security failed: %s level %u err %d\n", addr, level,
err);
}
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.identity_resolved = identity_resolved,
.security_changed = security_changed,
};
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof (addr));
printk("Passkey for %s: %06u\n", addr, passkey);
}
static void auth_cancel(struct bt_conn *conn) {
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof (addr));
printk("Pairing cancelled: %s\n", addr);
}
static void pairing_complete(struct bt_conn *conn, bool bonded) {
printk("Pairing Complete\n");
}
static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) {
printk("Pairing Failed (%d). Disconnecting.\n", reason);
bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL);
}
static struct bt_conn_auth_cb auth_cb_display = {
.passkey_display = auth_passkey_display,
.passkey_entry = NULL,
.cancel = auth_cancel,
.pairing_confirm = NULL,
};
static struct bt_conn_auth_info_cb auth_cb_info = {
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed,
};
void main(void) {
int err;
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
bt_conn_auth_cb_register(&auth_cb_display);
bt_conn_auth_info_cb_register(&auth_cb_info);
unsigned int passkey = 555555;
bt_passkey_set(passkey);
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
printk("Advertising successfully started\n");
}