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 NULL only 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 unused

Note: Parameter order matches the WiSeConnect API. See Register Callbacks and Callbacks Declarations. Pairing flows also require rsi_ble_gap_register_callbacks() (and rsi_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 with rsi_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.

io_capability

Meaning

0x00

Display Only

0x01

Display Yes/No

0x02

Keyboard Only

0x03

No Input No Output

mitm_req

Meaning

0x00

MITM disabled

0x01

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

ble_secureconnection

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

ble_secureconnection

LE privacy / IRK / resolving list

ble_privacy

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

ble_secureconnection

See also: Pairing and bonding, SMP overview.


APIs Used in This Section#

Topic

APIs / symbols

Reference

SMP — register callbacks

rsi_ble_smp_register_callbacks()

Register Callbacks

SMP — callback typedefs

rsi_ble_on_smp_request_t, rsi_ble_on_smp_response_t (SMP response), rsi_ble_on_smp_passkey_t, rsi_ble_on_smp_failed_t, rsi_ble_on_encrypt_started_t, rsi_ble_on_smp_passkey_display_t, rsi_ble_on_sc_passkey_t, rsi_ble_on_le_ltk_req_event_t, rsi_ble_on_le_security_keys_t, rsi_ble_on_smp_response_t (client SMP response), rsi_ble_on_sc_method_t

Callbacks Declarations

Pairing — procedures

rsi_ble_set_smp_pairing_cap_data(), rsi_ble_smp_pair_request(), rsi_ble_smp_pair_response(), rsi_ble_smp_passkey(), rsi_ble_smp_pair_failed(); struct rsi_ble_set_smp_pairing_capabilty_data_t

GAP

Bonding / encryption

rsi_ble_ltk_req_reply(), rsi_ble_start_encryption(); rsi_bt_event_le_ltk_request_t, rsi_bt_event_encryption_enabled_t, rsi_bt_event_le_security_keys_t, rsi_bt_event_smp_passkey_display_t, rsi_bt_event_sc_passkey_t

GAP, Callbacks Declarations

In-guide: BLE API reference. SDK: Developing with WiSeConnect SDK.