ble_error_t btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP) { ret_code_t rc; pm_conn_sec_status_t conn_sec_status; rc = pm_conn_sec_status_get(connectionHandle, &conn_sec_status); if (rc == NRF_SUCCESS) { if (conn_sec_status.encrypted) { *securityStatusP = SecurityManager::ENCRYPTED; } else if (conn_sec_status.connected) { if (_enc_in_progress) { *securityStatusP = SecurityManager::ENCRYPTION_IN_PROGRESS; } else { *securityStatusP = SecurityManager::NOT_ENCRYPTED; } } return BLE_ERROR_NONE; } switch (rc) { case BLE_ERROR_INVALID_CONN_HANDLE: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_INVALID_STATE: return BLE_ERROR_INVALID_STATE; default: return BLE_ERROR_UNSPECIFIED; } }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch(p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: { NRF_LOG_PRINTF_DEBUG("Connected to previously bonded device\r\n"); // Start Security Request timer. err_code = app_timer_start(m_sec_req_timer_id, SECURITY_REQUEST_DELAY, NULL); APP_ERROR_CHECK(err_code); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } }break;//PM_EVT_BONDED_PEER_CONNECTED case PM_EVT_CONN_SEC_START: break;//PM_EVT_CONN_SEC_START case PM_EVT_CONN_SEC_SUCCEEDED: { /*Check if the link is authenticated (meaning at least MITM)*/ 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); if (!conn_sec_status.mitm_protected) { APP_LOG("Collector did not use MITM, disconnecting\r\n"); /*The peer did not use MITM, disconnect*/ err_code = pm_peer_id_get(m_conn_handle, &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); // m_state = W_ADV_STATE_UNBONDED; } else { NRF_LOG_PRINTF_DEBUG("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); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } // m_state = W_ADV_STATE_BONDED; } }break;//PM_EVT_CONN_SEC_SUCCEEDED case PM_EVT_CONN_SEC_FAILED: { /** In some cases, when securing fails, it can be restarted directly. Sometimes it can * be restarted, but only after changing some Security Parameters. Sometimes, it cannot * be restarted until the link is disconnected and reconnected. Sometimes it is * impossible, to secure the link, or the peer device does not support it. How to * handle this error is highly application dependent. */ APP_LOG("link secure failed! "); switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: NRF_LOG_DEBUG("error: PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING"); break;//PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING case PM_CONN_SEC_ERROR_MIC_FAILURE: NRF_LOG_DEBUG("error: PM_CONN_SEC_ERROR_MIC_FAILURE"); break;//PM_CONN_SEC_ERROR_MIC_FAILURE case PM_CONN_SEC_ERROR_DISCONNECT : NRF_LOG_DEBUG("error: PM_CONN_SEC_ERROR_DISCONNECT "); break;//PM_CONN_SEC_ERROR_DISCONNECT case PM_CONN_SEC_ERROR_SMP_TIMEOUT: NRF_LOG_DEBUG("error: PM_CONN_SEC_ERROR_SMP_TIMEOUT"); break;//PM_CONN_SEC_ERROR_SMP_TIMEOUT default: NRF_LOG_DEBUG("unknown error"); break; } APP_LOG("\r\nDisconnecting\r\n"); err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); m_conn_handle = BLE_CONN_HANDLE_INVALID; }break;//PM_EVT_CONN_SEC_FAILED case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); }break;//PM_EVT_CONN_SEC_CONFIG_REQ case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } }break;//PM_EVT_STORAGE_FULL case PM_EVT_ERROR_UNEXPECTED: // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break;//PM_EVT_ERROR_UNEXPECTED case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: break;//PM_EVT_PEER_DATA_UPDATE_SUCCEEDED case PM_EVT_PEER_DATA_UPDATE_FAILED: // Assert. APP_ERROR_CHECK_BOOL(false); break;//PM_EVT_PEER_DATA_UPDATE_FAILED case PM_EVT_PEER_DELETE_SUCCEEDED: break;//PM_EVT_PEER_DELETE_SUCCEEDED case PM_EVT_PEER_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break;//PM_EVT_PEER_DELETE_FAILED case PM_EVT_PEERS_DELETE_SUCCEEDED: NRF_LOG_PRINTF_DEBUG("%s: PM_EVT_PEERS_DELETE_SUCCEEDED\r\n", __func__); // m_erasing_bonds = false; // advertising_init(); // advertising_start(); break; case PM_EVT_PEERS_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break;//PM_EVT_PEERS_DELETE_FAILED case PM_EVT_LOCAL_DB_CACHE_APPLIED: break;//PM_EVT_LOCAL_DB_CACHE_APPLIED case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break;//PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED case PM_EVT_SERVICE_CHANGED_IND_SENT: break;//PM_EVT_SERVICE_CHANGED_IND_SENT case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break;//PM_EVT_SERVICE_CHANGED_IND_CONFIRMED default: // No implementation needed. break; } } /**@brief Function for handling Service errors. * * @details A pointer to this function will be passed to each service which may need to inform the * application about an error. * * @param[in] nrf_error Error code containing information about what went wrong. */ //static void service_error_handler(uint32_t nrf_error) //{ // APP_ERROR_HANDLER(nrf_error); //} /**@brief Function for performing battery measurement and updating the Battery Level characteristic * in Battery Service. */ static void battery_level_update(void) { uint32_t err_code; uint8_t battery_level; // battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg); battery_level = 37; err_code = ble_bas_battery_level_update(&m_bas, battery_level); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != BLE_ERROR_NO_TX_PACKETS) && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) ) { APP_ERROR_HANDLER(err_code); } // if (m_adv_state == W_ADV_STATE_IDLE) { // advertising_init(); // advertising_start(); // } }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch (p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } break; // PM_EVT_BONDED_PEER_CONNECTED case PM_EVT_CONN_SEC_START: break; // PM_EVT_CONN_SEC_START case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_INFO("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); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_CONN_SEC_SUCCEEDED case PM_EVT_CONN_SEC_FAILED: { /** In some cases, when securing fails, it can be restarted directly. Sometimes it can * be restarted, but only after changing some Security Parameters. Sometimes, it cannot * be restarted until the link is disconnected and reconnected. Sometimes it is * impossible, to secure the link, or the peer device does not support it. How to * handle this error is highly application dependent. */ switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: // Rebond if one party has lost its keys. err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; // PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING default: break; } } break; // PM_EVT_CONN_SEC_FAILED case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } break; // PM_EVT_CONN_SEC_CONFIG_REQ case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_STORAGE_FULL case PM_EVT_ERROR_UNEXPECTED: // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break; // PM_EVT_ERROR_UNEXPECTED case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: break; // PM_EVT_PEER_DATA_UPDATE_SUCCEEDED case PM_EVT_PEER_DATA_UPDATE_FAILED: // Assert. APP_ERROR_CHECK_BOOL(false); break; // PM_EVT_PEER_DATA_UPDATE_FAILED case PM_EVT_PEER_DELETE_SUCCEEDED: break; // PM_EVT_PEER_DELETE_SUCCEEDED case PM_EVT_PEER_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break; // PM_EVT_PEER_DELETE_FAILED case PM_EVT_PEERS_DELETE_SUCCEEDED: advertising_start(); break; // PM_EVT_PEERS_DELETE_SUCCEEDED case PM_EVT_PEERS_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break; // PM_EVT_PEERS_DELETE_FAILED case PM_EVT_LOCAL_DB_CACHE_APPLIED: break; // PM_EVT_LOCAL_DB_CACHE_APPLIED case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break; // PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED case PM_EVT_SERVICE_CHANGED_IND_SENT: break; // PM_EVT_SERVICE_CHANGED_IND_SENT case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break; // PM_EVT_SERVICE_CHANGED_IND_CONFIRMED default: // No implementation needed. break; } } /**@brief Function for handling the security request timer time-out. * * @details This function is called each time the security request timer expires. * * @param[in] p_context Pointer used for passing context information from the * app_start_timer() call to the time-out handler. */ static void sec_req_timeout_handler(void * p_context) { uint32_t err_code; pm_conn_sec_status_t status; if (m_cur_conn_handle != BLE_CONN_HANDLE_INVALID) { err_code = pm_conn_sec_status_get(m_cur_conn_handle, &status); APP_ERROR_CHECK(err_code); // If the link is still not secured by the peer, initiate security procedure. if (!status.encrypted) { NRF_LOG_INFO("Start encryption\r\n"); err_code = pm_conn_secure(m_cur_conn_handle, false); APP_ERROR_CHECK(err_code); } } }