SMP — Usage Scenarios#
WiSeConnect BLE example projects under examples/snippets/ble/<example_folder>/ show SMP (pairing, passkey, encryption, LTK) flows. Each scenario below states when to use it and gives a compact implementation example: #include lines as in the SDK, a one-line // caption, then the API sequence. Non-essential branches are folded to //.... Full sources live under wiseconnect/examples/snippets/ble/ relative to the WiSeConnect SDK content root; the same tree is published in the Silicon Labs wiseconnect GitHub repository (WiseConnect SDK).
Related: BLE usage scenarios hub, SMP overview, Pairing and bonding, BLE initialization and configuration, Debugging and error handling.
Register SMP Callbacks#
When to Use#
After wireless/BLE stack initialization, register SMP event handlers before initiating pairing or before a peer can start pairing on an established link.
Register GAP (and GATT, if used) callbacks in the same bring-up sequence; pairing is driven from the application task after connection events (see BLE usage scenarios hub — Application task and BLE event handling).
Pass
NULLonly for slots your application does not use.
Implementation Example#
rsi_ble_smp_register_callbacks() takes eleven parameters (WiSeConnect rsi_ble_apis.h). Pass NULL only for slots your application does not use. A non-NULL argument must be a function pointer type-compatible with that position’s callback typedef (parameter and return types only; the function identifier is not specified by the API). Snippet identifiers follow ble_secureconnection and are illustrative. ble_secureconnection passes NULL for the tenth and eleventh callbacks; the example below uses named handlers for those slots. The tenth parameter reuses rsi_ble_on_smp_response_t for the client SMP response callback; the eleventh uses rsi_ble_on_sc_method_t (Register Callbacks).
#include "rsi_ble_apis.h"
// ble_secureconnection/app.c — SMP callback registration
rsi_ble_smp_register_callbacks(
rsi_ble_on_smp_request, // SMP request — NULL if unused
rsi_ble_on_smp_response, // SMP response — NULL if unused
rsi_ble_on_smp_passkey, // legacy passkey — NULL if unused
rsi_ble_on_smp_failed, // pairing failed — NULL if unused
rsi_ble_on_encrypt_started, // encryption started — NULL if unused
rsi_ble_on_smp_passkey_display, // passkey display — NULL if unused
rsi_ble_on_sc_passkey, // Secure Connections passkey — NULL if unused
rsi_ble_on_le_ltk_req_event, // LTK request — NULL if unused
rsi_ble_on_le_security_keys, // security keys — NULL if unused
rsi_ble_on_cli_smp_response, // client SMP response — NULL if unused
rsi_ble_on_sc_method); // SC pairing method — NULL if unusedNote: Parameter order matches the WiSeConnect API. See Register Callbacks and Callbacks Declarations. Pairing flows also require
rsi_ble_gap_register_callbacks()(andrsi_ble_gatt_register_callbacks()when using GATT).
Typical Use Case 1: Pairing — Just Works, Passkey, Numeric Comparison#
When to Use#
After GAP connection, the application must complete SMP pairing before relying on encrypted attributes or MITM-protected methods.
Pairing method (Just Works, Passkey Entry, Numeric Comparison, Out-of-Band) follows IO capabilities, authentication requirements (
MITM), and LE Secure Connections support on both sides. Configure capabilities withrsi_ble_set_smp_pairing_cap_data()when you need explicit control; otherwise the stack uses defaults consistent with your build. See Pairing methods and Pairing process.Out-of-band (OOB) pairing is not supported; attempts return
0x4B02(SMP OOB not available). See Pairing and bonding — OOB.
Implementation Example#
Step 1: Initiate Pairing (Peripheral After Connect)#
ble_secureconnection advertises as connectable; on RSI_BLE_CONN_EVENT it calls rsi_ble_smp_pair_request() when pairing data is not yet available. The second and third arguments are io_capability and mitm_req (see GAP — rsi_ble_smp_pair_request). RSI_BLE_SMP_IO_CAPABILITY is 0x00 in that example; MITM_REQ is 0x01. Values must match your product’s security policy.
| Meaning |
|---|---|
| Display Only |
| Display Yes/No |
| Keyboard Only |
| No Input No Output |
| Meaning |
|---|---|
| MITM disabled |
| MITM enabled |
#include "rsi_ble_apis.h"
// ble_secureconnection/app.c — RSI_BLE_CONN_EVENT (excerpt)
if (!pairing_info_available) {
status = rsi_ble_smp_pair_request(remote_dev_address, RSI_BLE_SMP_IO_CAPABILITY, MITM_REQ);
if (status != RSI_SUCCESS) {
return;
}
}Step 2: Respond to Peer-Driven SMP (Request / Response)#
On a peer Security Request, the stack invokes rsi_ble_on_smp_request and the application responds with rsi_ble_smp_pair_request(). On a peer SMP Pairing Request, the stack invokes rsi_ble_on_smp_response and the application responds with rsi_ble_smp_pair_response(). Use the same remote_dev_address, io_capability, and mitm_req as in the SDK example.
// RSI_BLE_SMP_REQ_EVENT — ble_secureconnection/app.c (excerpt)
pairing_info_available = 0;
status = rsi_ble_smp_pair_request(remote_dev_address, RSI_BLE_SMP_IO_CAPABILITY, MITM_REQ);
// RSI_BLE_SMP_RESP_EVENT — ble_secureconnection/app.c (excerpt)
pairing_info_available = 0;
status = rsi_ble_smp_pair_response(remote_dev_address, RSI_BLE_SMP_IO_CAPABILITY, MITM_REQ);Step 3: Pairing Method on the Link (Just Works vs Passkey Paths)#
After rsi_ble_smp_pair_request() / rsi_ble_smp_pair_response() (Steps 1–2), the stack selects the pairing method from both sides’ IO capability and MITM settings. Just Works is not a separate API sequence: if the negotiated method is Just Works, the stack completes pairing without RSI_BLE_SMP_PASSKEY_EVENT, RSI_BLE_SC_PASSKEY_EVENT, or passkey-display events—you only run Steps 1–2 and wait for encryption / completion callbacks.
Passkey Entry: When the stack raises RSI_BLE_SMP_PASSKEY_EVENT, supply the passkey with rsi_ble_smp_passkey() (example uses RSI_BLE_SMP_PASSKEY from ble_config.h / app.c).
LE Secure Connections (rsi_ble_on_sc_passkey): rsi_ble_on_sc_passkey receives rsi_bt_event_sc_passkey_t (including passkey). Handle the value in product UI (Numeric Comparison and Passkey Entry both use this passkey path under LE SC), then send it with rsi_ble_smp_passkey(). Use rsi_ble_on_sc_method when you must distinguish Just Works from passkey-related SC methods (Callbacks Declarations).
// RSI_BLE_SMP_PASSKEY_EVENT — ble_secureconnection/app.c (excerpt)
status = rsi_ble_smp_passkey(remote_dev_address, RSI_BLE_SMP_PASSKEY);
// rsi_ble_on_sc_passkey — callback (excerpt): numeric_value = sc_passkey->passkey; then task path:
status = rsi_ble_smp_passkey(remote_dev_address, numeric_value);Passkey display (peer shows passkey): Handle RSI_BLE_SMP_PASSKEY_DISPLAY_EVENT, read rsi_bt_event_smp_passkey_display_t (for example passkey and dev_addr) for UI/logging; completion is method-specific.
Step 4: Pairing Failure#
On rsi_ble_on_smp_failed, clear application pairing state (example sets pairing_info_available = 0) and handle RSI_BLE_SMP_FAILED_EVENT in the task. Use rsi_ble_smp_pair_failed() to send an SMP Pairing Failed PDU with a reason code when the application must reject pairing (see GAP).
SDK Example Project#
Goal | Example folder |
|---|---|
Pairing + encryption + SC passkey |
|
See also: Pairing and bonding, GAP — usage scenarios — Typical Use Case 1 (connect then pair).
Typical Use Case 2: Bonding and Reconnection#
When to Use#
After successful pairing, the application may persist LTK, EDIV, Rand, and identity keys for reconnection without repeating the full pairing UI.
On reconnect, the controller may issue an LTK request; the application must answer with
rsi_ble_ltk_req_reply()using stored material or a negative reply (then re-pair). The stack does not automatically persist bonding data in non-volatile storage; that is application responsibility. See Bonding.
Implementation Example#
Step 1: Mark Pairing Complete When Encryption Starts#
ble_secureconnection sets pairing_info_available = 1 on RSI_BLE_ENCRYPT_STARTED_EVENT after rsi_ble_on_encrypt_started copies rsi_bt_event_encryption_enabled_t into encrypt_keys.
// RSI_BLE_ENCRYPT_STARTED_EVENT — ble_secureconnection/app.c (excerpt)
pairing_info_available = 1;
rsi_ble_app_clear_event(RSI_BLE_ENCRYPT_STARTED_EVENT);Step 2: LTK Request on Reconnect#
rsi_ble_on_le_ltk_req_event copies rsi_bt_event_le_ltk_request_t into ble_ltk_req and raises RSI_BLE_LTK_REQ_EVENT. If pairing_info_available is set, reply with rsi_ble_ltk_req_reply() using encrypt_keys.localltk and flags derived from encrypt_keys (example uses (1 | encrypt_keys.enabled | (encrypt_keys.sc_enable << 7))). If keys are not available, reply with rsi_ble_ltk_req_reply(remote_dev_address, 0, NULL) and restart pairing per your policy.
// RSI_BLE_LTK_REQ_EVENT — ble_secureconnection/app.c (excerpt)
if (pairing_info_available) {
status = rsi_ble_ltk_req_reply(remote_dev_address,
(1 | encrypt_keys.enabled | (encrypt_keys.sc_enable << 7)),
encrypt_keys.localltk);
} else {
status = rsi_ble_ltk_req_reply(remote_dev_address, 0, NULL);
// restart pairing: rsi_ble_smp_pair_request(...)
}Step 3: Capture Security Keys for Storage#
rsi_ble_on_le_security_keys receives rsi_bt_event_le_security_keys_t (example logs remote_ediv). Copy fields to secure application storage if you implement bonding across power cycles.
// RSI_BLE_SECURITY_KEYS_EVENT — ble_iop_test/app.c (excerpt)
memcpy(ble_dev_ltk_list[ix].remote_rand, le_sec_keys->remote_rand, 8);
memcpy(ble_dev_ltk_list[ix].remote_ltk, le_sec_keys->remote_ltk, 16);
memcpy(ble_dev_ltk_list[ix].local_irk, le_sec_keys->local_irk, 16);
memcpy(ble_dev_ltk_list[ix].peer_irk, le_sec_keys->remote_irk, 16);
ble_dev_ltk_list[ix].remote_ediv = le_sec_keys->remote_ediv;SDK Example Project#
Goal | Example folder |
|---|---|
Pairing, encrypt, LTK path |
|
LE privacy / IRK / resolving list |
|
See also: Pairing and bonding, LE Privacy.
Typical Use Case 3: Encryption and Key Distribution#
When to Use#
After pairing, link encryption protects ATT and GATT procedures. Encryption started confirms the link is encrypted; security keys events expose material for bonding and logging.
Use
rsi_ble_start_encryption()when your application must start encryption with a known LTK (for example policy-driven reconnect) per the WiSeConnect BLE API; many flows complete encryption through pairing without a separate call. See GAP.
Implementation Example#
Step 1: Encryption-Started Event#
rsi_ble_on_encrypt_started provides rsi_bt_event_encryption_enabled_t (example encrypt_keys for enabled, sc_enable, localltk).
// rsi_ble_on_encrypt_started — ble_secureconnection/app.c (excerpt)
void rsi_ble_on_encrypt_started(uint16_t status, rsi_bt_event_encryption_enabled_t *enc_enabled)
{
memcpy(&encrypt_keys, enc_enabled, sizeof(rsi_bt_event_encryption_enabled_t));
rsi_ble_app_set_event(RSI_BLE_ENCRYPT_STARTED_EVENT);
}Step 2: Optional Explicit Start Encryption#
#include "rsi_ble_apis.h"
// Host-initiated encryption with bonded LTK material (product-specific):
status = rsi_ble_start_encryption(remote_dev_address, ediv, rand, ltk);Parameters: remote_dev_address (per WiSeConnect reference), ediv, rand, and ltk from pairing or bonded storage. See GAP — rsi_ble_start_encryption.
Step 3: Security and Policy#
SMP stack behavior and API details remain in Pairing and bonding and BLE API reference. Key storage, rotation, compliance, and threat model are outside this page.
SDK Example Project#
Goal | Example folder |
|---|---|
Pairing + encryption + keys |
|
See also: Pairing and bonding, SMP overview.
APIs Used in This Section#
Topic | APIs / symbols | Reference |
|---|---|---|
SMP — register callbacks |
| |
SMP — callback typedefs |
| |
Pairing — procedures |
| |
Bonding / encryption |
|
In-guide: BLE API reference. SDK: Developing with WiSeConnect SDK.