/******************************************************************************* * @file ble_security.c * @brief BLE Security - Peer Manager, LESC, Bonding * @author Charles KWON * @date 2025-01-30 * @copyright (c) 2025 Medithings Inc. All rights reserved. * * @details Peer Manager initialization and security event handling. ******************************************************************************/ #include "sdk_config.h" #include "ble_security.h" #if FEATURE_SECURE_CONNECTION #include "ble_core.h" #include "ble_data_tx.h" #include "power_ctrl.h" #include "device_config.h" #include "peer_manager.h" #include "peer_manager_handler.h" #include "nrf_ble_lesc.h" #include "ble_conn_state.h" #include "app_error.h" #include "debug_print.h" #include "battery_saadc.h" #include "ble_quick_security.h" #include /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ bool erase_bonds = false; /*============================================================================== * PRIVATE VARIABLES *============================================================================*/ static pm_peer_id_t m_peer_to_be_deleted = PM_PEER_ID_INVALID; static uint8_t c_addr[6]; /*============================================================================== * PEER MANAGER EVENT HANDLER *============================================================================*/ static void pm_evt_handler(pm_evt_t const * p_evt) { pm_peer_data_bonding_t peer_bonding_data; uint32_t return_code; ret_code_t err_code; /* Standard Peer Manager handlers */ pm_handler_on_pm_evt(p_evt); pm_handler_disconnect_on_sec_failure(p_evt); pm_handler_flash_clean(p_evt); /* Security module (automatic mode handling) */ ble_security_quick_pm_handler(p_evt); /* Application-specific event handling */ switch (p_evt->evt_id) { case PM_EVT_CONN_SEC_SUCCEEDED: { pm_conn_sec_status_t conn_sec_status; err_code = pm_conn_sec_status_get(p_evt->conn_handle, &conn_sec_status); APP_ERROR_CHECK(err_code); /* Accept if: MITM protected OR dev mode (no security) */ if (conn_sec_status.mitm_protected || BLE_DEV_MODE) { DBG_PRINTF("Link secured. Role: %d, conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); /* Start battery monitoring after secure connection */ ble_connection_st = 1; battery_timer_start(); } else { /* Security insufficient - disconnect (production mode) */ DBG_PRINTF("Link security FAILED\r\n"); err_code = pm_peer_id_get(m_conn_handle, &m_peer_to_be_deleted); APP_ERROR_CHECK(err_code); err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); } } break; case PM_EVT_CONN_SEC_FAILED: { DBG_PRINTF("Security failed: peer_id=%d, error=%d\r\n", p_evt->peer_id, p_evt->params.conn_sec_failed.error); /* Auto-retry if key missing (supports rebonding) */ if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING) { err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } } } break; case PM_EVT_PEERS_DELETE_SUCCEEDED: /* Restart advertising after bond deletion */ advertising_start(false); break; case PM_EVT_CONN_SEC_CONFIG_REQ: { /* Allow repairing for rebonding support */ pm_conn_sec_config_t conn_sec_config = { .allow_repairing = true }; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } break; case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: { /* Store peer address for tracking */ return_code = pm_peer_data_bonding_load(p_evt->peer_id, &peer_bonding_data); if (return_code == NRF_SUCCESS) { DBG_PRINTF("Peer updated: %02x:%02x:%02x:%02x:%02x:%02x\r\n", peer_bonding_data.peer_ble_id.id_addr_info.addr[5], peer_bonding_data.peer_ble_id.id_addr_info.addr[4], peer_bonding_data.peer_ble_id.id_addr_info.addr[3], peer_bonding_data.peer_ble_id.id_addr_info.addr[2], peer_bonding_data.peer_ble_id.id_addr_info.addr[1], peer_bonding_data.peer_ble_id.id_addr_info.addr[0]); memcpy(c_addr, peer_bonding_data.peer_ble_id.id_addr_info.addr, sizeof(c_addr)); DBG_PRINTF("Stored c_addr[3]: %02x\r\n", c_addr[3]); m_reset_status = 10; } else { DBG_PRINTF("Failed to load peer data: error=%d\r\n", return_code); m_reset_status = 10; } } break; default: break; } } /*============================================================================== * PUBLIC FUNCTIONS *============================================================================*/ void peer_manager_init(void) { ret_code_t err_code; /* Security mode auto-configuration */ ble_security_quick_init(BLE_DEV_MODE); /* Register PM event handler */ err_code = pm_register(pm_evt_handler); APP_ERROR_CHECK(err_code); DBG_PRINTF("BLE Security initialized (mode=%d)\r\n", BLE_DEV_MODE); } void delete_bonds(void) { ret_code_t err_code; DBG_PRINTF("Erase bonds!\r\n"); err_code = pm_peers_delete(); APP_ERROR_CHECK(err_code); } void security_idle_state_handle(void) { ret_code_t err_code; err_code = nrf_ble_lesc_request_handler(); APP_ERROR_CHECK(err_code); } #endif /* FEATURE_SECURE_CONNECTION */