/**@brief Function for sending a service changed indication in an event context, where no return * code can be given. * * @details This function will do the procedure, and check the result, set a flag if needed, and * send an event if needed. * * @param[in] conn_handle The connection to perform the procedure on. */ static void service_changed_send_in_evt(uint16_t conn_handle) { gcm_evt_t event; bool sc_pending_state = true; bool sc_sent_state = false; ret_code_t err_code = gscm_service_changed_ind_send(conn_handle); switch(err_code) { case NRF_SUCCESS: sc_sent_state = true; event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_SENT; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); event.params.service_changed_ind_sent.conn_handle = conn_handle; m_gcm.evt_handler(&event); break; case NRF_ERROR_BUSY: // Do nothing. break; case NRF_ERROR_INVALID_STATE: // CCCDs not enabled. Drop indication. // Fallthrough. case NRF_ERROR_NOT_SUPPORTED: // Service changed not supported. Drop indication. sc_pending_state = false; gscm_db_change_notification_done(im_peer_id_get_by_conn_handle(conn_handle)); break; case BLE_ERROR_GATTS_SYS_ATTR_MISSING: local_db_apply_in_evt(conn_handle); break; case BLE_ERROR_INVALID_CONN_HANDLE: // Do nothing. break; default: event.evt_id = GCM_EVT_ERROR_UNEXPECTED; event.params.error_unexpected.conn_handle = conn_handle; event.params.error_unexpected.error = err_code; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); m_gcm.evt_handler(&event); break; } ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, sc_pending_state); ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_sent, sc_sent_state); }
/**@brief Function for performing the local DB apply procedure in an event context, where no return * code can be given. * * @details This function will do the procedure, and check the result, set a flag if needed, and * send an event if needed. * * @param[in] conn_handle The connection to perform the procedure on. */ static void local_db_update_in_evt(uint16_t conn_handle) { gcm_evt_t event; bool set_procedure_as_pending = false; ret_code_t err_code = gscm_local_db_cache_update(conn_handle); switch(err_code) { case NRF_SUCCESS: event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED; event.params.local_db_cache_applied.conn_handle = conn_handle; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); m_gcm.evt_handler(&event); break; case BLE_ERROR_INVALID_CONN_HANDLE: /* Do nothing */ break; case NRF_ERROR_BUSY: set_procedure_as_pending = true; break; case NRF_ERROR_DATA_SIZE: event.evt_id = GCM_EVT_ERROR_DATA_SIZE; event.params.error_data_size.conn_handle = conn_handle; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); m_gcm.evt_handler(&event); break; case NRF_ERROR_NO_MEM: event.evt_id = GCM_EVT_ERROR_STORAGE_FULL; event.params.error_no_mem.conn_handle = conn_handle; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); m_gcm.evt_handler(&event); break; default: event.evt_id = GCM_EVT_ERROR_UNEXPECTED; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); event.params.error_unexpected.conn_handle = conn_handle; event.params.error_unexpected.error = err_code; m_gcm.evt_handler(&event); break; } ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending); }
/**@brief Function for performing the local DB update procedure in an event context, where no return * code can be given. * * @details This function will do the procedure, and check the result, set a flag if needed, and * send an event if needed. * * @param[in] conn_handle The connection to perform the procedure on. */ static void local_db_apply_in_evt(uint16_t conn_handle) { bool set_procedure_as_pending = false; ret_code_t err_code; gcm_evt_t event; if (conn_handle == BLE_CONN_HANDLE_INVALID) { return; } err_code = gscm_local_db_cache_apply(conn_handle); switch(err_code) { case NRF_SUCCESS: event.evt_id = GCM_EVT_LOCAL_DB_CACHE_APPLIED; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); event.params.local_db_cache_applied.conn_handle = conn_handle; m_gcm.evt_handler(&event); break; case NRF_ERROR_BUSY: set_procedure_as_pending = true; break; case NRF_ERROR_INVALID_DATA: event.evt_id = GCM_EVT_ERROR_LOCAL_DB_CACHE_APPLY; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); event.params.error_local_db_cache_apply.conn_handle = conn_handle; m_gcm.evt_handler(&event); break; case BLE_ERROR_INVALID_CONN_HANDLE: /* Do nothing */ break; default: event.evt_id = GCM_EVT_ERROR_UNEXPECTED; event.peer_id = im_peer_id_get_by_conn_handle(conn_handle); event.params.error_unexpected.conn_handle = conn_handle; event.params.error_unexpected.error = err_code; m_gcm.evt_handler(&event); break; } ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_apply_pending, set_procedure_as_pending); }
/**@brief Callback function for BLE events from the SoftDevice. * * @param[in] p_ble_evt The BLE event from the SoftDevice. */ void gcm_ble_evt_handler(ble_evt_t * p_ble_evt) { gcm_evt_t event; switch(p_ble_evt->header.evt_id) { case BLE_GATTS_EVT_SYS_ATTR_MISSING: local_db_apply_in_evt(p_ble_evt->evt.gatts_evt.conn_handle); break; case BLE_GATTS_EVT_SC_CONFIRM: event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_CONFIRMED; event.peer_id = im_peer_id_get_by_conn_handle(p_ble_evt->evt.gatts_evt.conn_handle); event.params.service_changed_ind_sent.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle; gscm_db_change_notification_done(event.peer_id); ble_conn_state_user_flag_set(p_ble_evt->evt.gatts_evt.conn_handle, m_gcm.flag_id_service_changed_pending, false); m_gcm.evt_handler(&event); break; case BLE_GATTS_EVT_WRITE: if (cccd_written(&p_ble_evt->evt.gatts_evt.params.write)) { local_db_update_in_evt(p_ble_evt->evt.gatts_evt.conn_handle); } break; } apply_pending_flags_check(); update_pending_flags_check(); service_changed_pending_flags_check(); }
ret_code_t pm_peer_id_get(uint16_t conn_handle, pm_peer_id_t * p_peer_id) { VERIFY_MODULE_INITIALIZED(); VERIFY_PARAM_NOT_NULL(p_peer_id); *p_peer_id = im_peer_id_get_by_conn_handle(conn_handle); return NRF_SUCCESS; }
void gcm_local_database_has_changed(void) { gscm_local_database_has_changed(); sdk_mapped_flags_key_list_t conn_handles = ble_conn_state_conn_handles(); for (uint16_t i = 0; i < conn_handles.len; i++) { if (im_peer_id_get_by_conn_handle(conn_handles.flag_keys[i]) == PM_PEER_ID_INVALID) { ble_conn_state_user_flag_set(conn_handles.flag_keys[i], m_gcm.flag_id_service_changed_pending, true); } } service_changed_pending_flags_check(); }
void im_evt_handler(im_evt_t const * p_evt) { pm_evt_t pm_evt; switch (p_evt->evt_id) { case IM_EVT_DUPLICATE_ID: // Delete the duplicate data to free space and avoid finding old data when scanning in the future pm_peer_delete(p_evt->params.duplicate_id.peer_id_2); break; case IM_EVT_BONDED_PEER_CONNECTED: ble_conn_state_user_flag_set(p_evt->conn_handle, m_pm.bonding_flag_id, true); memset(&pm_evt, 0, sizeof(pm_evt_t)); pm_evt.conn_handle = p_evt->conn_handle; pm_evt.peer_id = im_peer_id_get_by_conn_handle(p_evt->conn_handle); pm_evt.evt_id = PM_EVT_BONDED_PEER_CONNECTED; evt_send(&pm_evt); break; } }
/**@brief Event handler for events from the Security Manager module. * This handler is extern in the Security Manager module. * * @param[in] p_sm_evt The incoming Security Manager event. */ void pm_sm_evt_handler(sm_evt_t const * p_sm_evt) { bool find_peer_id = true; bool send_evt = true; pm_evt_t pm_evt; memset(&pm_evt, 0, sizeof(pm_evt_t)); pm_evt.conn_handle = p_sm_evt->conn_handle; switch (p_sm_evt->evt_id) { case SM_EVT_SLAVE_SECURITY_REQ: find_peer_id = false; send_evt = false; break; case SM_EVT_SEC_PROCEDURE_START: { pm_evt.evt_id = PM_EVT_CONN_SEC_START; bool pairing = p_sm_evt->params.sec_procedure_start.procedure != PM_LINK_SECURED_PROCEDURE_ENCRYPTION; bool bonding = p_sm_evt->params.sec_procedure_start.procedure == PM_LINK_SECURED_PROCEDURE_BONDING; ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_pairing_flag_id, pairing); ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_bonding_flag_id, bonding); break; } case SM_EVT_PAIRING_SUCCESS: pm_evt.evt_id = PM_EVT_CONN_SEC_SUCCEEDED; pm_evt.params.conn_sec_succeeded.procedure = p_sm_evt->params.pairing_success.bonded ? PM_LINK_SECURED_PROCEDURE_BONDING : PM_LINK_SECURED_PROCEDURE_PAIRING; ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_pairing_flag_id, true); ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_bonding_flag_id, p_sm_evt->params.pairing_success.bonded ); break; case SM_EVT_PAIRING_FAIL: pm_evt.evt_id = PM_EVT_CONN_SEC_FAILED; pm_evt.params.conn_sec_failed.procedure = ble_conn_state_user_flag_get(p_sm_evt->conn_handle, m_bonding_flag_id) ? PM_LINK_SECURED_PROCEDURE_BONDING : PM_LINK_SECURED_PROCEDURE_PAIRING; pm_evt.params.conn_sec_failed.error_src = p_sm_evt->params.pairing_failed.error_src; pm_evt.params.conn_sec_failed.error = p_sm_evt->params.pairing_failed.error; break; case SM_EVT_LINK_ENCRYPTION_UPDATE: if (!ble_conn_state_user_flag_get(p_sm_evt->conn_handle, m_pairing_flag_id)) { pm_evt.evt_id = PM_EVT_CONN_SEC_SUCCEEDED; pm_evt.params.conn_sec_succeeded.procedure = PM_LINK_SECURED_PROCEDURE_ENCRYPTION; } else { find_peer_id = false; send_evt = false; } break; case SM_EVT_LINK_ENCRYPTION_FAILED: pm_evt.evt_id = PM_EVT_CONN_SEC_FAILED; pm_evt.params.conn_sec_failed.procedure = PM_LINK_SECURED_PROCEDURE_ENCRYPTION; pm_evt.params.conn_sec_failed.error_src = p_sm_evt->params.link_encryption_failed.error_src; pm_evt.params.conn_sec_failed.error = p_sm_evt->params.link_encryption_failed.error; break; case SM_EVT_BONDING_INFO_STORED: pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_SUCCEEDED; pm_evt.peer_id = p_sm_evt->params.bonding_info_stored.peer_id; pm_evt.params.peer_data_update_succeeded.data_id = PM_PEER_DATA_ID_BONDING; pm_evt.params.peer_data_update_succeeded.action = PM_PEER_DATA_OP_UPDATE; find_peer_id = false; break; case SM_EVT_ERROR_BONDING_INFO: pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_FAILED; pm_evt.peer_id = p_sm_evt->params.error_bonding_info.peer_id; pm_evt.params.peer_data_update_failed.data_id = PM_PEER_DATA_ID_BONDING; pm_evt.params.peer_data_update_failed.action = PM_PEER_DATA_OP_UPDATE; pm_evt.params.peer_data_update_failed.error = p_sm_evt->params.error_bonding_info.error; find_peer_id = false; break; case SM_EVT_ERROR_UNEXPECTED: pm_evt.evt_id = PM_EVT_ERROR_UNEXPECTED; pm_evt.params.error_unexpected.error = p_sm_evt->params.error_unexpected.error; break; case SM_EVT_ERROR_NO_MEM: pm_evt.evt_id = PM_EVT_STORAGE_FULL; break; case SM_EVT_ERROR_SMP_TIMEOUT: pm_evt.evt_id = PM_EVT_CONN_SEC_FAILED; pm_evt.params.conn_sec_failed.procedure = ble_conn_state_user_flag_get(p_sm_evt->conn_handle, m_bonding_flag_id) ? PM_LINK_SECURED_PROCEDURE_BONDING : PM_LINK_SECURED_PROCEDURE_PAIRING; pm_evt.params.conn_sec_failed.error_src = BLE_GAP_SEC_STATUS_SOURCE_LOCAL; pm_evt.params.conn_sec_failed.error = PM_CONN_SEC_ERROR_SMP_TIMEOUT; break; case SM_EVT_CONN_SEC_CONFIG_REQ: pm_evt.evt_id = PM_EVT_CONN_SEC_CONFIG_REQ; break; default: send_evt = false; break; } if (find_peer_id) { pm_evt.peer_id = im_peer_id_get_by_conn_handle(p_sm_evt->conn_handle); } if (send_evt) { evt_send(&pm_evt); } }