bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) { /* * Use a helper function from the Nordic SDK to test whether the BLE * address can be generated using the IRK. */ return im_address_resolve(p_addr, p_irk); }
void im_ble_evt_handler(ble_evt_t * ble_evt) { ble_gap_evt_t gap_evt; pm_peer_id_t bonded_matching_peer_id; NRF_PM_DEBUG_CHECK(m_module_initialized); if (ble_evt->header.evt_id != BLE_GAP_EVT_CONNECTED) { // Nothing to do. return; } gap_evt = ble_evt->evt.gap_evt; bonded_matching_peer_id = PM_PEER_ID_INVALID; if ( gap_evt.params.connected.peer_addr.addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) { /* Search the database for bonding data matching the one that triggered the event. * Public and static addresses can be matched on address alone, while resolvable * random addresses can be resolved agains known IRKs. Non-resolvable random addresses * are never matching because they are not longterm form of identification. */ pm_peer_id_t peer_id; pm_peer_data_flash_t peer_data; pds_peer_data_iterate_prepare(); switch (gap_evt.params.connected.peer_addr.addr_type) { case BLE_GAP_ADDR_TYPE_PUBLIC: case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: { while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data)) { if (addr_compare(&gap_evt.params.connected.peer_addr, &peer_data.p_bonding_data->peer_id.id_addr_info)) { bonded_matching_peer_id = peer_id; break; } } } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: { while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data)) { if (im_address_resolve(&gap_evt.params.connected.peer_addr, &peer_data.p_bonding_data->peer_id.id_info)) { bonded_matching_peer_id = peer_id; break; } } } break; default: NRF_PM_DEBUG_CHECK(false); break; } } uint8_t new_index = new_connection(gap_evt.conn_handle, &gap_evt.params.connected.peer_addr); UNUSED_VARIABLE(new_index); if (bonded_matching_peer_id != PM_PEER_ID_INVALID) { im_new_peer_id(gap_evt.conn_handle, bonded_matching_peer_id); // Send a bonded peer event im_evt_t im_evt; im_evt.conn_handle = gap_evt.conn_handle; im_evt.evt_id = IM_EVT_BONDED_PEER_CONNECTED; evt_send(&im_evt); } }
void im_ble_evt_handler(ble_evt_t * ble_evt) { ret_code_t err_code; switch (ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: { pm_peer_id_t bonded_matching_peer_id = PM_PEER_ID_INVALID; if (ble_evt->evt.gap_evt.params.connected.irk_match == 1) { // The peer was matched using a whitelist. bonded_matching_peer_id = m_im.irk_whitelist_peer_ids[ble_evt->evt.gap_evt.params.connected.irk_match_idx]; } else if ( ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) { /* Search the database for bonding data matching the one that triggered the event. * Public and static addresses can be matched on address alone, while resolvable * random addresses can be resolved agains known IRKs. Non-resolvable random addresses * are never matching because they are not longterm form of identification. */ pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID); while ( (compared_peer_id != PM_PEER_ID_INVALID) && (bonded_matching_peer_id == PM_PEER_ID_INVALID)) { pm_peer_data_flash_t compared_data; switch (ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type) { case BLE_GAP_ADDR_TYPE_PUBLIC: /* fall-through */ case BLE_GAP_ADDR_TYPE_RANDOM_STATIC: err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL); if ((err_code == NRF_SUCCESS) && addr_compare(&ble_evt->evt.gap_evt.params.connected.peer_addr, &compared_data.p_bonding_data->peer_id.id_addr_info) ) { bonded_matching_peer_id = compared_peer_id; } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE: err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL); if (err_code == NRF_SUCCESS && im_address_resolve(&ble_evt->evt.gap_evt.params.connected.peer_addr, &compared_data.p_bonding_data->peer_id.id_info) ) { bonded_matching_peer_id = compared_peer_id; } break; case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE: // Should not happen. break; default: break; } compared_peer_id = pdb_next_peer_id_get(compared_peer_id); } } uint8_t new_index = new_connection(ble_evt->evt.gap_evt.conn_handle, &ble_evt->evt.gap_evt.params.connected.peer_addr); UNUSED_VARIABLE(new_index); if (bonded_matching_peer_id != PM_PEER_ID_INVALID) { im_new_peer_id(ble_evt->evt.gap_evt.conn_handle, bonded_matching_peer_id); // Send a bonded peer event im_evt_t im_evt; im_evt.conn_handle = ble_evt->evt.gap_evt.conn_handle; im_evt.evt_id = IM_EVT_BONDED_PEER_CONNECTED; evt_send(&im_evt); } } } }
void pm_handler(pm_evt_t const *p_event) { nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE); nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager(); ret_code_t err_code; SecurityManager::SecurityMode_t resolvedSecurityMode; switch (p_event->evt_id) { case PM_EVT_CONN_SEC_START: /* started */ { const ble_gap_sec_params_t *peerParams = &securityParameters; securityManager.processSecuritySetupInitiatedEvent(p_event->conn_handle, peerParams->bond, peerParams->mitm, (SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps); _enc_in_progress = true; break; } case PM_EVT_CONN_SEC_SUCCEEDED: // Update the rank of the peer. if (p_event->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING) { err_code = pm_peer_rank_highest(p_event->peer_id); } securityManager. processSecuritySetupCompletedEvent(p_event->conn_handle, SecurityManager::SEC_STATUS_SUCCESS);// SEC_STATUS_SUCCESS of SecurityCompletionStatus_t ble_gap_conn_sec_t conn_sec; sd_ble_gap_conn_sec_get(p_event->conn_handle, &conn_sec); resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS; switch (conn_sec.sec_mode.sm) { case 1: switch (conn_sec.sec_mode.lv) { case 1: resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK; break; case 2: resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM; break; case 3: resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM; break; } break; case 2: switch (conn_sec.sec_mode.lv) { case 1: resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM; break; case 2: resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM; break; } break; } securityManager.processLinkSecuredEvent(p_event->conn_handle, resolvedSecurityMode); _enc_in_progress = false; break; case PM_EVT_CONN_SEC_FAILED: SecurityManager::SecurityCompletionStatus_t securityCompletionStatus; if ((uint32_t)p_event->params.conn_sec_failed.error >= PM_CONN_SEC_ERROR_BASE ) { securityCompletionStatus = SecurityManager::SEC_STATUS_UNSPECIFIED; } else { securityCompletionStatus = (SecurityManager::SecurityCompletionStatus_t)p_event->params.conn_sec_failed.error; } securityManager. processSecuritySetupCompletedEvent(p_event->conn_handle, securityCompletionStatus); _enc_in_progress = false; break; case PM_EVT_BONDED_PEER_CONNECTED: pm_peer_rank_highest(p_event->peer_id); break; case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: if (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE) { securityManager.processSecurityContextStoredEvent(p_event->conn_handle); } break; case PM_EVT_PEER_DATA_UPDATE_FAILED: break; case PM_EVT_PEERS_DELETE_SUCCEEDED: async_ret_code = NRF_SUCCESS; // respond SUCCESS to the busy-loop in f. btle_purgeAllBondingState break; case PM_EVT_PEERS_DELETE_FAILED: async_ret_code = NRF_ERROR_INTERNAL; // respond FAILURE to the busy-loop in f. btle_purgeAllBondingState break; 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_CONN_SEC_CONFIG_REQ:{ // A connected peer (central) is trying to pair, but the Peer Manager already has a bond // for that peer. Setting allow_repairing to false rejects the pairing request. // If this event is ignored (pm_conn_sec_config_reply is not called in the event // handler), the Peer Manager assumes allow_repairing to be false. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true}; pm_conn_sec_config_reply(p_event->conn_handle, &conn_sec_config); } break;//PM_EVT_CONN_SEC_CONFIG_REQ default: break; } } #if (NRF_SD_BLE_API_VERSION <= 2) ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist) { if (!btle_hasInitializedSecurity()) { return BLE_ERROR_INITIALIZATION_INCOMPLETE; } ret_code_t err = pm_whitelist_create( NULL, BLE_GAP_WHITELIST_ADDR_MAX_COUNT, p_whitelist); if (err == NRF_SUCCESS) { return BLE_ERROR_NONE; } else if (err == NRF_ERROR_NULL) { return BLE_ERROR_PARAM_OUT_OF_RANGE; } else { return BLE_ERROR_INVALID_STATE; } } #endif bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk) { /* * Use a helper function from the Nordic SDK to test whether the BLE * address can be generated using the IRK. */ return im_address_resolve(p_addr, p_irk); } void btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address) { /* Set type to resolvable */ address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE; /* * Assign a random number to the most significant 3 bytes * of the address. */ address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E; address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F; address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C; /* Calculate the hash and store it in the top half of the address */ ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr); }