uint32_t conn_mw_ble_gap_conn_sec_get(uint8_t const * const p_rx_buf, uint32_t rx_buf_len, uint8_t * const p_tx_buf, uint32_t * const p_tx_buf_len) { SER_ASSERT_NOT_NULL(p_rx_buf); SER_ASSERT_NOT_NULL(p_tx_buf); SER_ASSERT_NOT_NULL(p_tx_buf_len); uint32_t err_code = NRF_SUCCESS; uint32_t sd_err_code; uint16_t conn_handle; ble_gap_conn_sec_t conn_sec; ble_gap_conn_sec_t * p_conn_sec = &conn_sec; err_code = ble_gap_conn_sec_get_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &p_conn_sec); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gap_conn_sec_get(conn_handle, p_conn_sec); err_code = ble_gap_conn_sec_get_rsp_enc(sd_err_code, p_conn_sec, p_tx_buf, p_tx_buf_len); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) { ble_error_t returnValue = BLE_ERROR_NONE; ble_gatts_value_t value = { /* .len = */ len, /* .offset = */ 0, /* .p_value = */ const_cast<uint8_t *>(buffer), }; if (localOnly) { /* Only update locally regardless of notify/indicate */ ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), BLE_ERROR_PARAM_OUT_OF_RANGE ); return BLE_ERROR_NONE; } int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); if ((characteristicIndex != -1) && (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { /* HVX update for the characteristic value */ ble_gatts_hvx_params_t hvx_params; hvx_params.handle = attributeHandle; hvx_params.type = (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION; hvx_params.offset = 0; hvx_params.p_data = const_cast<uint8_t *>(buffer); hvx_params.p_len = &len; if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */ nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); connectionHandle = gap.getConnectionHandle(); } bool updatesEnabled = false; if (connectionHandle != BLE_CONN_HANDLE_INVALID) { ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled); // FIXME: The softdevice allocates and populates CCCD when the client // interract with them. Checking for updates may return an out of // range error in such case. if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) { return err; } } bool updates_permitted = false; ble_gap_conn_sec_t connection_security; uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security); if (!err && (connection_security.sec_mode.sm == 1) && (connection_security.sec_mode.lv >= p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) { updates_permitted = true; } if (updatesEnabled && updates_permitted) { error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); if (error != ERROR_NONE) { switch (error) { case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */ case ERROR_BUSY: returnValue = BLE_STACK_BUSY; break; case ERROR_INVALID_STATE: case ERROR_BLEGATTS_SYS_ATTR_MISSING: returnValue = BLE_ERROR_INVALID_STATE; break; default : ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), BLE_ERROR_PARAM_OUT_OF_RANGE ); /* Notifications consume application buffers. The return value can * be used for resending notifications. */ returnValue = BLE_STACK_BUSY; break; } } } else { returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); } } else { returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); } return returnValue; }
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); }