aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c578
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h113
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c347
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h163
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c890
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h327
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c678
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h270
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c814
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h309
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c202
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h167
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c983
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h781
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h207
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h354
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c151
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h159
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c144
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h125
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c1110
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h166
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c675
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h181
24 files changed, 9894 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c
new file mode 100644
index 0000000..053a389
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c
@@ -0,0 +1,578 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "gatt_cache_manager.h"
+
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "ble_conn_state.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "id_manager.h"
+#include "gatts_cache_manager.h"
+#include "peer_database.h"
+#include "pm_mutex.h"
+
+
+// The number of registered event handlers.
+#define GCM_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+// GATT Cache Manager event handler in Peer Manager.
+extern void pm_gcm_evt_handler(pm_evt_t * p_gcm_evt);
+
+// GATT Cache Manager events' handlers.
+// The number of elements in this array is GCM_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t m_evt_handlers[] =
+{
+ pm_gcm_evt_handler
+};
+
+static bool m_module_initialized;
+static uint8_t m_db_update_in_progress_mutex; /**< Mutex indicating whether a local DB write operation is ongoing. */
+static ble_conn_state_user_flag_id_t m_flag_local_db_update_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB update procedure. */
+static ble_conn_state_user_flag_id_t m_flag_local_db_apply_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB apply procedure. */
+static ble_conn_state_user_flag_id_t m_flag_service_changed_pending; /**< Flag ID for flag collection to keep track of which connections need to be sent a service changed indication. */
+static ble_conn_state_user_flag_id_t m_flag_service_changed_sent; /**< Flag ID for flag collection to keep track of which connections have been sent a service changed indication and are waiting for a handle value confirmation. */
+
+#ifdef PM_SERVICE_CHANGED_ENABLED
+ STATIC_ASSERT(PM_SERVICE_CHANGED_ENABLED || !NRF_SDH_BLE_SERVICE_CHANGED,
+ "PM_SERVICE_CHANGED_ENABLED should be enabled if NRF_SDH_BLE_SERVICE_CHANGED is enabled.");
+#else
+ #define PM_SERVICE_CHANGED_ENABLED 1
+#endif
+
+/**@brief Function for resetting the module variable(s) of the GSCM module.
+ *
+ * @param[out] The instance to reset.
+ */
+static void internal_state_reset()
+{
+ m_module_initialized = false;
+}
+
+
+static void evt_send(pm_evt_t * p_gcm_evt)
+{
+ p_gcm_evt->peer_id = im_peer_id_get_by_conn_handle(p_gcm_evt->conn_handle);
+
+ for (uint32_t i = 0; i < GCM_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_gcm_evt);
+ }
+}
+
+
+/**@brief Function for checking a write event for whether a CCCD was written during the write
+ * operation.
+ *
+ * @param[in] p_write_evt The parameters of the write event.
+ *
+ * @return Whether the write was on a CCCD.
+ */
+static bool cccd_written(ble_gatts_evt_write_t const * p_write_evt)
+{
+ return ( (p_write_evt->op == BLE_GATTS_OP_WRITE_REQ)
+ && (p_write_evt->uuid.type == BLE_UUID_TYPE_BLE)
+ && (p_write_evt->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
+ );
+}
+
+
+/**@brief Function for sending an PM_EVT_ERROR_UNEXPECTED event.
+ *
+ * @param[in] conn_handle The connection handle the event pertains to.
+ * @param[in] err_code The unexpected error that occurred.
+ */
+static void send_unexpected_error(uint16_t conn_handle, ret_code_t err_code)
+{
+ pm_evt_t error_evt =
+ {
+ .evt_id = PM_EVT_ERROR_UNEXPECTED,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .error_unexpected =
+ {
+ .error = err_code,
+ }
+ }
+ };
+ evt_send(&error_evt);
+}
+
+
+/**@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;
+ pm_evt_t event =
+ {
+ .conn_handle = conn_handle,
+ };
+
+ 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 = PM_EVT_LOCAL_DB_CACHE_APPLIED;
+
+ evt_send(&event);
+ break;
+
+ case NRF_ERROR_BUSY:
+ set_procedure_as_pending = true;
+ break;
+
+ case NRF_ERROR_INVALID_DATA:
+ event.evt_id = PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED;
+
+ evt_send(&event);
+ break;
+
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ /* Do nothing */
+ break;
+
+ default:
+ send_unexpected_error(conn_handle, err_code);
+ break;
+ }
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_local_db_apply_pending, set_procedure_as_pending);
+}
+
+
+/**@brief Function for asynchronously starting a DB update procedure.
+ *
+ * @note This procedure can only be started asynchronously.
+ *
+ * @param[in] conn_handle The connection to perform the procedure on.
+ * @param[in] update Whether to perform the procedure.
+ */
+static __INLINE void local_db_update(uint16_t conn_handle, bool update)
+{
+ ble_conn_state_user_flag_set(conn_handle, m_flag_local_db_update_pending, update);
+}
+
+
+/**@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 bool local_db_update_in_evt(uint16_t conn_handle)
+{
+ bool set_procedure_as_pending = false;
+ bool success = false;
+ ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ success = true;
+ break;
+
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ /* Do nothing */
+ break;
+
+ case NRF_ERROR_BUSY:
+ set_procedure_as_pending = true;
+ break;
+
+ case NRF_ERROR_STORAGE_FULL:
+ {
+ pm_evt_t event =
+ {
+ .evt_id = PM_EVT_STORAGE_FULL,
+ .conn_handle = conn_handle,
+ };
+
+ evt_send(&event);
+ break;
+ }
+
+ default:
+ send_unexpected_error(conn_handle, err_code);
+ break;
+ }
+
+ local_db_update(conn_handle, set_procedure_as_pending);
+
+ return success;
+}
+
+#if PM_SERVICE_CHANGED_ENABLED
+/**@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)
+{
+ 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:
+ {
+ pm_evt_t event =
+ {
+ .evt_id = PM_EVT_SERVICE_CHANGED_IND_SENT,
+ .conn_handle = conn_handle,
+ };
+
+ sc_sent_state = true;
+
+ evt_send(&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:
+ send_unexpected_error(conn_handle, err_code);
+ break;
+ }
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_pending, sc_pending_state);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_sent, sc_sent_state);
+}
+#endif
+
+static void apply_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ local_db_apply_in_evt(conn_handle);
+}
+
+
+static __INLINE void apply_pending_flags_check(void)
+{
+ UNUSED_RETURN_VALUE(ble_conn_state_for_each_set_user_flag(m_flag_local_db_apply_pending,
+ apply_pending_handle,
+ NULL));
+}
+
+
+static void db_update_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ if (pm_mutex_lock(&m_db_update_in_progress_mutex, 0))
+ {
+ if (local_db_update_in_evt(conn_handle))
+ {
+ // Successfully started writing to flash.
+ return;
+ }
+ else
+ {
+ pm_mutex_unlock(&m_db_update_in_progress_mutex, 0);
+ }
+ }
+}
+
+
+static __INLINE void update_pending_flags_check(void)
+{
+ UNUSED_RETURN_VALUE(ble_conn_state_for_each_set_user_flag(m_flag_local_db_update_pending,
+ db_update_pending_handle,
+ NULL));
+}
+
+
+#if PM_SERVICE_CHANGED_ENABLED
+static void sc_send_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ if (!ble_conn_state_user_flag_get(conn_handle, m_flag_service_changed_sent))
+ {
+ service_changed_send_in_evt(conn_handle);
+ }
+}
+
+
+static __INLINE void service_changed_pending_flags_check(void)
+{
+ UNUSED_RETURN_VALUE(ble_conn_state_for_each_set_user_flag(m_flag_service_changed_pending,
+ sc_send_pending_handle,
+ NULL));
+}
+#endif
+
+
+/**@brief Callback function for events from the ID Manager module.
+ * This function is registered in the ID Manager module.
+ *
+ * @param[in] p_event The event from the ID Manager module.
+ */
+void gcm_im_evt_handler(pm_evt_t * p_event)
+{
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_BONDED_PEER_CONNECTED:
+ local_db_apply_in_evt(p_event->conn_handle);
+#if (PM_SERVICE_CHANGED_ENABLED == 1)
+ if (gscm_service_changed_ind_needed(p_event->conn_handle))
+ {
+ ble_conn_state_user_flag_set(p_event->conn_handle, m_flag_service_changed_pending, true);
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+
+/**@brief Callback function for events from the Peer Database module.
+ * This handler is extern in Peer Database.
+ *
+ * @param[in] p_event The event from the Security Dispatcher module.
+ */
+void gcm_pdb_evt_handler(pm_evt_t * p_event)
+{
+ if ( p_event->evt_id == PM_EVT_PEER_DATA_UPDATE_SUCCEEDED
+ && p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ {
+ switch (p_event->params.peer_data_update_succeeded.data_id)
+ {
+ case PM_PEER_DATA_ID_BONDING:
+ {
+ uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
+
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ local_db_update(conn_handle, true);
+ }
+ break;
+ }
+
+#if PM_SERVICE_CHANGED_ENABLED
+ case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
+ {
+ ret_code_t err_code;
+ pm_peer_data_flash_t peer_data;
+
+ err_code = pdb_peer_data_ptr_get(p_event->peer_id,
+ PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
+ &peer_data);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (*peer_data.p_service_changed_pending)
+ {
+ uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_pending, true);
+ service_changed_pending_flags_check();
+ }
+ }
+ }
+ break;
+ }
+#endif
+
+ case PM_PEER_DATA_ID_GATT_LOCAL:
+ pm_mutex_unlock(&m_db_update_in_progress_mutex, 0);
+ // Expecting a call to update_pending_flags_check() immediately.
+ break;
+
+ default:
+ /* No action */
+ break;
+ }
+ }
+
+ update_pending_flags_check();
+}
+
+
+ret_code_t gcm_init()
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+
+ m_flag_local_db_update_pending = ble_conn_state_user_flag_acquire();
+ m_flag_local_db_apply_pending = ble_conn_state_user_flag_acquire();
+ m_flag_service_changed_pending = ble_conn_state_user_flag_acquire();
+ m_flag_service_changed_sent = ble_conn_state_user_flag_acquire();
+
+ if ((m_flag_local_db_update_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
+ || (m_flag_local_db_apply_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
+ || (m_flag_service_changed_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
+ || (m_flag_service_changed_sent == BLE_CONN_STATE_USER_FLAG_INVALID)
+ )
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ pm_mutex_init(&m_db_update_in_progress_mutex, 1);
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@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 const * p_ble_evt)
+{
+ uint16_t conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTS_EVT_SYS_ATTR_MISSING:
+ local_db_apply_in_evt(conn_handle);
+ break;
+
+#if PM_SERVICE_CHANGED_ENABLED
+ case BLE_GATTS_EVT_SC_CONFIRM:
+ {
+ pm_evt_t event =
+ {
+ .evt_id = PM_EVT_SERVICE_CHANGED_IND_CONFIRMED,
+ .peer_id = im_peer_id_get_by_conn_handle(conn_handle),
+ .conn_handle = conn_handle,
+ };
+
+ gscm_db_change_notification_done(event.peer_id);
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_sent, false);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_pending, false);
+ evt_send(&event);
+ break;
+ }
+#endif
+
+ case BLE_GATTS_EVT_WRITE:
+ if (cccd_written(&p_ble_evt->evt.gatts_evt.params.write))
+ {
+ local_db_update(conn_handle, true);
+ update_pending_flags_check();
+ }
+ break;
+ }
+
+ apply_pending_flags_check();
+#if PM_SERVICE_CHANGED_ENABLED
+ service_changed_pending_flags_check();
+#endif
+}
+
+
+ret_code_t gcm_local_db_cache_update(uint16_t conn_handle)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ local_db_update(conn_handle, true);
+ update_pending_flags_check();
+
+ return NRF_SUCCESS;
+}
+
+
+#if PM_SERVICE_CHANGED_ENABLED
+void gcm_local_database_has_changed(void)
+{
+ gscm_local_database_has_changed();
+
+ ble_conn_state_conn_handle_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.conn_handles[i]) == PM_PEER_ID_INVALID)
+ {
+ ble_conn_state_user_flag_set(conn_handles.conn_handles[i], m_flag_service_changed_pending, true);
+ }
+ }
+
+ service_changed_pending_flags_check();
+}
+#endif
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h
new file mode 100644
index 0000000..0cb508a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GATT_CACHE_MANAGER_H__
+#define GATT_CACHE_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup gatt_cache_manager GATT Cache Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
+ * attributes.
+ */
+
+
+/**@brief Function for initializing the GATT Cache Manager module.
+ *
+ * @retval NRF_SUCCESS Initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t gcm_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the GATT Cache Manager module.
+ *
+ * @param[in] p_ble_evt The SoftDevice event.
+ */
+void gcm_ble_evt_handler(ble_evt_t const * p_ble_evt);
+
+
+/**@brief Function for triggering local GATT database data to be stored persistently.
+ *
+ * @details Values are retrieved from SoftDevice and written to persistent storage.
+ *
+ * @note This operation happens asynchronously, so any errors are reported as events.
+ *
+ * @note This function is only needed when you want to override the regular functionality of the
+ * module, e.g. to immediately store to flash instead of waiting for the native logic to
+ * perform the update.
+ *
+ * @param[in] conn_handle Connection handle to perform update on.
+ *
+ * @retval NRF_SUCCESS Store operation started.
+ */
+ret_code_t gcm_local_db_cache_update(uint16_t conn_handle);
+
+
+/**@brief Function for manually informing that the local database has changed.
+ *
+ * @details This causes a service changed notification to be sent to all bonded peers that
+ * subscribe to it.
+ */
+void gcm_local_database_has_changed(void);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GATT_CACHE_MANAGER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c
new file mode 100644
index 0000000..3b70837
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c
@@ -0,0 +1,347 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "gatts_cache_manager.h"
+
+#include <string.h>
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "peer_database.h"
+#include "id_manager.h"
+
+
+// Syntactic sugar, two spoons.
+#define SYS_ATTR_SYS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS)
+#define SYS_ATTR_USR (BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS)
+#define SYS_ATTR_BOTH (SYS_ATTR_SYS | SYS_ATTR_USR)
+
+static bool m_module_initialized;
+static pm_peer_id_t m_current_sc_store_peer_id;
+
+
+/**@brief Function for resetting the module variable(s) of the GSCM module.
+ */
+static void internal_state_reset()
+{
+ m_module_initialized = false;
+ m_current_sc_store_peer_id = PM_PEER_ID_INVALID;
+
+ // If PM_SERVICE_CHANGED_ENABLED is 0, this variable is unused.
+ UNUSED_VARIABLE(m_current_sc_store_peer_id);
+}
+
+
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+//lint -save -e550
+/**@brief Function for storing service_changed_pending = true to flash for all peers, in sequence.
+ *
+ * This function aborts if it gets @ref NRF_ERROR_BUSY when trying to store. A subsequent call will
+ * continue where the last call was aborted.
+ */
+static void service_changed_pending_set(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ ret_code_t err_code;
+ // Use a uint32_t to enforce 4-byte alignment.
+ static const uint32_t service_changed_pending = true;
+
+ //lint -save -e65 -e64
+ pm_peer_data_const_t peer_data =
+ {
+ .data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
+ .length_words = PM_SC_STATE_N_WORDS(),
+ .p_service_changed_pending = (bool*)&service_changed_pending,
+ };
+ //lint -restore
+
+ err_code = pdb_raw_store(m_current_sc_store_peer_id, &peer_data, NULL);
+ while ((m_current_sc_store_peer_id != PM_PEER_ID_INVALID) && (err_code != NRF_ERROR_BUSY))
+ {
+ m_current_sc_store_peer_id = pdb_next_peer_id_get(m_current_sc_store_peer_id);
+ err_code = pdb_raw_store(m_current_sc_store_peer_id, &peer_data, NULL);
+ }
+}
+//lint -restore
+
+
+
+/**@brief Event handler for events from the Peer Database module.
+ * This function is extern in Peer Database.
+ *
+ * @param[in] p_event The event that has happend with peer id and flags.
+ */
+void gscm_pdb_evt_handler(pm_evt_t * p_event)
+{
+ if (m_current_sc_store_peer_id != PM_PEER_ID_INVALID)
+ {
+ service_changed_pending_set();
+ }
+}
+#endif
+
+
+ret_code_t gscm_init()
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t gscm_local_db_cache_update(uint16_t conn_handle)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ ret_code_t err_code;
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+ else
+ {
+ pm_peer_data_t peer_data;
+ uint16_t n_bufs = 1;
+ bool retry_with_bigger_buffer = false;
+
+ do
+ {
+ retry_with_bigger_buffer = false;
+
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, n_bufs++, &peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ pm_peer_data_local_gatt_db_t * p_local_gatt_db = peer_data.p_local_gatt_db;
+
+ p_local_gatt_db->flags = SYS_ATTR_BOTH;
+
+ err_code = sd_ble_gatts_sys_attr_get(conn_handle, &p_local_gatt_db->data[0], &p_local_gatt_db->len, p_local_gatt_db->flags);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = pdb_write_buf_store(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, peer_id);
+ }
+ else
+ {
+ if (err_code == NRF_ERROR_DATA_SIZE)
+ {
+ // The sys attributes are bigger than the requested write buffer.
+ retry_with_bigger_buffer = true;
+ }
+ else if (err_code == NRF_ERROR_NOT_FOUND)
+ {
+ // There are no sys attributes in the GATT db, so nothing needs to be stored.
+ err_code = NRF_SUCCESS;
+ }
+
+ ret_code_t err_code_release = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_GATT_LOCAL);
+ if (err_code_release != NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ }
+ else if (err_code == NRF_ERROR_INVALID_PARAM)
+ {
+ // The sys attributes are bigger than the entire write buffer.
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ } while (retry_with_bigger_buffer);
+ }
+
+ return err_code;
+}
+
+
+ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ ret_code_t err_code;
+ pm_peer_data_flash_t peer_data;
+ uint8_t const * p_sys_attr_data = NULL;
+ uint16_t sys_attr_len = 0;
+ uint32_t sys_attr_flags = (SYS_ATTR_BOTH);
+ bool all_attributes_applied = true;
+
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, &peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ pm_peer_data_local_gatt_db_t const * p_local_gatt_db;
+
+ p_local_gatt_db = peer_data.p_local_gatt_db;
+ p_sys_attr_data = p_local_gatt_db->data;
+ sys_attr_len = p_local_gatt_db->len;
+ sys_attr_flags = p_local_gatt_db->flags;
+ }
+ }
+
+ do
+ {
+ err_code = sd_ble_gatts_sys_attr_set(conn_handle, p_sys_attr_data, sys_attr_len, sys_attr_flags);
+
+ if (err_code == NRF_ERROR_NO_MEM)
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+ else if (err_code == NRF_ERROR_INVALID_STATE)
+ {
+ err_code = NRF_SUCCESS;
+ }
+ else if (err_code == NRF_ERROR_INVALID_DATA)
+ {
+ all_attributes_applied = false;
+
+ if (sys_attr_flags & SYS_ATTR_USR)
+ {
+ // Try setting only system attributes.
+ sys_attr_flags = SYS_ATTR_SYS;
+ }
+ else if (p_sys_attr_data || sys_attr_len)
+ {
+ // Try reporting that none exist.
+ p_sys_attr_data = NULL;
+ sys_attr_len = 0;
+ sys_attr_flags = SYS_ATTR_BOTH;
+ }
+ else
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ } while (err_code == NRF_ERROR_INVALID_DATA);
+
+ if (!all_attributes_applied)
+ {
+ err_code = NRF_ERROR_INVALID_DATA;
+ }
+
+ return err_code;
+}
+
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+void gscm_local_database_has_changed(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ m_current_sc_store_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
+ service_changed_pending_set();
+}
+
+
+bool gscm_service_changed_ind_needed(uint16_t conn_handle)
+{
+ ret_code_t err_code;
+ bool service_changed_state;
+ pm_peer_data_flash_t peer_data;
+
+ peer_data.p_service_changed_pending = &service_changed_state;
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING, &peer_data);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return false;
+ }
+
+ return *peer_data.p_service_changed_pending;
+}
+
+
+ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle)
+{
+ static uint16_t start_handle;
+ const uint16_t end_handle = 0xFFFF;
+ ret_code_t err_code;
+
+ err_code = sd_ble_gatts_initial_user_handle_get(&start_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ do
+ {
+ err_code = sd_ble_gatts_service_changed(conn_handle, start_handle, end_handle);
+ if (err_code == BLE_ERROR_INVALID_ATTR_HANDLE)
+ {
+ start_handle += 1;
+ }
+ } while (err_code == BLE_ERROR_INVALID_ATTR_HANDLE);
+
+ return err_code;
+}
+
+
+void gscm_db_change_notification_done(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ // Use a uint32_t to enforce 4-byte alignment.
+ static const uint32_t service_changed_pending = false;
+
+ //lint -save -e65 -e64
+ pm_peer_data_const_t peer_data =
+ {
+ .data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
+ .length_words = PM_SC_STATE_N_WORDS(),
+ .p_service_changed_pending = (bool*)&service_changed_pending,
+ };
+ //lint -restore
+
+ // Don't need to check return code, because all error conditions can be ignored.
+ //lint -save -e550
+ (void) pdb_raw_store(peer_id, &peer_data, NULL);
+ //lint -restore
+}
+#endif
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h
new file mode 100644
index 0000000..b1303df
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h
@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GATTS_CACHE_MANAGER_H__
+#define GATTS_CACHE_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup gatts_cache_manager GATT Server Cache Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
+ * attributes pertaining to the GATT server role of the local device.
+ */
+
+
+/**@brief Function for initializing the GATT Server Cache Manager module.
+ *
+ * @retval NRF_SUCCESS Initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t gscm_init(void);
+
+
+/**@brief Function for triggering local GATT database data to be stored persistently. Values are
+ * retrieved from the SoftDevice and written to persistent storage.
+ *
+ * @param[in] conn_handle Connection handle to perform update on.
+ *
+ * @retval NRF_SUCCESS Store operation started.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection with a
+ * bonded peer.
+ * @retval NRF_ERROR_BUSY Unable to perform operation at this time. Reattempt later.
+ * @retval NRF_ERROR_DATA_SIZE Write buffer not large enough. Call will never work with
+ * this GATT database.
+ * @retval NRF_ERROR_STORAGE_FULL No room in persistent_storage. Free up space; the
+ * operation will be automatically reattempted after the
+ * next FDS garbage collection procedure.
+ */
+ret_code_t gscm_local_db_cache_update(uint16_t conn_handle);
+
+
+/**@brief Function for applying stored local GATT database data to the SoftDevice. Values are
+ * retrieved from persistent storage and given to the SoftDevice.
+ *
+ * @param[in] conn_handle Connection handle to apply values to.
+ *
+ * @retval NRF_SUCCESS Store operation started.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection with a
+ * bonded peer.
+ * @retval NRF_ERROR_INVALID_DATA The stored data was rejected by the SoftDevice, which
+ * probably means that the local database has changed. The
+ * system part of the sys_attributes was attempted applied,
+ * so service changed indications can be sent to subscribers.
+ * @retval NRF_ERROR_BUSY Unable to perform operation at this time. Reattempt later.
+ * @return An unexpected return value from an internal function call.
+ */
+ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle);
+
+
+/**@brief Function for storing the fact that the local database has changed, for all currently
+ * bonded peers.
+ *
+ * @note This will cause a later call to @ref gscm_service_changed_ind_needed to return true for
+ * a connection with a currently bonded peer.
+ */
+void gscm_local_database_has_changed(void);
+
+
+/**@brief Function for checking if a service changed indication should be sent.
+ *
+ * @param[in] conn_handle The connection to check.
+ *
+ * @return true if a service changed indication should be sent, false if not.
+ */
+bool gscm_service_changed_ind_needed(uint16_t conn_handle);
+
+
+/**@brief Function for sending a service changed indication to a connected peer.
+ *
+ * @param[in] conn_handle The connection to send the indication on.
+ *
+ * @retval NRF_SUCCESS Indication sent or not needed.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection.
+ * @retval NRF_ERROR_BUSY Unable to send indication at this time. Reattempt later.
+ * @retval BLE_ERROR_GATTS_SYS_ATTR_MISSING Information missing. Apply local cache, then reattempt.
+ * @retval NRF_ERROR_INVALID_PARAM From @ref sd_ble_gatts_service_changed. Unexpected.
+ * @retval NRF_ERROR_NOT_SUPPORTED Service changed characteristic is not present.
+ * @retval NRF_ERROR_INVALID_STATE Service changed cannot be indicated to this peer
+ * because the peer has not subscribed to it.
+ * @retval NRF_ERROR_INTERNAL An unexpected error happened.
+ */
+ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle);
+
+
+/**@brief Function for specifying that a peer has been made aware of the latest local database
+ * change.
+ *
+ * @note After calling this, a later call to @ref gscm_service_changed_ind_needed will to return
+ * false for this peer unless @ref gscm_local_database_has_changed is called again.
+ *
+ * @param[in] peer_id The connection to send the indication on.
+ */
+void gscm_db_change_notification_done(pm_peer_id_t peer_id);
+
+/** @}
+ * @endcond
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GATTS_CACHE_MANAGER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c
new file mode 100644
index 0000000..bbe7702
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c
@@ -0,0 +1,890 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "id_manager.h"
+
+#include <string.h>
+#include "ble.h"
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "ble_conn_state.h"
+#include "peer_manager_types.h"
+#include "peer_database.h"
+#include "peer_data_storage.h"
+#include "nrf_soc.h"
+
+
+#define IM_MAX_CONN_HANDLES (20)
+#define IM_NO_INVALID_CONN_HANDLES (0xFF)
+#define IM_ADDR_CLEARTEXT_LENGTH (3)
+#define IM_ADDR_CIPHERTEXT_LENGTH (3)
+
+// The number of registered event handlers.
+#define IM_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Identity Manager event handlers in Peer Manager and GATT Cache Manager.
+extern void pm_im_evt_handler(pm_evt_t * p_event);
+extern void gcm_im_evt_handler(pm_evt_t * p_event);
+
+// Identity Manager events' handlers.
+// The number of elements in this array is IM_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pm_im_evt_handler,
+ gcm_im_evt_handler
+};
+
+
+typedef struct
+{
+ pm_peer_id_t peer_id;
+ uint16_t conn_handle;
+ ble_gap_addr_t peer_address;
+} im_connection_t;
+
+static bool m_module_initialized;
+static im_connection_t m_connections[IM_MAX_CONN_HANDLES];
+static ble_conn_state_user_flag_id_t m_conn_state_user_flag_id;
+
+static uint8_t m_wlisted_peer_cnt;
+static pm_peer_id_t m_wlisted_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+
+
+static void internal_state_reset()
+{
+ m_conn_state_user_flag_id = BLE_CONN_STATE_USER_FLAG_INVALID;
+
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ m_connections[i].conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+}
+
+
+/**@brief Function for sending an event to all registered event handlers.
+ *
+ * @param[in] p_event The event to distribute.
+ */
+static void evt_send(pm_evt_t * p_event)
+{
+ for (uint32_t i = 0; i < IM_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+/**@brief Function finding a free position in m_connections.
+ *
+ * @detail All connection handles in the m_connections array are checked against the connection
+ * state module. The index of the first one that is not a connection handle for a current
+ * connection is returned. This position in the array can safely be used for a new connection.
+ *
+ * @return Either the index of a free position in the array or IM_NO_INVALID_CONN_HANDLES if no free
+ position exists.
+ */
+uint8_t get_free_connection()
+{
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ // Query the connection state module to check if the
+ // connection handle does not belong to a valid connection.
+ if (!ble_conn_state_user_flag_get(m_connections[i].conn_handle, m_conn_state_user_flag_id))
+ {
+ return i;
+ }
+ }
+ // If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
+ return IM_NO_INVALID_CONN_HANDLES;
+}
+
+
+/**@brief Function finding a particular connection handle m_connections.
+ *
+ * @param[in] conn_handle The handle to find.
+ *
+ * @return Either the index of the conn_handle in the array or IM_NO_INVALID_CONN_HANDLES if the
+ * handle was not found.
+ */
+uint8_t get_connection_by_conn_handle(uint16_t conn_handle)
+{
+ if (ble_conn_state_user_flag_get(conn_handle, m_conn_state_user_flag_id))
+ {
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ if (m_connections[i].conn_handle == conn_handle)
+ {
+ return i;
+ }
+ }
+ }
+ // If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
+ return IM_NO_INVALID_CONN_HANDLES;
+}
+
+
+/**@brief Function for registering a new connection instance.
+ *
+ * @param[in] conn_handle The handle of the new connection.
+ * @param[in] p_ble_addr The address used to connect.
+ *
+ * @return Either the index of the new connection in the array or IM_NO_INVALID_CONN_HANDLES if no
+ * free position exists.
+ */
+uint8_t new_connection(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
+{
+ uint8_t conn_index = IM_NO_INVALID_CONN_HANDLES;
+
+ if ((p_ble_addr != NULL) && (conn_handle != BLE_CONN_HANDLE_INVALID))
+ {
+ ble_conn_state_user_flag_set(conn_handle, m_conn_state_user_flag_id, true);
+
+ conn_index = get_connection_by_conn_handle(conn_handle);
+ if (conn_index == IM_NO_INVALID_CONN_HANDLES)
+ {
+ conn_index = get_free_connection();
+ }
+
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ m_connections[conn_index].conn_handle = conn_handle;
+ m_connections[conn_index].peer_id = PM_PEER_ID_INVALID;
+ m_connections[conn_index].peer_address = *p_ble_addr;
+ }
+ }
+ return conn_index;
+}
+
+
+/**@brief Function checking the validity of an IRK
+ *
+ * @detail An all-zero IRK is not valid. This function will check if a given IRK is valid.
+ *
+ * @param[in] p_irk The IRK for which the validity is going to be checked.
+ *
+ * @retval true The IRK is valid.
+ * @retval false The IRK is invalid.
+ */
+bool is_valid_irk(ble_gap_irk_t const * p_irk)
+{
+ NRF_PM_DEBUG_CHECK(p_irk != NULL);
+
+ for (uint32_t i = 0; i < BLE_GAP_SEC_KEY_LEN; i++)
+ {
+ if (p_irk->irk[i] != 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**@brief Function for comparing two addresses to determine if they are identical
+ *
+ * @note The address type need to be identical, as well as every bit in the address itself.
+ *
+ * @param[in] p_addr1 The first address to be compared.
+ * @param[in] p_addr2 The second address to be compared.
+ *
+ * @retval true The addresses are identical.
+ * @retval false The addresses are not identical.
+ */
+bool addr_compare(ble_gap_addr_t const * p_addr1, ble_gap_addr_t const * p_addr2)
+{
+ // @note emdi: use NRF_PM_DEBUG_CHECK ?
+ if ((p_addr1 == NULL) || (p_addr2 == NULL))
+ {
+ return false;
+ }
+
+ // Check that the addr type is identical, return false if it is not
+ if (p_addr1->addr_type != p_addr2->addr_type)
+ {
+ return false;
+ }
+
+ // Check if the addr bytes are is identical
+ return (memcmp(p_addr1->addr, p_addr2->addr, BLE_GAP_ADDR_LEN) == 0);
+}
+
+
+void im_ble_evt_handler(ble_evt_t const * 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_ble_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_ble_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
+ pm_evt_t im_evt;
+ im_evt.conn_handle = gap_evt.conn_handle;
+ im_evt.peer_id = bonded_matching_peer_id;
+ im_evt.evt_id = PM_EVT_BONDED_PEER_CONNECTED;
+ evt_send(&im_evt);
+ }
+}
+
+
+/**@brief Function to compare two sets of bonding data to check if they belong to the same device.
+ * @note Invalid irks will never match even though they are identical.
+ *
+ * @param[in] p_bonding_data1 First bonding data for comparison
+ * @param[in] p_bonding_data2 Second bonding data for comparison
+ *
+ * @return True if the input matches, false if it does not.
+ */
+bool im_is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1,
+ pm_peer_data_bonding_t const * p_bonding_data2)
+{
+ NRF_PM_DEBUG_CHECK(p_bonding_data1 != NULL);
+ NRF_PM_DEBUG_CHECK(p_bonding_data2 != NULL);
+
+ ble_gap_addr_t const * p_addr1 = &p_bonding_data1->peer_ble_id.id_addr_info;
+ ble_gap_addr_t const * p_addr2 = &p_bonding_data2->peer_ble_id.id_addr_info;
+
+ bool duplicate_irk = ((memcmp(p_bonding_data1->peer_ble_id.id_info.irk,
+ p_bonding_data2->peer_ble_id.id_info.irk,
+ BLE_GAP_SEC_KEY_LEN) == 0)
+ && is_valid_irk(&p_bonding_data1->peer_ble_id.id_info)
+ && is_valid_irk(&p_bonding_data2->peer_ble_id.id_info));
+
+ bool duplicate_addr = addr_compare(p_addr1, p_addr2);
+
+ bool id_addrs = ((p_addr1->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+ && (p_addr1->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)
+ && (p_addr2->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+ && (p_addr2->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE));
+
+ return (duplicate_addr && id_addrs) || (duplicate_irk && !id_addrs);
+}
+
+
+pm_peer_id_t im_find_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data,
+ pm_peer_id_t peer_id_skip)
+{
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data_duplicate;
+
+ NRF_PM_DEBUG_CHECK(p_bonding_data != NULL);
+
+ pds_peer_data_iterate_prepare();
+
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data_duplicate))
+ {
+ if ( (peer_id != peer_id_skip)
+ && im_is_duplicate_bonding_data(p_bonding_data,
+ peer_data_duplicate.p_bonding_data))
+ {
+ return peer_id;
+ }
+ }
+ return PM_PEER_ID_INVALID;
+}
+
+
+ret_code_t im_init(void)
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+
+ m_conn_state_user_flag_id = ble_conn_state_user_flag_acquire();
+ if (m_conn_state_user_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle)
+{
+ uint8_t conn_index;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ conn_index = get_connection_by_conn_handle(conn_handle);
+
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ return m_connections[conn_index].peer_id;
+ }
+
+ return PM_PEER_ID_INVALID;
+}
+
+
+ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
+{
+ uint8_t conn_index;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_ble_addr != NULL);
+
+ conn_index = get_connection_by_conn_handle(conn_handle);
+
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ *p_ble_addr = m_connections[conn_index].peer_address;
+ return NRF_SUCCESS;
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1,
+ ble_gap_master_id_t const * p_master_id2)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_master_id1 != NULL);
+ NRF_PM_DEBUG_CHECK(p_master_id2 != NULL);
+
+ if (!im_master_id_is_valid(p_master_id1))
+ {
+ return false;
+ }
+
+ if (p_master_id1->ediv != p_master_id2->ediv)
+ {
+ return false;
+ }
+
+ return (memcmp(p_master_id1->rand, p_master_id2->rand, BLE_GAP_SEC_RAND_LEN) == 0);
+}
+
+
+pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t const * p_master_id)
+{
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_master_id != NULL);
+
+ pds_peer_data_iterate_prepare();
+
+ // For each stored peer, check if the master_id matches p_master_id
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data))
+ {
+ if (im_master_ids_compare(p_master_id, &peer_data.p_bonding_data->own_ltk.master_id) ||
+ im_master_ids_compare(p_master_id, &peer_data.p_bonding_data->peer_ltk.master_id))
+ {
+ // If a matching master ID is found then return the peer ID.
+ return peer_id;
+ }
+ }
+
+ // If no matching master ID is found return PM_PEER_ID_INVALID.
+ return PM_PEER_ID_INVALID;
+}
+
+
+uint16_t im_conn_handle_get(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ if (peer_id == m_connections[i].peer_id)
+ {
+ return m_connections[i].conn_handle;
+ }
+ }
+ return BLE_CONN_HANDLE_INVALID;
+}
+
+
+bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ if (p_master_id->ediv != 0)
+ {
+ return true;
+ }
+
+ for (uint32_t i = 0; i < BLE_GAP_SEC_RAND_LEN; i++)
+ {
+ if (p_master_id->rand[i] != 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**@brief Function to set the peer ID associated with a connection handle.
+ *
+ * @param[in] conn_handle The connection handle.
+ * @param[in] peer_id The peer ID to associate with @c conn_handle.
+ */
+static void peer_id_set(uint16_t conn_handle, pm_peer_id_t peer_id)
+{
+ uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ m_connections[conn_index].peer_id = peer_id;
+ }
+}
+
+
+void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ peer_id_set(conn_handle, peer_id);
+}
+
+
+ret_code_t im_peer_free(pm_peer_id_t peer_id)
+{
+ uint16_t conn_handle;
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ conn_handle = im_conn_handle_get(peer_id);
+ ret = pdb_peer_free(peer_id);
+
+ if ((conn_handle != BLE_CONN_HANDLE_INVALID) && (ret == NRF_SUCCESS))
+ {
+ peer_id_set(conn_handle, PM_PEER_ID_INVALID);
+ }
+ return ret;
+}
+
+
+/**@brief Given a list of peers, loads their GAP address and IRK into the provided buffers.
+ */
+static ret_code_t peers_id_keys_get(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt,
+ ble_gap_addr_t * p_gap_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_gap_irks,
+ uint32_t * p_irk_cnt)
+{
+ ret_code_t ret;
+
+ pm_peer_data_bonding_t bond_data;
+ pm_peer_data_t peer_data;
+
+ uint32_t const buf_size = sizeof(bond_data);
+
+ bool copy_addrs = false;
+ bool copy_irks = false;
+
+ NRF_PM_DEBUG_CHECK(p_peers != NULL);
+
+ // One of these two has to be provided.
+ NRF_PM_DEBUG_CHECK((p_gap_addrs != NULL) || (p_gap_irks != NULL));
+
+ if ((p_gap_addrs != NULL) && (p_addr_cnt != NULL))
+ {
+ NRF_PM_DEBUG_CHECK((*p_addr_cnt) >= peer_cnt);
+
+ copy_addrs = true;
+ *p_addr_cnt = 0;
+ }
+
+ if ((p_gap_irks != NULL) && (p_irk_cnt != NULL))
+ {
+ NRF_PM_DEBUG_CHECK((*p_irk_cnt) >= peer_cnt);
+
+ copy_irks = true;
+ *p_irk_cnt = 0;
+ }
+
+ memset(&peer_data, 0x00, sizeof(peer_data));
+ peer_data.p_bonding_data = &bond_data;
+
+ // Read through flash memory and look for peers ID keys.
+
+ for (uint32_t i = 0; i < peer_cnt; i++)
+ {
+ memset(&bond_data, 0x00, sizeof(bond_data));
+
+ // Read peer data from flash.
+ ret = pds_peer_data_read(p_peers[i], PM_PEER_DATA_ID_BONDING,
+ &peer_data, &buf_size);
+
+ if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM))
+ {
+ // Peer data coulnd't be found in flash or peer ID is not valid.
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ uint8_t const addr_type = bond_data.peer_ble_id.id_addr_info.addr_type;
+
+ if ((addr_type != BLE_GAP_ADDR_TYPE_PUBLIC) &&
+ (addr_type != BLE_GAP_ADDR_TYPE_RANDOM_STATIC))
+ {
+ // The address shared by the peer during bonding can't be used for whitelisting.
+ return BLE_ERROR_GAP_INVALID_BLE_ADDR;
+ }
+
+ // Copy the GAP address.
+ if (copy_addrs)
+ {
+ memcpy(&p_gap_addrs[i], &bond_data.peer_ble_id.id_addr_info, sizeof(ble_gap_addr_t));
+ (*p_addr_cnt)++;
+ }
+
+ // Copy the IRK.
+ if (copy_irks)
+ {
+ memcpy(&p_gap_irks[i], bond_data.peer_ble_id.id_info.irk, BLE_GAP_SEC_KEY_LEN);
+ (*p_irk_cnt)++;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t im_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ ret_code_t ret;
+ pm_peer_data_t peer_data;
+ pm_peer_data_bonding_t bond_data;
+
+ ble_gap_id_key_t keys[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
+ ble_gap_id_key_t const * key_ptrs[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
+
+ if ((p_peers == NULL) || (peer_cnt == 0))
+ {
+ // Clear the device identities list.
+ return sd_ble_gap_device_identities_set(NULL, NULL, 0);
+ }
+
+ peer_data.p_bonding_data = &bond_data;
+ uint32_t const buf_size = sizeof(bond_data);
+
+ memset(keys, 0x00, sizeof(keys));
+ for (uint32_t i = 0; i < BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT; i++)
+ {
+ key_ptrs[i] = &keys[i];
+ }
+
+ for (uint32_t i = 0; i < peer_cnt; i++)
+ {
+ memset(&bond_data, 0x00, sizeof(bond_data));
+
+ // Read peer data from flash.
+ ret = pds_peer_data_read(p_peers[i], PM_PEER_DATA_ID_BONDING,
+ &peer_data, &buf_size);
+
+ if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM))
+ {
+ // Peer data coulnd't be found in flash or peer ID is not valid.
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ uint8_t const addr_type = bond_data.peer_ble_id.id_addr_info.addr_type;
+
+ if ((addr_type != BLE_GAP_ADDR_TYPE_PUBLIC) &&
+ (addr_type != BLE_GAP_ADDR_TYPE_RANDOM_STATIC))
+ {
+ // The address shared by the peer during bonding can't be whitelisted.
+ return BLE_ERROR_GAP_INVALID_BLE_ADDR;
+ }
+
+ // Copy data to the buffer.
+ memcpy(&keys[i], &bond_data.peer_ble_id, sizeof(ble_gap_id_key_t));
+ }
+
+ return sd_ble_gap_device_identities_set(key_ptrs, NULL, peer_cnt);
+}
+
+
+ret_code_t im_id_addr_set(ble_gap_addr_t const * p_addr)
+{
+ return sd_ble_gap_addr_set(p_addr);
+}
+
+
+ret_code_t im_id_addr_get(ble_gap_addr_t * p_addr)
+{
+ NRF_PM_DEBUG_CHECK(p_addr != NULL);
+
+ return sd_ble_gap_addr_get(p_addr);
+}
+
+
+ret_code_t im_privacy_set(pm_privacy_params_t const * p_privacy_params)
+{
+ return sd_ble_gap_privacy_set(p_privacy_params);
+}
+
+
+ret_code_t im_privacy_get(pm_privacy_params_t * p_privacy_params)
+{
+ return sd_ble_gap_privacy_get(p_privacy_params);
+}
+
+
+/* Create a whitelist for the user using the cached list of peers.
+ * This whitelist is meant to be provided by the application to the Advertising module.
+ */
+ret_code_t im_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt)
+{
+ // One of the two buffers has to be provided.
+ NRF_PM_DEBUG_CHECK((p_addrs != NULL) || (p_irks != NULL));
+ NRF_PM_DEBUG_CHECK((p_addr_cnt != NULL) || (p_irk_cnt != NULL));
+
+ if (((p_addr_cnt != NULL) && (m_wlisted_peer_cnt > *p_addr_cnt)) ||
+ ((p_irk_cnt != NULL) && (m_wlisted_peer_cnt > *p_irk_cnt)))
+ {
+ // The size of the cached list of peers is larger than the provided buffers.
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // NRF_SUCCESS or
+ // NRF_ERROR_NOT_FOUND, if a peer or its data were not found.
+ // BLE_ERROR_GAP_INVALID_BLE_ADDR, if a peer address can not be used for whitelisting.
+ return peers_id_keys_get(m_wlisted_peers, m_wlisted_peer_cnt,
+ p_addrs, p_addr_cnt,
+ p_irks, p_irk_cnt);
+}
+
+
+/* Copies the peers to whitelist into a local cache.
+ * The cached list will be used by im_whitelist_get() to retrieve the active whitelist.
+ * For SoftDevices 3x, also loads the peers' GAP addresses and whitelists them using
+ * sd_ble_gap_whitelist_set().
+ */
+ret_code_t im_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ // Clear the cache of whitelisted peers.
+ memset(m_wlisted_peers, 0x00, sizeof(m_wlisted_peers));
+
+ if ((p_peers == NULL) || (peer_cnt == 0))
+ {
+ // Clear the current whitelist.
+ m_wlisted_peer_cnt = 0;
+
+ // NRF_SUCCESS, or
+ // BLE_GAP_ERROR_WHITELIST_IN_USE
+ return sd_ble_gap_whitelist_set(NULL, 0);
+ }
+
+ // @todo emdi: should not ever cache more than BLE_GAP_WHITELIST_ADDR_MAX_COUNT...
+
+ // Copy the new whitelisted peers.
+ m_wlisted_peer_cnt = peer_cnt;
+ memcpy(m_wlisted_peers, p_peers, sizeof(pm_peer_id_t) * peer_cnt);
+
+ ret_code_t ret;
+ uint32_t wlist_addr_cnt = 0;
+
+ ble_gap_addr_t const * addr_ptrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+ ble_gap_addr_t addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+
+ memset(addrs, 0x00, sizeof(addrs));
+
+ // Fetch GAP addresses for these peers, but don't fetch IRKs.
+ ret = peers_id_keys_get(p_peers, peer_cnt, addrs, &wlist_addr_cnt, NULL, NULL);
+
+ if (ret != NRF_SUCCESS)
+ {
+ // NRF_ERROR_NOT_FOUND, if a peer or its data were not found.
+ // BLE_ERROR_GAP_INVALID_BLE_ADDR, if a peer address can not be used for whitelisting.
+ return ret;
+ }
+
+ for (uint32_t i = 0; i < BLE_GAP_WHITELIST_ADDR_MAX_COUNT; i++)
+ {
+ addr_ptrs[i] = &addrs[i];
+ }
+
+ // NRF_ERROR_DATA_SIZE, if peer_cnt > BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ // BLE_ERROR_GAP_WHITELIST_IN_USE, if a whitelist is in use.
+ return sd_ble_gap_whitelist_set(addr_ptrs, peer_cnt);
+}
+
+
+/**@brief Function for calculating the ah() hash function described in Bluetooth core specification
+ * 4.2 section 3.H.2.2.2.
+ *
+ * @detail BLE uses a hash function to calculate the first half of a resolvable address
+ * from the second half of the address and an irk. This function will use the ECB
+ * periferal to hash these data acording to the Bluetooth core specification.
+ *
+ * @note The ECB expect little endian input and output.
+ * This function expect big endian and will reverse the data as necessary.
+ *
+ * @param[in] p_k The key used in the hash function.
+ * For address resolution this is should be the irk.
+ * The array must have a length of 16.
+ * @param[in] p_r The rand used in the hash function. For generating a new address
+ * this would be a random number. For resolving a resolvable address
+ * this would be the last half of the address being resolved.
+ * The array must have a length of 3.
+ * @param[out] p_local_hash The result of the hash operation. For address resolution this
+ * will match the first half of the address being resolved if and only
+ * if the irk used in the hash function is the same one used to generate
+ * the address.
+ * The array must have a length of 16.
+ */
+void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash)
+{
+ nrf_ecb_hal_data_t ecb_hal_data;
+
+ for (uint32_t i = 0; i < SOC_ECB_KEY_LENGTH; i++)
+ {
+ ecb_hal_data.key[i] = p_k[SOC_ECB_KEY_LENGTH - 1 - i];
+ }
+
+ memset(ecb_hal_data.cleartext, 0, SOC_ECB_KEY_LENGTH - IM_ADDR_CLEARTEXT_LENGTH);
+
+ for (uint32_t i = 0; i < IM_ADDR_CLEARTEXT_LENGTH; i++)
+ {
+ ecb_hal_data.cleartext[SOC_ECB_KEY_LENGTH - 1 - i] = p_r[i];
+ }
+
+ // Can only return NRF_SUCCESS.
+ (void) sd_ecb_block_encrypt(&ecb_hal_data);
+
+ for (uint32_t i = 0; i < IM_ADDR_CIPHERTEXT_LENGTH; i++)
+ {
+ p_local_hash[i] = ecb_hal_data.ciphertext[SOC_ECB_KEY_LENGTH - 1 - i];
+ }
+}
+
+
+bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint8_t hash[IM_ADDR_CIPHERTEXT_LENGTH];
+ uint8_t local_hash[IM_ADDR_CIPHERTEXT_LENGTH];
+ uint8_t prand[IM_ADDR_CLEARTEXT_LENGTH];
+
+ if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+ {
+ return false;
+ }
+
+ memcpy(hash, p_addr->addr, IM_ADDR_CIPHERTEXT_LENGTH);
+ memcpy(prand, &p_addr->addr[IM_ADDR_CIPHERTEXT_LENGTH], IM_ADDR_CLEARTEXT_LENGTH);
+ ah(p_irk->irk, prand, local_hash);
+
+ return (memcmp(hash, local_hash, IM_ADDR_CIPHERTEXT_LENGTH) == 0);
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h
new file mode 100644
index 0000000..fc73958
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h
@@ -0,0 +1,327 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_ID_MANAGER_H__
+#define PEER_ID_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup id_manager ID Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for keeping track of peer identities
+ * (IRK and peer address).
+ */
+
+
+/**@brief Function for initializing the Identity manager.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an error occurred.
+ */
+ret_code_t im_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the ID Manager module.
+ *
+ * @param[in] p_ble_evt The SoftDevice event.
+ */
+void im_ble_evt_handler(ble_evt_t const * p_ble_evt);
+
+
+/**@brief Function for getting the corresponding peer ID from a connection handle.
+ *
+ * @param[in] conn_handle The connection handle.
+ *
+ * @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
+ */
+pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle);
+
+
+/**@brief Function for getting the corresponding peer ID from a master ID (EDIV and rand).
+ *
+ * @param[in] p_master_id The master ID.
+ *
+ * @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
+ */
+pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t const * p_master_id);
+
+
+/**@brief Function for getting the corresponding connection handle from a peer ID.
+ *
+ * @param[in] peer_id The peer ID.
+ *
+ * @return The corresponding connection handle, or @ref BLE_CONN_HANDLE_INVALID if none could be
+ * resolved.
+ */
+uint16_t im_conn_handle_get(pm_peer_id_t peer_id);
+
+
+/**@brief Function for comparing two master ids
+ * @note Two invalid master IDs will not match.
+ *
+ * @param[in] p_master_id1 First master id for comparison
+ * @param[in] p_master_id2 Second master id for comparison
+ *
+ * @return True if the input matches, false if it does not.
+ */
+bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1,
+ ble_gap_master_id_t const * p_master_id2);
+
+
+/**@brief Function for getting the BLE address used by the peer when connecting.
+ *
+ * @param[in] conn_handle The connection handle.
+ * @param[out] p_ble_addr The BLE address used by the peer when the connection specified by
+ * conn_handle was established.
+ *
+ * @retval NRF_SUCCESS The address was found and copied.
+ * @retval BLE_ERROR_CONN_HANDLE_INVALID conn_handle does not refer to an active connection.
+ * @retval NRF_ERROR_NULL p_ble_addr was NULL.
+ */
+ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr);
+
+
+/**@brief Function for checking if a master ID is valid or invalid
+ *
+ * @param[in] p_master_id The master ID.
+ *
+ * @retval true The master id is valid.
+ * @retval false The master id is invalid (i.e. all zeros).
+ */
+bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id);
+
+
+/**@brief Function for checking if two pieces of bonding data correspond to the same peer.
+ *
+ * @param[in] p_bonding_data1 The first piece of bonding data to check.
+ * @param[in] p_bonding_data2 The second piece of bonding data to check.
+ *
+ * @retval true The bonding data correspond to the same peer.
+ * @retval false The bonding data do not correspond to the same peer.
+ */
+bool im_is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1,
+ pm_peer_data_bonding_t const * p_bonding_data2);
+
+
+/**@brief Function for finding if we are already bonded to a peer.
+ *
+ * @param[in] p_bonding_data The bonding data to check.
+ * @param[in] peer_id_skip Optional peer to ignore when searching for duplicates.
+ *
+ * @return An existing peer ID for the peer, or PM_PEER_ID_INVALID if none was found.
+ */
+pm_peer_id_t im_find_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data,
+ pm_peer_id_t peer_id_skip);
+
+
+/**@brief Function for reporting that a new peer ID has been allocated for a specified connection.
+ *
+ * @param[in] conn_handle The connection.
+ * @param[in] peer_id The new peer ID.
+ */
+void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id);
+
+
+/**@brief Function for deleting all of a peer's data from flash and disassociating it from any
+ * connection handles it is associated with.
+ *
+ * @param[in] peer_id The peer to free.
+ *
+ * @return Any error code returned by @ref pdb_peer_free.
+ */
+ret_code_t im_peer_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function to set the local Bluetooth identity address.
+ *
+ * @details The local Bluetooth identity address is the address that identifies this device to other
+ * peers. The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC. The identity address cannot be changed while roles are
+ * running.
+ *
+ * @note This address will be distributed to the peer during bonding.
+ * If the address changes, the address stored in the peer device will not be valid and the
+ * ability to reconnect using the old address will be lost.
+ *
+ * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC
+ * upon being enabled. The address is a random number populated during the IC manufacturing
+ * process and remains unchanged for the lifetime of each IC.
+ *
+ * @param[in] p_addr Pointer to address structure.
+ *
+ * @retval NRF_SUCCESS Address successfully set.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If the GAP address is invalid.
+ * @retval NRF_ERROR_BUSY Could not process at this time. Process SoftDevice events
+ * and retry.
+ * @retval NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising,
+ * scanning, or while in a connection.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t im_id_addr_set(ble_gap_addr_t const * p_addr);
+
+
+/**@brief Function to get the local Bluetooth identity address.
+ *
+ * @note This will always return the identity address irrespective of the privacy settings,
+ * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC.
+ *
+ * @param[out] p_addr Pointer to address structure to be filled in.
+ *
+ * @retval NRF_SUCCESS If the address was successfully retrieved.
+ */
+ret_code_t im_id_addr_get(ble_gap_addr_t * p_addr);
+
+
+/**@brief Function to set privacy settings.
+ *
+ * @details Privacy settings cannot be set while advertising, scanning, or while in a connection.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS If privacy options were set successfully.
+ * @retval NRF_ERROR_NULL If @p p_privacy_params is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If the address type is not valid.
+ * @retval NRF_ERROR_BUSY If the request could not be processed at this time.
+ * Process SoftDevice events and retry.
+ * @retval NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while BLE roles using
+ * privacy are enabled.
+ */
+ret_code_t im_privacy_set(pm_privacy_params_t const * p_privacy_params);
+
+
+/**@brief Function to retrieve the current privacy settings.
+ *
+ * @details The privacy settings returned include the current device irk as well.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS Successfully retrieved privacy settings.
+ * @retval NRF_ERROR_NULL @c p_privacy_params is NULL.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t im_privacy_get(pm_privacy_params_t * p_privacy_params);
+
+
+/**@brief Function for resolving a resolvable address with an identity resolution key (IRK).
+ *
+ * @details This function will use the ECB peripheral to resolve a resolvable address.
+ * This can be used to resolve the identity of a device distributing a random
+ * resolvable address based on any IRKs you have received earlier. If an address is
+ * resolved by an IRK, the device distributing the address must also know the IRK.
+ *
+ * @param[in] p_addr A random resolvable address.
+ * @param[in] p_irk An identity resolution key (IRK).
+ *
+ * @retval true The irk used matched the one used to create the address.
+ * @retval false The irk used did not match the one used to create the address, or an argument was
+ * NULL.
+ */
+bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
+
+
+/**@brief Function for setting / clearing the whitelist.
+ *
+ * @param p_peers The peers to whitelist. Pass NULL to clear the whitelist.
+ * @param peer_cnt The number of peers to whitelist. Pass zero to clear the whitelist.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully set or cleared.
+ * @retval BLE_GAP_ERROR_WHITELIST_IN_USE If a whitelist is in use.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If any peer has an address which can not be used
+ * for whitelisting.
+ * @retval NRF_ERROR_NOT_FOUND If any peer or its data could not be found.
+ * @retval NRF_ERROR_DATA_SIZE If @p peer_cnt is greater than
+ * @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ */
+ret_code_t im_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t const peer_cnt);
+
+
+/**@brief Retrieves the current whitelist, set by a previous call to @ref im_whitelist_set.
+ *
+ * @param[out] A buffer where to copy the GAP addresses.
+ * @param[inout] In: the size of the @p p_addrs buffer.
+ * Out: the number of address copied into the buffer.
+ * @param[out] A buffer where to copy the IRKs.
+ * @param[inout] In: the size of the @p p_irks buffer.
+ * Out: the number of IRKs copied into the buffer.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully retreived.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If any peer has an address which can not be used for
+ * whitelisting.
+ * @retval NRF_ERROR_NOT_FOUND If the data for any of the cached whitelisted peers
+ * can not be found anymore. It might have been deleted in
+ * the meanwhile.
+ * @retval NRF_ERROR_NO_MEM If the provided buffers are too small.
+ */
+ret_code_t im_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt);
+
+
+/**@brief Set the device identities list.
+ */
+ret_code_t im_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt);
+
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_ID_MANAGER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c
new file mode 100644
index 0000000..12058d7
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c
@@ -0,0 +1,678 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "peer_data_storage.h"
+
+#include <stdint.h>
+#include <string.h>
+#include "sdk_errors.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "peer_id.h"
+#include "fds.h"
+
+
+// Macro for verifying that the peer id is within a valid range.
+#define VERIFY_PEER_ID_IN_RANGE(id) VERIFY_FALSE((id >= PM_PEER_ID_N_AVAILABLE_IDS), \
+ NRF_ERROR_INVALID_PARAM)
+
+// Macro for verifying that the peer data id is withing a valid range.
+#define VERIFY_PEER_DATA_ID_IN_RANGE(id) VERIFY_TRUE(peer_data_id_is_valid(id), \
+ NRF_ERROR_INVALID_PARAM)
+
+// The number of registered event handlers.
+#define PDS_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Peer Data Storage event handler in Peer Database.
+extern void pdb_pds_evt_handler(pm_evt_t *);
+
+// Peer Data Storage events' handlers.
+// The number of elements in this array is PDS_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pdb_pds_evt_handler,
+};
+
+static bool m_module_initialized = false;
+static volatile bool m_peer_delete_deferred = false;
+
+// A token used for Flash Data Storage searches.
+static fds_find_token_t m_fds_ftok;
+
+
+// Function for dispatching events to all registered event handlers.
+static void pds_evt_send(pm_evt_t * p_event)
+{
+ p_event->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ for (uint32_t i = 0; i < PDS_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+// Function to convert peer IDs to file IDs.
+static uint16_t peer_id_to_file_id(pm_peer_id_t peer_id)
+{
+ return (uint16_t)(peer_id + PEER_ID_TO_FILE_ID);
+}
+
+
+// Function to convert peer data id to type id.
+static pm_peer_id_t file_id_to_peer_id(uint16_t file_id)
+{
+ return (pm_peer_id_t)(file_id + FILE_ID_TO_PEER_ID);
+}
+
+
+// Function to convert peer data IDs to record keys.
+static uint16_t peer_data_id_to_record_key(pm_peer_data_id_t peer_data_id)
+{
+ return (uint16_t)(peer_data_id + DATA_ID_TO_RECORD_KEY);
+}
+
+
+// Function to convert record keys to peer data IDs.
+static pm_peer_data_id_t record_key_to_peer_data_id(uint16_t record_key)
+{
+ return (pm_peer_data_id_t)(record_key + RECORD_KEY_TO_DATA_ID);
+}
+
+
+// Function for checking whether a file ID is relevant for the Peer Manager.
+static bool file_id_within_pm_range(uint16_t file_id)
+{
+ return ((PDS_FIRST_RESERVED_FILE_ID <= file_id)
+ && (file_id <= PDS_LAST_RESERVED_FILE_ID));
+}
+
+
+// Function for checking whether a record key is relevant for the Peer Manager.
+static bool record_key_within_pm_range(uint16_t record_key)
+{
+ return ((PDS_FIRST_RESERVED_RECORD_KEY <= record_key)
+ && (record_key <= PDS_LAST_RESERVED_RECORD_KEY));
+}
+
+
+static bool peer_data_id_is_valid(pm_peer_data_id_t data_id)
+{
+ return ((data_id == PM_PEER_DATA_ID_BONDING) ||
+ (data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING) ||
+ (data_id == PM_PEER_DATA_ID_GATT_LOCAL) ||
+ (data_id == PM_PEER_DATA_ID_GATT_REMOTE) ||
+ (data_id == PM_PEER_DATA_ID_PEER_RANK) ||
+ (data_id == PM_PEER_DATA_ID_APPLICATION));
+}
+
+
+/**@brief Function for sending a PM_EVT_ERROR_UNEXPECTED event.
+ *
+ * @param[in] peer_id The peer the event pertains to.
+ * @param[in] err_code The unexpected error that occurred.
+ */
+static void send_unexpected_error(pm_peer_id_t peer_id, ret_code_t err_code)
+{
+ pm_evt_t error_evt =
+ {
+ .evt_id = PM_EVT_ERROR_UNEXPECTED,
+ .peer_id = peer_id,
+ .params =
+ {
+ .error_unexpected =
+ {
+ .error = err_code,
+ }
+ }
+ };
+ pds_evt_send(&error_evt);
+}
+
+
+// Function for deleting all data beloning to a peer.
+// These operations will be sent to FDS one at a time.
+static void peer_data_delete_process()
+{
+ ret_code_t ret;
+ pm_peer_id_t peer_id;
+ uint16_t file_id;
+ fds_record_desc_t desc;
+ fds_find_token_t ftok;
+
+ m_peer_delete_deferred = false;
+
+ memset(&ftok, 0x00, sizeof(fds_find_token_t));
+ peer_id = peer_id_get_next_deleted(PM_PEER_ID_INVALID);
+
+ while ( (peer_id != PM_PEER_ID_INVALID)
+ && (fds_record_find_in_file(peer_id_to_file_id(peer_id), &desc, &ftok)
+ == FDS_ERR_NOT_FOUND))
+ {
+ peer_id_free(peer_id);
+ peer_id = peer_id_get_next_deleted(peer_id);
+ }
+
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ file_id = peer_id_to_file_id(peer_id);
+ ret = fds_file_delete(file_id);
+
+ if (ret == FDS_ERR_NO_SPACE_IN_QUEUES)
+ {
+ m_peer_delete_deferred = true;
+ }
+ else if (ret != FDS_SUCCESS)
+ {
+ send_unexpected_error(peer_id, ret);
+ }
+ }
+}
+
+
+static ret_code_t peer_data_find(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ fds_record_desc_t * const p_desc)
+{
+ ret_code_t ret;
+ fds_find_token_t ftok;
+
+ NRF_PM_DEBUG_CHECK(peer_id < PM_PEER_ID_N_AVAILABLE_IDS);
+ NRF_PM_DEBUG_CHECK(peer_data_id_is_valid(data_id));
+ NRF_PM_DEBUG_CHECK(p_desc != NULL);
+
+ memset(&ftok, 0x00, sizeof(fds_find_token_t));
+
+ uint16_t file_id = peer_id_to_file_id(peer_id);
+ uint16_t record_key = peer_data_id_to_record_key(data_id);
+
+ ret = fds_record_find(file_id, record_key, p_desc, &ftok);
+
+ if (ret != FDS_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+static void peer_ids_load()
+{
+ fds_record_desc_t record_desc;
+ fds_flash_record_t record;
+ fds_find_token_t ftok;
+
+ memset(&ftok, 0x00, sizeof(fds_find_token_t));
+
+ uint16_t const record_key = peer_data_id_to_record_key(PM_PEER_DATA_ID_BONDING);
+
+ while (fds_record_find_by_key(record_key, &record_desc, &ftok) == FDS_SUCCESS)
+ {
+ pm_peer_id_t peer_id;
+
+ // It is safe to ignore the return value since the descriptor was
+ // just obtained and also 'record' is different from NULL.
+ (void)fds_record_open(&record_desc, &record);
+ peer_id = file_id_to_peer_id(record.p_header->file_id);
+ (void)fds_record_close(&record_desc);
+
+ (void)peer_id_allocate(peer_id);
+ }
+}
+
+
+static void fds_evt_handler(fds_evt_t const * const p_fds_evt)
+{
+ pm_evt_t pds_evt =
+ {
+ .peer_id = file_id_to_peer_id(p_fds_evt->write.file_id)
+ };
+
+ switch (p_fds_evt->id)
+ {
+ case FDS_EVT_WRITE:
+ case FDS_EVT_UPDATE:
+ case FDS_EVT_DEL_RECORD:
+ if ( file_id_within_pm_range(p_fds_evt->write.file_id)
+ || record_key_within_pm_range(p_fds_evt->write.record_key))
+ {
+ pds_evt.params.peer_data_update_succeeded.data_id
+ = record_key_to_peer_data_id(p_fds_evt->write.record_key);
+ pds_evt.params.peer_data_update_succeeded.action
+ = (p_fds_evt->id == FDS_EVT_DEL_RECORD) ? PM_PEER_DATA_OP_DELETE
+ : PM_PEER_DATA_OP_UPDATE;
+ pds_evt.params.peer_data_update_succeeded.token = p_fds_evt->write.record_id;
+
+ if (p_fds_evt->result == FDS_SUCCESS)
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_SUCCEEDED;
+ pds_evt.params.peer_data_update_succeeded.flash_changed = true;
+ }
+ else
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_FAILED;
+ pds_evt.params.peer_data_update_failed.error = p_fds_evt->result;
+ }
+
+ pds_evt_send(&pds_evt);
+ }
+ break;
+
+ case FDS_EVT_DEL_FILE:
+ if ( file_id_within_pm_range(p_fds_evt->del.file_id)
+ && (p_fds_evt->del.record_key == FDS_RECORD_KEY_DIRTY))
+ {
+ if (p_fds_evt->result == FDS_SUCCESS)
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DELETE_SUCCEEDED;
+ peer_id_free(pds_evt.peer_id);
+ }
+ else
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DELETE_FAILED;
+ }
+
+ m_peer_delete_deferred = true; // Trigger remaining deletes.
+
+ pds_evt_send(&pds_evt);
+ }
+ break;
+
+ case FDS_EVT_GC:
+ pds_evt.evt_id = PM_EVT_FLASH_GARBAGE_COLLECTED;
+ pds_evt.peer_id = PM_PEER_ID_INVALID;
+
+ pds_evt_send(&pds_evt);
+ break;
+
+ default:
+ // No action.
+ break;
+ }
+
+ if (m_peer_delete_deferred)
+ {
+ peer_data_delete_process();
+ }
+}
+
+
+ret_code_t pds_init()
+{
+ ret_code_t ret;
+
+ // Check for re-initialization if debugging.
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ ret = fds_register(fds_evt_handler);
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ ret = fds_init();
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_STORAGE_FULL;
+ }
+
+ peer_id_init();
+ peer_ids_load();
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_data,
+ uint32_t const * const p_buf_len)
+{
+ ret_code_t ret;
+ fds_record_desc_t rec_desc;
+ fds_flash_record_t rec_flash;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_data != NULL);
+
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+ VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
+
+ ret = peer_data_find(peer_id, data_id, &rec_desc);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // Shouldn't fail, unless the record was deleted in the meanwhile or the CRC check has failed.
+ ret = fds_record_open(&rec_desc, &rec_flash);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ p_data->data_id = data_id;
+ p_data->length_words = rec_flash.p_header->length_words;
+
+ // If p_buf_len is NULL, provide a pointer to data in flash, otherwise,
+ // check that the buffer is large enough and copy the data in flash into the buffer.
+ if (p_buf_len == NULL)
+ {
+ // The cast is necessary because if no buffer is provided, we just copy the pointer,
+ // but in that case it should be considered a pointer to const data by the caller,
+ // since it is a pointer to data in flash.
+ p_data->p_all_data = (void*)rec_flash.p_data;
+ }
+ else
+ {
+ uint32_t const data_len_bytes = (p_data->length_words * sizeof(uint32_t));
+
+ if ((*p_buf_len) >= data_len_bytes)
+ {
+ memcpy(p_data->p_all_data, rec_flash.p_data, data_len_bytes);
+ }
+ else
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+ }
+
+ // Shouldn't fail unless the record was already closed, in which case it can be ignored.
+ (void)fds_record_close(&rec_desc);
+
+ return NRF_SUCCESS;
+}
+
+
+void pds_peer_data_iterate_prepare(void)
+{
+ memset(&m_fds_ftok, 0x00, sizeof(fds_find_token_t));
+}
+
+
+bool pds_peer_data_iterate(pm_peer_data_id_t data_id,
+ pm_peer_id_t * const p_peer_id,
+ pm_peer_data_flash_t * const p_data)
+{
+ ret_code_t ret;
+ uint16_t rec_key;
+ fds_record_desc_t rec_desc;
+ fds_flash_record_t rec_flash;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_id != NULL);
+ NRF_PM_DEBUG_CHECK(p_data != NULL);
+
+ VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
+
+ rec_key = peer_data_id_to_record_key(data_id);
+
+ if (fds_record_find_by_key(rec_key, &rec_desc, &m_fds_ftok) != NRF_SUCCESS)
+ {
+ return false;
+ }
+
+ ret = fds_record_open(&rec_desc, &rec_flash);
+
+ if (ret != NRF_SUCCESS)
+ {
+ // It can only happen if the record was deleted after the call to fds_record_find_by_key(),
+ // before we could open it, or if CRC support was enabled in Flash Data Storage at compile
+ // time and the CRC check failed.
+ return false;
+ }
+
+ p_data->data_id = data_id;
+ p_data->length_words = rec_flash.p_header->length_words;
+ p_data->p_all_data = rec_flash.p_data;
+
+ *p_peer_id = file_id_to_peer_id(rec_flash.p_header->file_id);
+
+ (void)fds_record_close(&rec_desc);
+
+ return true;
+}
+
+
+ret_code_t pds_space_reserve(pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t * p_prepare_token)
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+ NRF_PM_DEBUG_CHECK(p_prepare_token != NULL);
+
+ VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
+
+ ret = fds_reserve((fds_reserve_token_t*)p_prepare_token, p_peer_data->length_words);
+
+ switch (ret)
+ {
+ case FDS_SUCCESS:
+ return NRF_SUCCESS;
+
+ case FDS_ERR_RECORD_TOO_LARGE:
+ return NRF_ERROR_INVALID_LENGTH;
+
+ case FDS_ERR_NO_SPACE_IN_FLASH:
+ return NRF_ERROR_STORAGE_FULL;
+
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+}
+
+
+ret_code_t pds_space_reserve_cancel(pm_prepare_token_t prepare_token)
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(prepare_token != PDS_PREPARE_TOKEN_INVALID);
+
+ ret = fds_reserve_cancel((fds_reserve_token_t*)&prepare_token);
+
+ if (ret != FDS_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pds_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t prepare_token,
+ pm_store_token_t * p_store_token)
+{
+ ret_code_t ret;
+ fds_record_t rec;
+ fds_record_desc_t rec_desc;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+ VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
+
+ // Prepare the record to be stored in flash.
+ rec.file_id = peer_id_to_file_id(peer_id);
+ rec.key = peer_data_id_to_record_key(p_peer_data->data_id);
+ rec.data.p_data = (void*)p_peer_data->p_all_data;
+ rec.data.length_words = p_peer_data->length_words;
+
+ ret = peer_data_find(peer_id, p_peer_data->data_id, &rec_desc);
+
+ if (ret == NRF_ERROR_NOT_FOUND)
+ {
+ // No previous data exists in flash.
+ if (prepare_token == PDS_PREPARE_TOKEN_INVALID)
+ {
+ // No space was previously reserved.
+ ret = fds_record_write(&rec_desc, &rec);
+ }
+ else
+ {
+ // Space for this record was previously reserved.
+ ret = fds_record_write_reserved(&rec_desc, &rec, (fds_reserve_token_t*)&prepare_token);
+ }
+ }
+ else // NRF_SUCCESS
+ {
+ if (prepare_token != PDS_PREPARE_TOKEN_INVALID)
+ {
+ (void)fds_reserve_cancel((fds_reserve_token_t*)&prepare_token);
+ }
+
+ // Update existing record.
+ ret = fds_record_update(&rec_desc, &rec);
+ }
+
+ switch (ret)
+ {
+ case FDS_SUCCESS:
+ if (p_store_token != NULL)
+ {
+ // Update the store token.
+ (void)fds_record_id_from_desc(&rec_desc, (uint32_t*)p_store_token);
+ }
+ return NRF_SUCCESS;
+
+ case FDS_ERR_BUSY:
+ case FDS_ERR_NO_SPACE_IN_QUEUES:
+ return NRF_ERROR_BUSY;
+
+ case FDS_ERR_NO_SPACE_IN_FLASH:
+ return NRF_ERROR_STORAGE_FULL;
+
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+}
+
+
+ret_code_t pds_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ ret_code_t ret;
+ fds_record_desc_t record_desc;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+ VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
+
+ ret = peer_data_find(peer_id, data_id, &record_desc);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ ret = fds_record_delete(&record_desc);
+
+ switch (ret)
+ {
+ case FDS_SUCCESS:
+ return NRF_SUCCESS;
+
+ case FDS_ERR_NO_SPACE_IN_QUEUES:
+ return NRF_ERROR_BUSY;
+
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+}
+
+
+pm_peer_id_t pds_peer_id_allocate(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_allocate(PM_PEER_ID_INVALID);
+}
+
+
+ret_code_t pds_peer_id_free(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+
+ (void)peer_id_delete(peer_id);
+ peer_data_delete_process();
+
+ return NRF_SUCCESS;
+}
+
+
+bool pds_peer_id_is_allocated(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_is_allocated(peer_id);
+}
+
+
+pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_get_next_used(prev_peer_id);
+}
+
+
+pm_peer_id_t pds_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_get_next_deleted(prev_peer_id);
+}
+
+
+uint32_t pds_peer_count_get(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_n_ids();
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h
new file mode 100644
index 0000000..fccfabc
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h
@@ -0,0 +1,270 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_DATA_STORAGE_H__
+#define PEER_DATA_STORAGE_H__
+
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup peer_data_storage Peer Data Storage
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module provides a Peer Manager-specific API
+ * to the persistent storage.
+ *
+ * @details This module uses Flash Data Storage (FDS) to interface with persistent storage.
+ */
+
+#define PDS_PREPARE_TOKEN_INVALID (0) /**< Invalid value for prepare token. */
+#define PDS_FIRST_RESERVED_FILE_ID (0xC000) /**< The beginning of the range of file IDs reserved for Peer Manager. */
+#define PDS_LAST_RESERVED_FILE_ID (0xFFFE) /**< The end of the range of file IDs reserved for Peer Manager. */
+#define PDS_FIRST_RESERVED_RECORD_KEY (0xC000) /**< The beginning of the range of record keys reserved for Peer Manager. */
+#define PDS_LAST_RESERVED_RECORD_KEY (0xFFFE) /**< The end of the range of record keys reserved for Peer Manager. */
+
+#define PEER_ID_TO_FILE_ID ( PDS_FIRST_RESERVED_FILE_ID) //!< Macro for converting a @ref pm_peer_id_t to an FDS file ID.
+#define FILE_ID_TO_PEER_ID (-PDS_FIRST_RESERVED_FILE_ID) //!< Macro for converting an FDS file ID to a @ref pm_peer_id_t.
+#define DATA_ID_TO_RECORD_KEY ( PDS_FIRST_RESERVED_RECORD_KEY) //!< Macro for converting a @ref pm_peer_data_id_t to an FDS record ID.
+#define RECORD_KEY_TO_DATA_ID (-PDS_FIRST_RESERVED_RECORD_KEY) //!< Macro for converting an FDS record ID to a @ref pm_peer_data_id_t.
+
+
+/**@brief Function for initializing the module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_STORAGE_FULL If no flash pages were available for use.
+ * @retval NRF_ERROR_INTERNAL If the module couldn't register with the flash filesystem.
+ */
+ret_code_t pds_init(void);
+
+
+/**@brief Function for reading peer data in flash.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] data_id The data to retrieve.
+ * @param[out] p_data The peer data. May not be @c NULL.
+ * @param[in] p_buf_len Length of the provided buffer, in bytes. Pass @c NULL to only copy
+ * a pointer to the data in flash.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If the data was not found in flash.
+ * @retval NRF_ERROR_NO_MEM If the provided buffer is too small.
+ */
+ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_data,
+ uint32_t const * const p_buf_len);
+
+
+/**@brief Function to prepare iterating over peer data in flash using @ref pds_peer_data_iterate.
+ * Call this function once each time before iterating using @ref pds_peer_data_iterate.
+ */
+void pds_peer_data_iterate_prepare(void);
+
+
+/**@brief Function for iterating peers' data in flash.
+ * Always call @ref pds_peer_data_iterate_prepare before starting iterating.
+ *
+ * @param[in] data_id The peer data to iterate over.
+ * @param[out] p_peer_id The peer the data belongs to.
+ * @param[out] p_data The peer data in flash.
+ *
+ * @retval true If the operation was successful.
+ * @retval false If the data was not found in flash, or another error occurred.
+ */
+bool pds_peer_data_iterate(pm_peer_data_id_t data_id,
+ pm_peer_id_t * const p_peer_id,
+ pm_peer_data_flash_t * const p_data);
+
+
+/**@brief Function for reserving space in flash to store data.
+ *
+ * @param[in] p_peer_data The data to be stored in flash. Only data length and type (ID) are
+ * relevant for this operation. May not be @c NULL.
+ * @param[out] p_prepare_token A token identifying the reserved space. May not be @c NULL.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If the data ID in @p p_peer_data is invalid.
+ * @retval NRF_ERROR_INVALID_LENGTH If data length exceeds the maximum allowed length.
+ * @retval NRF_ERROR_STORAGE_FULL If no space is available in flash.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_space_reserve(pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t * p_prepare_token);
+
+
+/**@brief Function for undoing a previous call to @ref pds_space_reserve.
+ *
+ * @param[in] prepare_token A token identifying the reservation to cancel.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_space_reserve_cancel(pm_prepare_token_t prepare_token);
+
+
+/**@brief Function for storing peer data in flash. If the same piece of data already exists for the
+ * given peer, it will be updated. This operation is asynchronous.
+ * Expect a @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or @ref PM_EVT_PEER_DATA_UPDATE_FAILED
+ * event.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] p_peer_data The peer data. May not be @c NULL.
+ * @param[in] prepare_token A token identifying the reservation made in flash to store the data.
+ * Pass @ref PDS_PREPARE_TOKEN_INVALID if no space was reserved.
+ * @param[out] p_store_token A token identifying this particular store operation. The token can be
+ * used to identify events pertaining to this operation. Pass @p NULL
+ * if not used.
+ *
+ * @retval NRF_SUCCESS If the operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or the data ID in @p_peer_data are invalid.
+ * @retval NRF_ERROR_STORAGE_FULL If no space is available in flash. This can only happen if
+ * @p p_prepare_token is @ref PDS_PREPARE_TOKEN_INVALID.
+ * @retval NRF_ERROR_BUSY If the flash filesystem was busy.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t prepare_token,
+ pm_store_token_t * p_store_token);
+
+
+/**@brief Function for deleting peer data in flash. This operation is asynchronous.
+ * Expect a @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or @ref PM_EVT_PEER_DATA_UPDATE_FAILED
+ * event.
+ *
+ * @param[in] peer_id The peer the data belongs to
+ * @param[in] data_id The data to delete.
+ *
+ * @retval NRF_SUCCESS If the operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If data was not found in flash.
+ * @retval NRF_ERROR_BUSY If the flash filesystem was busy.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for claiming an unused peer ID.
+ *
+ * @retval PM_PEER_ID_INVALID If no peer ID was available.
+ */
+pm_peer_id_t pds_peer_id_allocate(void);
+
+
+/**@brief Function for freeing a peer ID and deleting all data associated with it in flash.
+ *
+ * @param[in] peer_id The ID of the peer to free.
+ *
+ * @retval NRF_SUCCESS The operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id is invalid.
+ */
+ret_code_t pds_peer_id_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function for finding out whether a peer ID is in use.
+ *
+ * @param[in] peer_id The peer ID to inquire about.
+ *
+ * @retval true @p peer_id is in use.
+ * @retval false @p peer_id is free.
+ */
+bool pds_peer_id_is_allocated(pm_peer_id_t peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
+ * used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The first ordinary peer ID If @p prev_peer_id is @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID If @p prev_peer_id is the last ordinary peer ID or the module
+ * is not initialized.
+ */
+pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all peer IDs pending deletion.
+ * Can be used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID pending deletion.
+ * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module
+ * is not initialized.
+ */
+pm_peer_id_t pds_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
+ * in persistent storage.
+ *
+ * @return The number of valid peer IDs.
+ */
+uint32_t pds_peer_count_get(void);
+
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_DATA_STORAGE_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c
new file mode 100644
index 0000000..53b6680
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c
@@ -0,0 +1,814 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "peer_database.h"
+
+#include <string.h>
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "peer_data_storage.h"
+#include "pm_buffer.h"
+
+
+/**@brief Macro for verifying that the data ID is among the values eligible for using the write buffer.
+ *
+ * @param[in] data_id The data ID to verify.
+ */
+// @note emdi: could this maybe be a function?
+#define VERIFY_DATA_ID_WRITE_BUF(data_id) \
+do \
+{ \
+ if (((data_id) != PM_PEER_DATA_ID_BONDING) && ((data_id) != PM_PEER_DATA_ID_GATT_LOCAL)) \
+ { \
+ return NRF_ERROR_INVALID_PARAM; \
+ } \
+} while (0)
+
+
+// The number of registered event handlers.
+#define PDB_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Peer Database event handlers in other Peer Manager submodules.
+extern void pm_pdb_evt_handler(pm_evt_t * p_event);
+extern void sm_pdb_evt_handler(pm_evt_t * p_event);
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+extern void gscm_pdb_evt_handler(pm_evt_t * p_event);
+#endif
+extern void gcm_pdb_evt_handler(pm_evt_t * p_event);
+
+// Peer Database events' handlers.
+// The number of elements in this array is PDB_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pm_pdb_evt_handler,
+ sm_pdb_evt_handler,
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+ gscm_pdb_evt_handler,
+#endif
+ gcm_pdb_evt_handler,
+};
+
+
+/**@brief Struct for keeping track of one write buffer, from allocation, until it is fully written
+ * or cancelled.
+ */
+typedef struct
+{
+ pm_peer_id_t peer_id; /**< The peer ID this buffer belongs to. */
+ pm_peer_data_id_t data_id; /**< The data ID this buffer belongs to. */
+ pm_prepare_token_t prepare_token; /**< Token given by Peer Data Storage if room in flash has been reserved. */
+ pm_store_token_t store_token; /**< Token given by Peer Data Storage when a flash write has been successfully requested. This is used as the check for whether such an operation has been successfully requested. */
+ uint8_t n_bufs; /**< The number of buffer blocks containing peer data. */
+ uint8_t buffer_block_id; /**< The index of the first (or only) buffer block containing peer data. */
+ uint8_t store_flash_full : 1; /**< Flag indicating that the buffer was attempted written to flash, but a flash full error was returned and the operation should be retried after room has been made. */
+ uint8_t store_busy : 1; /**< Flag indicating that the buffer was attempted written to flash, but a busy error was returned and the operation should be retried. */
+} pdb_buffer_record_t;
+
+
+static bool m_module_initialized;
+static pm_buffer_t m_write_buffer; /**< The internal states of the write buffer. */
+static pdb_buffer_record_t m_write_buffer_records[PM_FLASH_BUFFERS]; /**< The available write buffer records. */
+static bool m_pending_store = false; /**< Whether there are any pending (Not yet successfully requested in Peer Data Storage) store operations. This flag is for convenience only. The real bookkeeping is in the records (@ref m_write_buffer_records). */
+
+
+
+/**@brief Function for invalidating a record of a write buffer allocation.
+ *
+ * @param[in] p_record The record to invalidate.
+ */
+static void write_buffer_record_invalidate(pdb_buffer_record_t * p_record)
+{
+ p_record->peer_id = PM_PEER_ID_INVALID;
+ p_record->data_id = PM_PEER_DATA_ID_INVALID;
+ p_record->buffer_block_id = PM_BUFFER_INVALID_ID;
+ p_record->store_busy = false;
+ p_record->store_flash_full = false;
+ p_record->n_bufs = 0;
+ p_record->prepare_token = PDS_PREPARE_TOKEN_INVALID;
+ p_record->store_token = PM_STORE_TOKEN_INVALID;
+}
+
+
+/**@brief Function for finding a record of a write buffer allocation.
+ *
+ * @param[in] peer_id The peer ID in the record.
+ * @param[inout] p_index In: The starting index, out: The index of the record
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find_next(pm_peer_id_t peer_id, uint32_t * p_index)
+{
+ for (uint32_t i = *p_index; i < PM_FLASH_BUFFERS; i++)
+ {
+ if ((m_write_buffer_records[i].peer_id == peer_id))
+ {
+ *p_index = i;
+ return &m_write_buffer_records[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**@brief Function for finding a record of a write buffer allocation.
+ *
+ * @param[in] peer_id The peer ID in the record.
+ * @param[in] data_id The data ID in the record.
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id)
+{
+ uint32_t index = 0;
+ pdb_buffer_record_t * p_record = write_buffer_record_find_next(peer_id, &index);
+
+ while ((p_record != NULL) && ( (p_record->data_id != data_id)
+ || (p_record->store_busy)
+ || (p_record->store_flash_full)
+ || (p_record->store_token != PM_STORE_TOKEN_INVALID)))
+ {
+ index++;
+ p_record = write_buffer_record_find_next(peer_id, &index);
+ }
+
+ return p_record;
+}
+
+
+/**@brief Function for finding a record of a write buffer allocation that has been sent to be stored.
+ *
+ * @param[in] store_token The store token received when store was called for the record.
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find_stored(pm_store_token_t store_token)
+{
+ for (int i = 0; i < PM_FLASH_BUFFERS; i++)
+ {
+ if (m_write_buffer_records[i].store_token == store_token)
+ {
+ return &m_write_buffer_records[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**@brief Function for finding an available record for write buffer allocation.
+ *
+ * @return A pointer to the available record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find_unused(void)
+{
+ return write_buffer_record_find(PM_PEER_ID_INVALID, PM_PEER_DATA_ID_INVALID);
+}
+
+
+/**@brief Function for gracefully deactivating a write buffer record.
+ *
+ * @details This function will first release any buffers, then invalidate the record.
+ *
+ * @param[inout] p_write_buffer_record The record to release.
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static void write_buffer_record_release(pdb_buffer_record_t * p_write_buffer_record)
+{
+ for (uint32_t i = 0; i < p_write_buffer_record->n_bufs; i++)
+ {
+ pm_buffer_release(&m_write_buffer, p_write_buffer_record->buffer_block_id + i);
+ }
+
+ write_buffer_record_invalidate(p_write_buffer_record);
+}
+
+
+/**@brief Function for claiming and activating a write buffer record.
+ *
+ * @param[out] pp_write_buffer_record The claimed record.
+ * @param[in] peer_id The peer ID this record should have.
+ * @param[in] data_id The data ID this record should have.
+ */
+static void write_buffer_record_acquire(pdb_buffer_record_t ** pp_write_buffer_record,
+ pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id)
+{
+ if (pp_write_buffer_record == NULL)
+ {
+ return;
+ }
+ *pp_write_buffer_record = write_buffer_record_find_unused();
+ if (*pp_write_buffer_record == NULL)
+ {
+ // This also means the buffer is full.
+ return;
+ }
+ (*pp_write_buffer_record)->peer_id = peer_id;
+ (*pp_write_buffer_record)->data_id = data_id;
+}
+
+
+/**@brief Function for dispatching outbound events to all registered event handlers.
+ *
+ * @param[in] p_event The event to dispatch.
+ */
+static void pdb_evt_send(pm_evt_t * p_event)
+{
+ for (uint32_t i = 0; i < PDB_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+/**@brief Function for resetting the internal state of the Peer Database module.
+ *
+ * @param[out] p_event The event to dispatch.
+ */
+static void internal_state_reset()
+{
+ for (uint32_t i = 0; i < PM_FLASH_BUFFERS; i++)
+ {
+ write_buffer_record_invalidate(&m_write_buffer_records[i]);
+ }
+}
+
+
+static void peer_data_point_to_buffer(pm_peer_data_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint16_t n_bufs)
+{
+ uint16_t n_bytes = n_bufs * PDB_WRITE_BUF_SIZE;
+ p_peer_data->data_id = data_id;
+
+ p_peer_data->p_all_data = (pm_peer_data_bonding_t *)p_buffer_memory;
+ p_peer_data->length_words = BYTES_TO_WORDS(n_bytes);
+}
+
+
+static void peer_data_const_point_to_buffer(pm_peer_data_const_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint32_t n_bufs)
+{
+ peer_data_point_to_buffer((pm_peer_data_t*)p_peer_data, data_id, p_buffer_memory, n_bufs);
+}
+
+
+static void write_buf_length_words_set(pm_peer_data_const_t * p_peer_data)
+{
+ switch (p_peer_data->data_id)
+ {
+ case PM_PEER_DATA_ID_BONDING:
+ p_peer_data->length_words = PM_BONDING_DATA_N_WORDS();
+ break;
+ case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
+ p_peer_data->length_words = PM_SC_STATE_N_WORDS();
+ break;
+ case PM_PEER_DATA_ID_PEER_RANK:
+ p_peer_data->length_words = PM_USAGE_INDEX_N_WORDS();
+ break;
+ case PM_PEER_DATA_ID_GATT_LOCAL:
+ p_peer_data->length_words = PM_LOCAL_DB_N_WORDS(p_peer_data->p_local_gatt_db->len);
+ break;
+ default:
+ // No action needed.
+ break;
+ }
+}
+
+
+/**@brief Function for writing data into persistent storage. Writing happens asynchronously.
+ *
+ * @note This will unlock the data after it has been written.
+ *
+ * @param[in] p_write_buffer_record The write buffer record to write into persistent storage.
+ *
+ * @retval NRF_SUCCESS Data storing was successfully started.
+ * @retval NRF_ERROR_STORAGE_FULL No space available in persistent storage. Please clear some
+ * space, the operation will be reattempted after the next compress
+ * procedure. This error will not happen if
+ * @ref pdb_write_buf_store_prepare is called beforehand.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID was invalid.
+ * @retval NRF_ERROR_INVALID_STATE Module is not initialized.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t write_buf_store(pdb_buffer_record_t * p_write_buffer_record)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ pm_peer_data_const_t peer_data = {.data_id = p_write_buffer_record->data_id};
+ uint8_t * p_buffer_memory;
+
+ p_buffer_memory = pm_buffer_ptr_get(&m_write_buffer, p_write_buffer_record->buffer_block_id);
+ if (p_buffer_memory == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ peer_data_const_point_to_buffer(&peer_data,
+ p_write_buffer_record->data_id,
+ p_buffer_memory,
+ p_write_buffer_record->n_bufs);
+ write_buf_length_words_set(&peer_data);
+
+ err_code = pds_peer_data_store(p_write_buffer_record->peer_id,
+ &peer_data,
+ p_write_buffer_record->prepare_token,
+ &p_write_buffer_record->store_token);
+
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ p_write_buffer_record->store_busy = false;
+ p_write_buffer_record->store_flash_full = false;
+ break;
+
+ case NRF_ERROR_BUSY:
+ p_write_buffer_record->store_busy = true;
+ p_write_buffer_record->store_flash_full = false;
+ m_pending_store = true;
+
+ err_code = NRF_SUCCESS;
+ break;
+
+ case NRF_ERROR_STORAGE_FULL:
+ p_write_buffer_record->store_busy = false;
+ p_write_buffer_record->store_flash_full = true;
+ m_pending_store = true;
+ break;
+
+ case NRF_ERROR_INVALID_PARAM:
+ // No action.
+ break;
+
+ default:
+ err_code = NRF_ERROR_INTERNAL;
+ break;
+ }
+
+ return err_code;
+}
+
+
+/**@brief This calls @ref write_buf_store and sends events based on the return value.
+ *
+ * See @ref write_buf_store for more info.
+ *
+ * @return Whether or not the store operation succeeded.
+ */
+static bool write_buf_store_in_event(pdb_buffer_record_t * p_write_buffer_record)
+{
+ ret_code_t err_code;
+ pm_evt_t event;
+
+ err_code = write_buf_store(p_write_buffer_record);
+ if (err_code != NRF_SUCCESS)
+ {
+ event.conn_handle = BLE_CONN_HANDLE_INVALID;
+ event.peer_id = p_write_buffer_record->peer_id;
+
+ if (err_code == NRF_ERROR_STORAGE_FULL)
+ {
+ event.evt_id = PM_EVT_STORAGE_FULL;
+ }
+ else
+ {
+ event.evt_id = PM_EVT_ERROR_UNEXPECTED;
+ event.params.error_unexpected.error = err_code;
+ }
+
+ pdb_evt_send(&event);
+
+ return false;
+ }
+
+ return true;
+}
+
+
+/**@brief This reattempts store operations on write buffers, that previously failed because of @ref
+ * NRF_ERROR_BUSY or @ref NRF_ERROR_STORAGE_FULL errors.
+ *
+ * param[in] retry_flash_full Whether to retry operations that failed because of an
+ * @ref NRF_ERROR_STORAGE_FULL error.
+ */
+static void reattempt_previous_operations(bool retry_flash_full)
+{
+ bool found_pending_operation = false;
+
+ if (!m_pending_store)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < PM_FLASH_BUFFERS; i++)
+ {
+ if ((m_write_buffer_records[i].store_busy)
+ || (m_write_buffer_records[i].store_flash_full && retry_flash_full))
+ {
+ found_pending_operation = true;
+
+ bool success = write_buf_store_in_event(&m_write_buffer_records[i]);
+
+ if (!success)
+ {
+ return;
+ }
+ }
+ }
+
+ if (!found_pending_operation)
+ {
+ // All records have been searched and none were pending.
+ // Clear flag so records aren't searched.
+ m_pending_store = false;
+ }
+}
+
+
+/**@brief Function for handling events from the Peer Data Storage module.
+ * This function is extern in Peer Data Storage.
+ *
+ * @param[in] p_event The event to handle.
+ */
+void pdb_pds_evt_handler(pm_evt_t * p_event)
+{
+ pdb_buffer_record_t * p_write_buffer_record;
+ bool evt_send = true;
+ bool retry_flash_full = false;
+
+ p_write_buffer_record = write_buffer_record_find_stored(p_event->params.peer_data_update_succeeded.token);
+
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ if ( (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ && (p_write_buffer_record != NULL))
+ {
+ // The write came from PDB.
+ write_buffer_record_release(p_write_buffer_record);
+ }
+ break;
+
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ if ( (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ && (p_write_buffer_record != NULL))
+ {
+ // The write came from PDB, retry.
+ p_write_buffer_record->store_token = PM_STORE_TOKEN_INVALID;
+ p_write_buffer_record->store_busy = true;
+ m_pending_store = true;
+ evt_send = false;
+ }
+ break;
+
+ case PM_EVT_FLASH_GARBAGE_COLLECTED:
+ retry_flash_full = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (evt_send)
+ {
+ // Forward the event to all registered Peer Database event handlers.
+ pdb_evt_send(p_event);
+ }
+
+ reattempt_previous_operations(retry_flash_full);
+}
+
+
+ret_code_t pdb_init()
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+
+ PM_BUFFER_INIT(&m_write_buffer, PM_FLASH_BUFFERS, PDB_WRITE_BUF_SIZE, ret);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+pm_peer_id_t pdb_peer_allocate(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_id_allocate();
+}
+
+
+ret_code_t pdb_peer_free(pm_peer_id_t peer_id)
+{
+ ret_code_t err_code_in = NRF_SUCCESS;
+ ret_code_t err_code_out = NRF_SUCCESS;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint32_t index = 0;
+ pdb_buffer_record_t * p_record = write_buffer_record_find_next(peer_id, &index);
+
+ while (p_record != NULL)
+ {
+ err_code_in = pdb_write_buf_release(peer_id, p_record->data_id);
+
+ if ( (err_code_in != NRF_SUCCESS)
+ && (err_code_in != NRF_ERROR_NOT_FOUND))
+ {
+ err_code_out = NRF_ERROR_INTERNAL;
+ }
+
+ index++;
+ p_record = write_buffer_record_find_next(peer_id, &index);
+ }
+
+ if (err_code_out == NRF_SUCCESS)
+ {
+ err_code_in = pds_peer_id_free(peer_id);
+
+ if (err_code_in == NRF_SUCCESS)
+ {
+ // No action needed.
+ }
+ else if (err_code_in == NRF_ERROR_INVALID_PARAM)
+ {
+ err_code_out = NRF_ERROR_INVALID_PARAM;
+ }
+ else
+ {
+ err_code_out = NRF_ERROR_INTERNAL;
+ }
+ }
+
+ return err_code_out;
+}
+
+
+ret_code_t pdb_peer_data_ptr_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_flash_t * const p_peer_data)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+
+ // Pass NULL to only retrieve a pointer.
+ return pds_peer_data_read(peer_id, data_id, (pm_peer_data_t*)p_peer_data, NULL);
+}
+
+
+
+ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ uint32_t n_bufs,
+ pm_peer_data_t * p_peer_data)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_PARAM_NOT_NULL(p_peer_data);
+ VERIFY_DATA_ID_WRITE_BUF(data_id);
+
+ if ( (n_bufs == 0)
+ || (n_bufs > PM_FLASH_BUFFERS)
+ || !pds_peer_id_is_allocated(peer_id))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ pdb_buffer_record_t * p_write_buffer_record;
+ uint8_t * p_buffer_memory;
+ bool new_record = false;
+
+ p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ // No buffer exists.
+ write_buffer_record_acquire(&p_write_buffer_record, peer_id, data_id);
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_BUSY;
+ }
+ }
+ else if (p_write_buffer_record->n_bufs != n_bufs)
+ {
+ // Buffer exists with a different n_bufs from what was requested.
+ return NRF_ERROR_FORBIDDEN;
+ }
+
+ if (p_write_buffer_record->buffer_block_id == PM_BUFFER_INVALID_ID)
+ {
+ p_write_buffer_record->buffer_block_id = pm_buffer_block_acquire(&m_write_buffer, n_bufs);
+
+ if (p_write_buffer_record->buffer_block_id == PM_BUFFER_INVALID_ID)
+ {
+ write_buffer_record_invalidate(p_write_buffer_record);
+ return NRF_ERROR_BUSY;
+ }
+
+ new_record = true;
+ }
+
+ p_write_buffer_record->n_bufs = n_bufs;
+
+ p_buffer_memory = pm_buffer_ptr_get(&m_write_buffer, p_write_buffer_record->buffer_block_id);
+
+ if (p_buffer_memory == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ peer_data_point_to_buffer(p_peer_data, data_id, p_buffer_memory, n_bufs);
+ if (new_record && (data_id == PM_PEER_DATA_ID_GATT_LOCAL))
+ {
+ p_peer_data->p_local_gatt_db->len = PM_LOCAL_DB_LEN(p_peer_data->length_words);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ ret_code_t err_code = NRF_SUCCESS;
+ pdb_buffer_record_t * p_write_buffer_record;
+ p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (p_write_buffer_record->prepare_token != PDS_PREPARE_TOKEN_INVALID)
+ {
+ err_code = pds_space_reserve_cancel(p_write_buffer_record->prepare_token);
+ if (err_code != NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+
+ write_buffer_record_release(p_write_buffer_record);
+
+ return err_code;
+}
+
+
+ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_DATA_ID_WRITE_BUF(data_id);
+
+ ret_code_t err_code = NRF_SUCCESS;
+ pdb_buffer_record_t * p_write_buffer_record;
+ p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (p_write_buffer_record->prepare_token == PDS_PREPARE_TOKEN_INVALID)
+ {
+ uint8_t * p_buffer_memory = pm_buffer_ptr_get(&m_write_buffer,
+ p_write_buffer_record->buffer_block_id);
+ pm_peer_data_const_t peer_data = {.data_id = data_id};
+
+ if (p_buffer_memory == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs);
+
+ write_buf_length_words_set(&peer_data);
+
+ err_code = pds_space_reserve(&peer_data, &p_write_buffer_record->prepare_token);
+ if (err_code == NRF_ERROR_INVALID_LENGTH)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+
+ return err_code;
+}
+
+
+ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_id_t new_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_DATA_ID_WRITE_BUF(data_id);
+
+ pdb_buffer_record_t * p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ p_write_buffer_record->peer_id = new_peer_id;
+ p_write_buffer_record->data_id = data_id;
+ return write_buf_store(p_write_buffer_record);
+}
+
+
+ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_data_delete(peer_id, data_id);
+}
+
+
+uint32_t pdb_n_peers(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_count_get();
+}
+
+
+pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_next_peer_id_get(prev_peer_id);
+}
+
+
+pm_peer_id_t pdb_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_next_deleted_peer_id_get(prev_peer_id);
+}
+
+
+ret_code_t pdb_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_peer_data)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+
+ // Provide the buffer length in bytes.
+ uint32_t const data_len_bytes = (p_peer_data->length_words * sizeof(uint32_t));
+ return pds_peer_data_read(peer_id, data_id, p_peer_data, &data_len_bytes);
+}
+
+
+ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t * p_peer_data,
+ pm_store_token_t * p_store_token)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_data_store(peer_id, p_peer_data, PDS_PREPARE_TOKEN_INVALID, p_store_token);
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h
new file mode 100644
index 0000000..819a9eb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h
@@ -0,0 +1,309 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_DATABASE_H__
+#define PEER_DATABASE_H__
+
+#include <stdint.h>
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup peer_database Peer Database
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for simple management of reading and
+ * writing of peer data into persistent storage.
+ *
+ */
+
+#define PDB_WRITE_BUF_SIZE (sizeof(pm_peer_data_bonding_t)) //!< The size (in bytes) of each block in the internal buffer accessible via @ref pdb_write_buf_get.
+
+
+/**@brief Function for initializing the module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL An unexpected error happened.
+ */
+ret_code_t pdb_init(void);
+
+
+/**@brief Function for allocating persistent bond storage for a peer.
+ *
+ * @return The ID of the newly allocated storage.
+ * @retval PM_PEER_ID_INVALID If no peer ID is available.
+ */
+pm_peer_id_t pdb_peer_allocate(void);
+
+
+/**@brief Function for freeing a peer's persistent bond storage.
+ *
+ * @note This function will call @ref pdb_write_buf_release on the data for this peer.
+ *
+ * @param[in] peer_id ID to be freed.
+ *
+ * @retval NRF_SUCCESS Peer ID was released and clear operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM Peer ID was invalid.
+ */
+ret_code_t pdb_peer_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function for retrieving a pointer to peer data in flash (read-only).
+ *
+ * @note Dereferencing this pointer is not the safest thing to do if interrupts are enabled,
+ * because Flash Data Storage garbage collection might move the data around. Either disable
+ * interrupts while using the data, or use @ref pdb_peer_data_load.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] data_id The data to read.
+ * @param[out] p_peer_data The peer data, read-only.
+ *
+ * @retval NRF_SUCCESS If the pointer to the data was retrieved successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If either @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If data was not found in flash.
+ */
+ret_code_t pdb_peer_data_ptr_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_flash_t * const p_peer_data);
+
+
+/**@brief Function for retrieving pointers to a write buffer for peer data.
+ *
+ * @details This function will provide pointers to a buffer of the data. The data buffer will not be
+ * written to persistent storage until @ref pdb_write_buf_store is called. The buffer is
+ * released by calling either @ref pdb_write_buf_release, @ref pdb_write_buf_store, or
+ * @ref pdb_peer_free.
+ *
+ * When the data_id refers to a variable length data type, the available size is written
+ * to the data, both the top-level, and any internal length fields.
+ *
+ * @note Calling this function on a peer_id/data_id pair that already has a buffer created will
+ * give the same buffer, not create a new one. If n_bufs was increased since last time, the
+ * buffer might be relocated to be able to provide additional room. In this case, the data
+ * will be copied. If n_bufs was increased since last time, this function might return @ref
+ * NRF_ERROR_BUSY. In that case, the buffer is automatically released.
+ *
+ * @param[in] peer_id ID of peer to get a write buffer for.
+ * @param[in] data_id Which piece of data to get.
+ * @param[in] n_bufs The number of contiguous buffers needed.
+ * @param[out] p_peer_data Pointers to mutable peer data.
+ *
+ * @retval NRF_SUCCESS Data retrieved successfully.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated, or n_bufs was 0
+ * or more than the total available buffers.
+ * @retval NRF_ERROR_FORBIDDEN n_bufs was higher or lower than the existing buffer. If needed,
+ * release the existing buffer with @ref pdb_write_buf_release, and
+ * call this function again.
+ * @retval NRF_ERROR_NULL p_peer_data was NULL.
+ * @retval NRF_ERROR_BUSY Not enough buffer(s) available.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ uint32_t n_bufs,
+ pm_peer_data_t * p_peer_data);
+
+
+/**@brief Function for freeing a write buffer allocated with @ref pdb_write_buf_get.
+ *
+ * @note This function will not write peer data to persistent memory. Data in released buffer will
+ * be lost.
+ *
+ * @note This function will undo any previous call to @ref pdb_write_buf_store_prepare for this
+ * piece of data.
+ *
+ * @param[in] peer_id ID of peer to release buffer for.
+ * @param[in] data_id Which piece of data to release buffer for.
+ *
+ * @retval NRF_SUCCESS Successfully released buffer.
+ * @retval NRF_ERROR_NOT_FOUND No buffer was allocated for this peer ID/data ID pair.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for reserving space in persistent storage for data in a buffer.
+ *
+ * @note This function only works for data which has a write buffer allocated. If the write buffer
+ * is released, this prepare is undone.
+ *
+ * @note If space has already been reserved for this data, nothing is done.
+ *
+ * @param[in] peer_id The peer whose data to reserve space for.
+ * @param[in] data_id The type of data to reserve space for.
+ *
+ * @retval NRF_SUCCESS Successfully reserved space in persistent storage.
+ * @retval NRF_ERROR_STORAGE_FULL Not enough room in persistent storage.
+ * @retval NRF_ERROR_NOT_FOUND No buffer has been allocated for this peer ID/data ID pair.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
+ */
+ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for writing data into persistent storage. Writing happens asynchronously.
+ *
+ * @note This will unlock the data after it has been written.
+ *
+ * @param[in] peer_id The ID used to address the write buffer.
+ * @param[in] data_id Which piece of data to store.
+ * @param[in] new_peer_id The ID to put in flash. This will usually be the same as peer_id.
+ *
+ * @retval NRF_SUCCESS Data storing was successfully started.
+ * @retval NRF_ERROR_STORAGE_FULL No space available in persistent storage. Please clear some
+ * space, the operation will be reattempted after the next compress
+ * procedure. This error will not happen if
+ * @ref pdb_write_buf_store_prepare is called beforehand.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID was invalid.
+ * @retval NRF_ERROR_NOT_FOUND No buffer has been allocated for this peer ID/data ID pair.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_id_t new_peer_id);
+
+
+/**@brief Function for clearing data from persistent storage.
+ *
+ * @param[in] peer_id ID of peer to clear data for.
+ * @param[in] data_id Which piece of data to clear.
+ *
+ * @retval NRF_SUCCESS The clear was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or peer ID was invalid.
+ * @retval NRF_ERROR_NOT_FOUND Nothing to clear for this peer ID/data ID combination.
+ * @retval NRF_ERROR_BUSY Underlying modules are busy and can't take any more requests at
+ * this moment.
+ * @retval NRF_ERROR_INTERNAL Internal error.
+ */
+ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
+ * in persistent storage.
+ *
+ * @return The number of valid peer IDs.
+ */
+uint32_t pdb_n_peers(void);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
+ * used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID.
+ * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID.
+ */
+pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all peer IDs pending deletion.
+ * Can be used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID pending deletion.
+ * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID.
+ */
+pm_peer_id_t pdb_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for copy peer data from flash into a provided buffer.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] data_id The data to read.
+ * @param[inout] p_peer_data The buffer where to copy data into. The field @c length_words in this
+ * parameter must represent the buffer length in words.
+ *
+ * @note Actually, it represents the buffer length in bytes upon entering the function,
+ * and upon exit it represents the length of the data in words.. not good. Fix this.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If the data was not found in flash.
+ * @retval NRF_ERROR_NO_MEM If the provided buffer is too small.
+ */
+ret_code_t pdb_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_peer_data);
+
+
+/**@brief Function for writing data directly to persistent storage from external memory.
+ *
+ * @param[in] peer_id ID of peer to write data for.
+ * @param[in] p_peer_data Data to store.
+ * @param[out] p_store_token A token identifying this particular store operation. The token can be
+ * used to identify events pertaining to this operation.
+ *
+ * @retval NRF_SUCCESS Data successfully written.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
+ * @retval NRF_ERROR_NULL p_peer_data contained a NULL pointer.
+ * @retval NRF_ERROR_STORAGE_FULL No space available in persistent storage.
+ * @retval NRF_ERROR_INVALID_LENGTH Data length above the maximum allowed.
+ * @retval NRF_ERROR_BUSY Unable to perform operation at this time.
+ */
+ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t * p_peer_data,
+ pm_store_token_t * p_store_token);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_DATABASE_H__ */
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c
new file mode 100644
index 0000000..a5f5475
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "peer_id.h"
+
+#include <stdint.h>
+#include <string.h>
+#include "sdk_errors.h"
+#include "peer_manager_types.h"
+#include "pm_mutex.h"
+
+
+typedef struct
+{
+ uint8_t used_peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /**< Bitmap designating which peer IDs are in use. */
+ uint8_t deleted_peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /**< Bitmap designating which peer IDs are marked for deletion. */
+} pi_t;
+
+
+static pi_t m_pi = {{0}, {0}};
+
+
+static void internal_state_reset(pi_t * p_pi)
+{
+ memset(p_pi, 0, sizeof(pi_t));
+}
+
+
+void peer_id_init(void)
+{
+ internal_state_reset(&m_pi);
+ pm_mutex_init(m_pi.used_peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
+ pm_mutex_init(m_pi.deleted_peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
+}
+
+
+static pm_peer_id_t claim(pm_peer_id_t peer_id, uint8_t * mutex_group)
+{
+ pm_peer_id_t allocated_peer_id = PM_PEER_ID_INVALID;
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ allocated_peer_id = pm_mutex_lock_first_available(mutex_group, PM_PEER_ID_N_AVAILABLE_IDS);
+ if (allocated_peer_id == PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ allocated_peer_id = PM_PEER_ID_INVALID;
+ }
+ }
+ else if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ bool lock_success = pm_mutex_lock(mutex_group, peer_id);
+ allocated_peer_id = lock_success ? peer_id : PM_PEER_ID_INVALID;
+ }
+ return allocated_peer_id;
+}
+
+
+static void release(pm_peer_id_t peer_id, uint8_t * mutex_group)
+{
+ if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ pm_mutex_unlock(mutex_group, peer_id);
+ }
+}
+
+
+pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id)
+{
+ return claim(peer_id, m_pi.used_peer_ids);
+}
+
+
+bool peer_id_delete(pm_peer_id_t peer_id)
+{
+ pm_peer_id_t deleted_peer_id;
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ return false;
+ }
+
+ deleted_peer_id = claim(peer_id, m_pi.deleted_peer_ids);
+
+ return (deleted_peer_id == peer_id);
+}
+
+
+void peer_id_free(pm_peer_id_t peer_id)
+{
+ release(peer_id, m_pi.used_peer_ids);
+ release(peer_id, m_pi.deleted_peer_ids);
+}
+
+
+bool peer_id_is_allocated(pm_peer_id_t peer_id)
+{
+ if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ return pm_mutex_lock_status_get(m_pi.used_peer_ids, peer_id);
+ }
+ return false;
+}
+
+
+bool peer_id_is_deleted(pm_peer_id_t peer_id)
+{
+ if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ return pm_mutex_lock_status_get(m_pi.deleted_peer_ids, peer_id);
+ }
+ return false;
+}
+
+
+pm_peer_id_t next_id_get(pm_peer_id_t prev_peer_id, uint8_t * mutex_group)
+{
+ pm_peer_id_t i = (prev_peer_id == PM_PEER_ID_INVALID) ? 0 : (prev_peer_id + 1);
+ for (; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
+ {
+ if (pm_mutex_lock_status_get(mutex_group, i))
+ {
+ return i;
+ }
+ }
+
+ return PM_PEER_ID_INVALID;
+}
+
+
+pm_peer_id_t peer_id_get_next_used(pm_peer_id_t peer_id)
+{
+ peer_id = next_id_get(peer_id, m_pi.used_peer_ids);
+
+ while (peer_id != PM_PEER_ID_INVALID)
+ {
+ if (!peer_id_is_deleted(peer_id))
+ {
+ return peer_id;
+ }
+
+ peer_id = next_id_get(peer_id, m_pi.used_peer_ids);
+ }
+
+ return peer_id;
+}
+
+
+pm_peer_id_t peer_id_get_next_deleted(pm_peer_id_t prev_peer_id)
+{
+ return next_id_get(prev_peer_id, m_pi.deleted_peer_ids);
+}
+
+
+uint32_t peer_id_n_ids(void)
+{
+ uint32_t n_ids = 0;
+
+ for (pm_peer_id_t i = 0; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
+ {
+ n_ids += pm_mutex_lock_status_get(m_pi.used_peer_ids, i);
+ }
+
+ return n_ids;
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h
new file mode 100644
index 0000000..04c99ff
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_ID_H__
+#define PEER_ID_H__
+
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup peer_id Peer IDs
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module keeps track of which peer IDs are in
+ * use and which are free.
+ */
+
+
+/**@brief Function for initializing the module.
+ */
+void peer_id_init(void);
+
+
+/**@brief Function for claiming an unused peer ID.
+ *
+ * @param peer_id The peer ID to allocate. If this is @ref PM_PEER_ID_INVALID, the first available
+ * will be allocated.
+ *
+ * @return The allocated peer ID.
+ * @retval PM_PEER_ID_INVALID If no peer ID could be allocated or module is not initialized.
+ */
+pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id);
+
+
+/**@brief Function for marking a peer ID for deletion.
+ *
+ * @param peer_id The peer ID to delete.
+ *
+ * @retval true Deletion was successful.
+ * @retval false Peer ID already marked for deletion, peer_id was PM_PEER_ID_INVALID, or module is
+ * not initialized.
+ */
+bool peer_id_delete(pm_peer_id_t peer_id);
+
+
+/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent
+ * storage.
+ *
+ * @param[in] peer_id Peer ID to free.
+ */
+void peer_id_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function for finding out whether a peer ID is marked for deletion.
+ *
+ * @param[in] peer_id The peer ID to inquire about.
+ *
+ * @retval true peer_id is in marked for deletion.
+ * @retval false peer_id is not marked for deletion, or the module is not initialized.
+ */
+bool peer_id_is_deleted(pm_peer_id_t peer_id);
+
+
+/**@brief Function for finding out whether a peer ID is in use.
+ *
+ * @param[in] peer_id The peer ID to inquire about.
+ *
+ * @retval true peer_id is in use.
+ * @retval false peer_id is free, or the module is not initialized.
+ */
+bool peer_id_is_allocated(pm_peer_id_t peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
+ * used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID.
+ * @return The first used peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module is
+ * not initialized.
+ */
+pm_peer_id_t peer_id_get_next_used(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all peer IDs marked for deletion.
+ * Can be used to loop through all peer IDs marked for deletion.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID.
+ * @return The first used peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module is
+ * not initialized.
+ */
+pm_peer_id_t peer_id_get_next_deleted(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
+ * in persistent storage.
+ *
+ * @return The number of valid peer IDs, or 0 if module is not initialized.
+ */
+uint32_t peer_id_n_ids(void);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_ID_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c
new file mode 100644
index 0000000..7de5793
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c
@@ -0,0 +1,983 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "ble_err.h"
+#include "peer_manager.h"
+#include <string.h>
+#include "security_manager.h"
+#include "security_dispatcher.h"
+#include "gatt_cache_manager.h"
+#include "gatts_cache_manager.h"
+#include "peer_database.h"
+#include "peer_data_storage.h"
+#include "id_manager.h"
+#include "ble_conn_state.h"
+#include "peer_manager_internal.h"
+#include "nrf_sdh_ble.h"
+
+#ifndef PM_PEER_RANKS_ENABLED
+ #define PM_PEER_RANKS_ENABLED 1
+#endif
+
+#define MODULE_INITIALIZED (m_module_initialized) /**< Macro indicating whether the module has been initialized properly. */
+
+
+static bool m_module_initialized; /**< Whether or not @ref pm_init has been called successfully. */
+static bool m_peer_rank_initialized; /**< Whether or not @ref rank_init has been called successfully. */
+static bool m_deleting_all; /**< True from when @ref pm_peers_delete is called until all peers have been deleted. */
+static pm_store_token_t m_peer_rank_token; /**< The store token of an ongoing peer rank update via a call to @ref pm_peer_rank_highest. If @ref PM_STORE_TOKEN_INVALID, there is no ongoing update. */
+static uint32_t m_current_highest_peer_rank; /**< The current highest peer rank. Used by @ref pm_peer_rank_highest. */
+static pm_peer_id_t m_highest_ranked_peer; /**< The peer with the highest peer rank. Used by @ref pm_peer_rank_highest. */
+static pm_evt_handler_t m_evt_handlers[PM_MAX_REGISTRANTS];/**< The subscribers to Peer Manager events, as registered through @ref pm_register. */
+static uint8_t m_n_registrants; /**< The number of event handlers registered through @ref pm_register. */
+
+
+/**@brief Function for sending a Peer Manager event to all subscribers.
+ *
+ * @param[in] p_pm_evt The event to send.
+ */
+static void evt_send(pm_evt_t const * p_pm_evt)
+{
+ for (int i = 0; i < m_n_registrants; i++)
+ {
+ m_evt_handlers[i](p_pm_evt);
+ }
+}
+
+
+#if PM_PEER_RANKS_ENABLED == 1
+/**@brief Function for initializing peer rank static variables.
+ */
+static void rank_vars_update(void)
+{
+ ret_code_t err_code = pm_peer_ranks_get(&m_highest_ranked_peer,
+ &m_current_highest_peer_rank,
+ NULL,
+ NULL);
+
+ m_peer_rank_initialized = ((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NOT_FOUND));
+}
+#endif
+
+
+/**@brief Event handler for events from the Peer Database module.
+ * This handler is extern in the Peer Database module.
+ *
+ * @param[in] p_pdb_evt The incoming Peer Database event.
+ */
+void pm_pdb_evt_handler(pm_evt_t * p_pdb_evt)
+{
+ bool send_evt = true;
+
+ p_pdb_evt->conn_handle = im_conn_handle_get(p_pdb_evt->peer_id);
+
+ switch (p_pdb_evt->evt_id)
+ {
+#if PM_PEER_RANKS_ENABLED == 1
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ if (p_pdb_evt->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ {
+ if ( (m_peer_rank_token != PM_STORE_TOKEN_INVALID)
+ && (m_peer_rank_token == p_pdb_evt->params.peer_data_update_succeeded.token))
+ {
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+ m_highest_ranked_peer = p_pdb_evt->peer_id;
+
+ p_pdb_evt->params.peer_data_update_succeeded.token = PM_STORE_TOKEN_INVALID;
+ }
+ else if ( m_peer_rank_initialized
+ && (p_pdb_evt->peer_id == m_highest_ranked_peer)
+ && (p_pdb_evt->params.peer_data_update_succeeded.data_id
+ == PM_PEER_DATA_ID_PEER_RANK))
+ {
+ // Update peer rank variable if highest ranked peer has changed its rank.
+ rank_vars_update();
+ }
+ }
+ else if (p_pdb_evt->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_DELETE)
+ {
+ if ( m_peer_rank_initialized
+ && (p_pdb_evt->peer_id == m_highest_ranked_peer)
+ && (p_pdb_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_PEER_RANK))
+ {
+ // Update peer rank variable if highest ranked peer has deleted its rank.
+ rank_vars_update();
+ }
+ }
+ break;
+
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ if (p_pdb_evt->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ {
+ if ( (m_peer_rank_token != PM_STORE_TOKEN_INVALID)
+ && (m_peer_rank_token == p_pdb_evt->params.peer_data_update_failed.token))
+ {
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+ m_current_highest_peer_rank -= 1;
+
+ p_pdb_evt->params.peer_data_update_succeeded.token = PM_STORE_TOKEN_INVALID;
+ }
+ }
+ break;
+#endif
+
+ case PM_EVT_PEER_DELETE_SUCCEEDED:
+ // Check that no peers marked for deletion are left.
+ if (m_deleting_all
+ && (pdb_next_peer_id_get(PM_PEER_ID_INVALID) == PM_PEER_ID_INVALID)
+ && (pdb_next_deleted_peer_id_get(PM_PEER_ID_INVALID) == PM_PEER_ID_INVALID))
+ {
+ // pm_peers_delete() has been called and this is the last peer to be deleted.
+ m_deleting_all = false;
+
+ pm_evt_t pm_delete_all_evt;
+ memset(&pm_delete_all_evt, 0, sizeof(pm_evt_t));
+ pm_delete_all_evt.evt_id = PM_EVT_PEERS_DELETE_SUCCEEDED;
+ pm_delete_all_evt.peer_id = PM_PEER_ID_INVALID;
+ pm_delete_all_evt.conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ send_evt = false;
+
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_pdb_evt); // Ensure that PEER_DELETE_SUCCEEDED arrives before PEERS_DELETE_SUCCEEDED.
+ evt_send(&pm_delete_all_evt);
+ }
+
+#if PM_PEER_RANKS_ENABLED == 1
+ if (m_peer_rank_initialized && (p_pdb_evt->peer_id == m_highest_ranked_peer))
+ {
+ // Update peer rank variable if highest ranked peer has been deleted.
+ rank_vars_update();
+ }
+#endif
+ break;
+
+ case PM_EVT_PEER_DELETE_FAILED:
+ if (m_deleting_all)
+ {
+ // pm_peers_delete() was called and has thus failed.
+
+ m_deleting_all = false;
+
+ pm_evt_t pm_delete_all_evt;
+ memset(&pm_delete_all_evt, 0, sizeof(pm_evt_t));
+ pm_delete_all_evt.evt_id = PM_EVT_PEERS_DELETE_FAILED;
+ pm_delete_all_evt.peer_id = PM_PEER_ID_INVALID;
+ pm_delete_all_evt.conn_handle = BLE_CONN_HANDLE_INVALID;
+ pm_delete_all_evt.params.peers_delete_failed_evt.error
+ = p_pdb_evt->params.peer_delete_failed.error;
+
+ send_evt = false;
+
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_pdb_evt); // Ensure that PEER_DELETE_FAILED arrives before PEERS_DELETE_FAILED.
+ evt_send(&pm_delete_all_evt);
+ }
+ break;
+
+ default:
+ // Do nothing.
+ break;
+ }
+
+ if (send_evt)
+ {
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_pdb_evt);
+ }
+}
+
+
+/**@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(pm_evt_t * p_sm_evt)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_sm_evt);
+
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_sm_evt);
+}
+
+
+/**@brief Event handler for events from the GATT Cache Manager module.
+ * This handler is extern in GATT Cache Manager.
+ *
+ * @param[in] p_gcm_evt The incoming GATT Cache Manager event.
+ */
+void pm_gcm_evt_handler(pm_evt_t * p_gcm_evt)
+{
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_gcm_evt);
+}
+
+
+/**@brief Event handler for events from the ID Manager module.
+ * This function is registered in the ID Manager.
+ *
+ * @param[in] p_im_evt The incoming ID Manager event.
+ */
+void pm_im_evt_handler(pm_evt_t * p_im_evt)
+{
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_im_evt);
+}
+
+/**
+ * @brief Function for handling BLE events.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Context.
+ */
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ im_ble_evt_handler(p_ble_evt);
+ sm_ble_evt_handler(p_ble_evt);
+ gcm_ble_evt_handler(p_ble_evt);
+}
+
+NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, PM_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
+
+
+/**@brief Function for resetting the internal state of this module.
+ */
+static void internal_state_reset()
+{
+ m_highest_ranked_peer = PM_PEER_ID_INVALID;
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+}
+
+
+ret_code_t pm_init(void)
+{
+ ret_code_t err_code;
+
+ err_code = pds_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = pdb_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = sm_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = smd_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = gcm_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = gscm_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = im_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ internal_state_reset();
+
+ m_peer_rank_initialized = false;
+ m_module_initialized = true;
+
+ // If PM_PEER_RANKS_ENABLED is 0, these variables are unused.
+ UNUSED_VARIABLE(m_peer_rank_initialized);
+ UNUSED_VARIABLE(m_peer_rank_token);
+ UNUSED_VARIABLE(m_current_highest_peer_rank);
+ UNUSED_VARIABLE(m_highest_ranked_peer);
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_register(pm_evt_handler_t event_handler)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if (m_n_registrants >= PM_MAX_REGISTRANTS)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ m_evt_handlers[m_n_registrants] = event_handler;
+ m_n_registrants += 1;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_sec_params_set(ble_gap_sec_params_t * p_sec_params)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+
+ err_code = sm_sec_params_set(p_sec_params);
+
+ // NRF_ERROR_INVALID_PARAM if parameters are invalid,
+ // NRF_SUCCESS otherwise.
+ return err_code;
+}
+
+
+ret_code_t pm_conn_secure(uint16_t conn_handle, bool force_repairing)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+
+ err_code = sm_link_secure(conn_handle, force_repairing);
+
+ if (err_code == NRF_ERROR_INVALID_STATE)
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+
+ return err_code;
+}
+
+
+void pm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config)
+{
+ if (p_conn_sec_config != NULL)
+ {
+ sm_conn_sec_config_reply(conn_handle, p_conn_sec_config);
+ }
+}
+
+
+ret_code_t pm_conn_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ return sm_sec_params_reply(conn_handle, p_sec_params, p_context);
+}
+
+
+void pm_local_database_has_changed(void)
+{
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ gcm_local_database_has_changed();
+#endif
+}
+
+
+ret_code_t pm_id_addr_set(ble_gap_addr_t const * p_addr)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return im_id_addr_set(p_addr);
+}
+
+
+ret_code_t pm_id_addr_get(ble_gap_addr_t * p_addr)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_addr);
+ return im_id_addr_get(p_addr);
+}
+
+
+ret_code_t pm_privacy_set(pm_privacy_params_t const * p_privacy_params)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_privacy_params);
+ return im_privacy_set(p_privacy_params);
+}
+
+
+ret_code_t pm_privacy_get(pm_privacy_params_t * p_privacy_params)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_privacy_params);
+ VERIFY_PARAM_NOT_NULL(p_privacy_params->p_device_irk);
+ return im_privacy_get(p_privacy_params);
+}
+
+
+bool pm_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if ((p_addr == NULL) || (p_irk == NULL))
+ {
+ return false;
+ }
+ else
+ {
+ return im_address_resolve(p_addr, p_irk);
+ }
+}
+
+
+ret_code_t pm_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return im_whitelist_set(p_peers, peer_cnt);
+}
+
+
+ret_code_t pm_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if (((p_addrs == NULL) && (p_irks == NULL)) ||
+ ((p_addrs != NULL) && (p_addr_cnt == NULL)) ||
+ ((p_irks != NULL) && (p_irk_cnt == NULL)))
+ {
+ // The buffers can't be both NULL, and if a buffer is provided its size must be specified.
+ return NRF_ERROR_NULL;
+ }
+
+ return im_whitelist_get(p_addrs, p_addr_cnt, p_irks, p_irk_cnt);
+}
+
+
+ret_code_t pm_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return im_device_identities_list_set(p_peers, peer_cnt);
+}
+
+
+ret_code_t pm_conn_sec_status_get(uint16_t conn_handle, pm_conn_sec_status_t * p_conn_sec_status)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_conn_sec_status);
+
+ ble_conn_state_status_t status = ble_conn_state_status(conn_handle);
+
+ if (status == BLE_CONN_STATUS_INVALID)
+ {
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+
+ p_conn_sec_status->connected = (status == BLE_CONN_STATUS_CONNECTED);
+ p_conn_sec_status->bonded = (im_peer_id_get_by_conn_handle(conn_handle) != PM_PEER_ID_INVALID);
+ p_conn_sec_status->encrypted = ble_conn_state_encrypted(conn_handle);
+ p_conn_sec_status->mitm_protected = ble_conn_state_mitm_protected(conn_handle);
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return sm_lesc_public_key_set(p_public_key);
+}
+
+
+ret_code_t pm_conn_handle_get(pm_peer_id_t peer_id, uint16_t * p_conn_handle)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_conn_handle);
+ *p_conn_handle = im_conn_handle_get(peer_id);
+ return NRF_SUCCESS;
+}
+
+
+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;
+}
+
+
+uint32_t pm_peer_count(void)
+{
+ if (!MODULE_INITIALIZED)
+ {
+ return 0;
+ }
+ return pdb_n_peers();
+}
+
+
+pm_peer_id_t pm_next_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ if (!MODULE_INITIALIZED)
+ {
+ return PM_PEER_ID_INVALID;
+ }
+ return pdb_next_peer_id_get(prev_peer_id);
+}
+
+
+ret_code_t pm_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void * p_data,
+ uint16_t * p_length)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_data);
+ VERIFY_PARAM_NOT_NULL(p_length);
+ if (ALIGN_NUM(4, *p_length) != *p_length)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ pm_peer_data_t peer_data;
+ memset(&peer_data, 0, sizeof(peer_data));
+ peer_data.length_words = BYTES_TO_WORDS(*p_length);
+ peer_data.data_id = data_id;
+ peer_data.p_all_data = p_data;
+
+ ret_code_t err_code = pdb_peer_data_load(peer_id, data_id, &peer_data);
+
+ *p_length = peer_data.length_words * BYTES_PER_WORD;
+
+ return err_code;
+}
+
+
+ret_code_t pm_peer_data_bonding_load(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t * p_data)
+{
+ uint16_t length = sizeof(pm_peer_data_bonding_t);
+ return pm_peer_data_load(peer_id,
+ PM_PEER_DATA_ID_BONDING,
+ p_data,
+ &length);
+}
+
+
+ret_code_t pm_peer_data_remote_db_load(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t * p_data,
+ uint16_t * p_length)
+{
+ return pm_peer_data_load(peer_id,
+ PM_PEER_DATA_ID_GATT_REMOTE,
+ p_data,
+ p_length);
+}
+
+
+ret_code_t pm_peer_data_app_data_load(pm_peer_id_t peer_id,
+ void * p_data,
+ uint16_t * p_length)
+{
+ return pm_peer_data_load(peer_id,
+ PM_PEER_DATA_ID_APPLICATION,
+ p_data,
+ p_length);
+}
+
+
+ret_code_t pm_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void const * p_data,
+ uint16_t length,
+ pm_store_token_t * p_token)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_data);
+ if (ALIGN_NUM(4, length) != length)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ if (data_id == PM_PEER_DATA_ID_BONDING)
+ {
+ pm_peer_id_t dupl_peer_id;
+ dupl_peer_id = im_find_duplicate_bonding_data((pm_peer_data_bonding_t *) p_data, peer_id);
+
+ if (dupl_peer_id != PM_PEER_ID_INVALID)
+ {
+ return NRF_ERROR_FORBIDDEN;
+ }
+ }
+
+ pm_peer_data_flash_t peer_data;
+ memset(&peer_data, 0, sizeof(peer_data));
+ peer_data.length_words = BYTES_TO_WORDS(length);
+ peer_data.data_id = data_id;
+ peer_data.p_all_data = p_data;
+
+ return pdb_raw_store(peer_id, &peer_data, p_token);
+}
+
+
+ret_code_t pm_peer_data_bonding_store(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t const * p_data,
+ pm_store_token_t * p_token)
+{
+ return pm_peer_data_store(peer_id,
+ PM_PEER_DATA_ID_BONDING,
+ p_data,
+ ALIGN_NUM(4, sizeof(pm_peer_data_bonding_t)),
+ p_token);
+}
+
+
+ret_code_t pm_peer_data_remote_db_store(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t const * p_data,
+ uint16_t length,
+ pm_store_token_t * p_token)
+{
+ return pm_peer_data_store(peer_id,
+ PM_PEER_DATA_ID_GATT_REMOTE,
+ p_data,
+ length,
+ p_token);
+}
+
+
+ret_code_t pm_peer_data_app_data_store(pm_peer_id_t peer_id,
+ void const * p_data,
+ uint16_t length,
+ pm_store_token_t * p_token)
+{
+ return pm_peer_data_store(peer_id,
+ PM_PEER_DATA_ID_APPLICATION,
+ p_data,
+ length,
+ p_token);
+}
+
+
+ret_code_t pm_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if (data_id == PM_PEER_DATA_ID_BONDING)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return pdb_clear(peer_id, data_id);
+}
+
+
+ret_code_t pm_peer_new(pm_peer_id_t * p_new_peer_id,
+ pm_peer_data_bonding_t * p_bonding_data,
+ pm_store_token_t * p_token)
+{
+ ret_code_t err_code;
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data;
+
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_bonding_data);
+ VERIFY_PARAM_NOT_NULL(p_new_peer_id);
+
+ memset(&peer_data, 0, sizeof(pm_peer_data_flash_t));
+
+ // Search through existing bonds to look for a duplicate.
+ pds_peer_data_iterate_prepare();
+
+ // @note emdi: should maybe use a critical section, since data is not copied while iterating.
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data))
+ {
+ if (im_is_duplicate_bonding_data(p_bonding_data, peer_data.p_bonding_data))
+ {
+ *p_new_peer_id = peer_id;
+ return NRF_SUCCESS;
+ }
+ }
+
+ // If no duplicate data is found, prepare to write a new bond to flash.
+
+ *p_new_peer_id = pdb_peer_allocate();
+
+ if (*p_new_peer_id == PM_PEER_ID_INVALID)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ memset(&peer_data, 0, sizeof(pm_peer_data_flash_t));
+
+ peer_data.data_id = PM_PEER_DATA_ID_BONDING;
+ peer_data.p_bonding_data = p_bonding_data;
+ peer_data.length_words = BYTES_TO_WORDS(sizeof(pm_peer_data_bonding_t));
+
+ err_code = pdb_raw_store(*p_new_peer_id, &peer_data, p_token);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (im_peer_free(*p_new_peer_id) != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ // NRF_ERROR_STORAGE_FULL, if no space in flash.
+ // NRF_ERROR_BUSY, if flash filesystem was busy.
+ // NRF_ERROR_INTENRAL, on internal error.
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_peer_delete(pm_peer_id_t peer_id)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ return im_peer_free(peer_id);
+}
+
+
+ret_code_t pm_peers_delete(void)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ m_deleting_all = true;
+
+ pm_peer_id_t current_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
+
+ if (current_peer_id == PM_PEER_ID_INVALID)
+ {
+ // No peers bonded.
+ m_deleting_all = false;
+
+ pm_evt_t pm_delete_all_evt;
+ memset(&pm_delete_all_evt, 0, sizeof(pm_evt_t));
+ pm_delete_all_evt.evt_id = PM_EVT_PEERS_DELETE_SUCCEEDED;
+ pm_delete_all_evt.peer_id = PM_PEER_ID_INVALID;
+ pm_delete_all_evt.conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ evt_send(&pm_delete_all_evt);
+ }
+
+ while (current_peer_id != PM_PEER_ID_INVALID)
+ {
+ ret_code_t err_code = pm_peer_delete(current_peer_id);
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ current_peer_id = pdb_next_peer_id_get(current_peer_id);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_peer_ranks_get(pm_peer_id_t * p_highest_ranked_peer,
+ uint32_t * p_highest_rank,
+ pm_peer_id_t * p_lowest_ranked_peer,
+ uint32_t * p_lowest_rank)
+{
+#if PM_PEER_RANKS_ENABLED == 0
+ return NRF_ERROR_NOT_SUPPORTED;
+#else
+ VERIFY_MODULE_INITIALIZED();
+
+ pm_peer_id_t peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
+ uint32_t peer_rank = 0;
+ //lint -save -e65 -e64
+ pm_peer_data_t peer_data = {.length_words = BYTES_TO_WORDS(sizeof(peer_rank)),
+ .p_peer_rank = &peer_rank};
+ //lint -restore
+ ret_code_t err_code = pdb_peer_data_load(peer_id, PM_PEER_DATA_ID_PEER_RANK, &peer_data);
+ uint32_t highest_rank = 0;
+ uint32_t lowest_rank = 0xFFFFFFFF;
+ pm_peer_id_t highest_ranked_peer = PM_PEER_ID_INVALID;
+ pm_peer_id_t lowest_ranked_peer = PM_PEER_ID_INVALID;
+
+ if (err_code == NRF_ERROR_INVALID_PARAM)
+ {
+ // No peer IDs exist.
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ while ((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NOT_FOUND))
+ {
+ if (err_code == NRF_ERROR_NOT_FOUND)
+ {
+ peer_rank = 0;
+ }
+ if (peer_rank >= highest_rank)
+ {
+ highest_rank = peer_rank;
+ highest_ranked_peer = peer_id;
+ }
+ if (peer_rank < lowest_rank)
+ {
+ lowest_rank = peer_rank;
+ lowest_ranked_peer = peer_id;
+ }
+ peer_id = pdb_next_peer_id_get(peer_id);
+ err_code = pdb_peer_data_load(peer_id, PM_PEER_DATA_ID_PEER_RANK, &peer_data);
+ }
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ err_code = NRF_SUCCESS;
+ if (p_highest_ranked_peer != NULL)
+ {
+ *p_highest_ranked_peer = highest_ranked_peer;
+ }
+ if (p_highest_rank != NULL)
+ {
+ *p_highest_rank = highest_rank;
+ }
+ if (p_lowest_ranked_peer != NULL)
+ {
+ *p_lowest_ranked_peer = lowest_ranked_peer;
+ }
+ if (p_lowest_rank != NULL)
+ {
+ *p_lowest_rank = lowest_rank;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ return err_code;
+#endif
+}
+
+
+#if PM_PEER_RANKS_ENABLED == 1
+/**@brief Function for initializing peer rank functionality.
+ */
+static void rank_init(void)
+{
+ rank_vars_update();
+}
+#endif
+
+
+ret_code_t pm_peer_rank_highest(pm_peer_id_t peer_id)
+{
+#if PM_PEER_RANKS_ENABLED == 0
+ return NRF_ERROR_NOT_SUPPORTED;
+#else
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+ //lint -save -e65 -e64
+ pm_peer_data_flash_t peer_data = {.length_words = BYTES_TO_WORDS(sizeof(m_current_highest_peer_rank)),
+ .data_id = PM_PEER_DATA_ID_PEER_RANK,
+ .p_peer_rank = &m_current_highest_peer_rank};
+ //lint -restore
+
+
+ if (!m_peer_rank_initialized)
+ {
+ rank_init();
+ }
+
+ if (!m_peer_rank_initialized || (m_peer_rank_token != PM_STORE_TOKEN_INVALID))
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+ else
+ {
+ if ((peer_id == m_highest_ranked_peer) && (m_current_highest_peer_rank > 0))
+ {
+ pm_evt_t pm_evt;
+
+ // The reported peer is already regarded as highest (provided it has an index at all)
+ err_code = NRF_SUCCESS;
+
+ memset(&pm_evt, 0, sizeof(pm_evt));
+ pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_SUCCEEDED;
+ pm_evt.conn_handle = im_conn_handle_get(peer_id);
+ pm_evt.peer_id = peer_id;
+ pm_evt.params.peer_data_update_succeeded.data_id = PM_PEER_DATA_ID_PEER_RANK;
+ pm_evt.params.peer_data_update_succeeded.action = PM_PEER_DATA_OP_UPDATE;
+ pm_evt.params.peer_data_update_succeeded.token = PM_STORE_TOKEN_INVALID;
+ pm_evt.params.peer_data_update_succeeded.flash_changed = false;
+
+ evt_send(&pm_evt);
+ }
+ else
+ {
+ if (m_current_highest_peer_rank == UINT32_MAX)
+ {
+ err_code = NRF_ERROR_RESOURCES;
+ }
+ else
+ {
+ m_current_highest_peer_rank += 1;
+ err_code = pdb_raw_store(peer_id, &peer_data, &m_peer_rank_token);
+ if (err_code != NRF_SUCCESS)
+ {
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+ m_current_highest_peer_rank -= 1;
+ {
+ if ((err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_STORAGE_FULL))
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ }
+ }
+ }
+ return err_code;
+#endif
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h
new file mode 100644
index 0000000..c320101
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h
@@ -0,0 +1,781 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file peer_manager.h
+ *
+ * @defgroup peer_manager Peer Manager
+ * @ingroup ble_sdk_lib
+ * @{
+ * @brief Module for managing BLE bonding, which includes controlling encryption and pairing
+ * procedures as well as persistently storing different pieces of data that must be stored
+ * when bonded.
+ *
+ * @details The API consists of functions for configuring the pairing and encryption behavior of the
+ * device and functions for manipulating the stored data.
+ *
+ * This module uses Flash Data Storage (FDS) to interface with persistent storage. The
+ * Peer Manager needs exclusive use of certain FDS file IDs and record keys. See
+ * @ref lib_fds_functionality_keys for more information.
+ */
+
+
+#ifndef PEER_MANAGER_H__
+#define PEER_MANAGER_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "sdk_common.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "peer_database.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**@brief Security status of a connection.
+ */
+typedef struct
+{
+ uint8_t connected : 1; /**< @brief The connection is active (not disconnected). */
+ uint8_t encrypted : 1; /**< @brief Communication on this link is encrypted. */
+ uint8_t mitm_protected : 1; /**< @brief The encrypted communication is also protected against man-in-the-middle attacks. */
+ uint8_t bonded : 1; /**< @brief The peer is bonded with us. */
+} pm_conn_sec_status_t;
+
+
+/**@brief Function for initializing the Peer Manager.
+ *
+ * @details You must initialize the Peer Manager before you can call any other Peer Manager
+ * functions.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_init(void);
+
+
+/**@brief Function for registering an event handler with the Peer Manager.
+ *
+ * @param[in] event_handler Callback for events from the @ref peer_manager module. @p event_handler
+ * is called for every event that the Peer Manager sends after this
+ * function is called.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_NULL If @p event_handler was NULL.
+ * @retval NRF_ERROR_NO_MEM If no more registrations can happen.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_register(pm_evt_handler_t event_handler);
+
+
+/**@brief Function for providing pairing and bonding parameters to use for pairing procedures.
+ *
+ * @details Until this function is called, all bonding procedures that are initiated by the
+ * peer are rejected.
+ *
+ * This function can be called multiple times with different parameters, even with NULL as
+ * @p p_sec_params, in which case the Peer Manager starts rejecting all procedures again.
+ *
+ * @param[in] p_sec_params Security parameters to be used for subsequent security procedures.
+ *
+ * @retval NRF_SUCCESS If the parameters were set successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If the combination of parameters is invalid.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_sec_params_set(ble_gap_sec_params_t * p_sec_params);
+
+
+/**@brief Function for establishing encryption on a connection, and optionally establishing a bond.
+ *
+ * @details This function attempts to secure the link that is specified by @p conn_handle. It uses
+ * the parameters that were previously provided in a call to @ref pm_sec_params_set.
+ *
+ * If the connection is a master connection, calling this function starts a security
+ * procedure on the link. If we have keys from a previous bonding procedure with this peer
+ * and the keys meet the security requirements in the currently active security parameters,
+ * the function attempts to establish encryption with the existing keys. If no key exists,
+ * the function attempts to perform pairing and bonding according to the currently active
+ * security parameters.
+ *
+ * If the function completes successfully, a @ref PM_EVT_CONN_SEC_START event is sent.
+ * The procedure might be queued, in which case the @ref PM_EVT_CONN_SEC_START event is
+ * delayed until the procedure is initiated in the SoftDevice.
+ *
+ * If the connection is a slave connection, the function sends a security request to
+ * the peer (master). It is up to the peer then to initiate pairing or encryption.
+ * If the peer ignores the request, a @ref BLE_GAP_EVT_AUTH_STATUS event occurs
+ * with the status @ref BLE_GAP_SEC_STATUS_TIMEOUT. Otherwise, the peer initiates
+ * security, in which case things happen as if the peer had initiated security itself.
+ * See @ref PM_EVT_CONN_SEC_START for information about peer-initiated security.
+ *
+ * @param[in] conn_handle Connection handle of the link as provided by the SoftDevice.
+ * @param[in] force_repairing Whether to force a pairing procedure even if there is an existing
+ * encryption key. This argument is relevant only for
+ * the central role. Recommended value: false.
+ *
+ * @retval NRF_SUCCESS If the operation completed successfully.
+ * @retval NRF_ERROR_BUSY If a security procedure is already in progress on the link,
+ * or if the link is disconnecting or disconnected.
+ * @retval NRF_ERROR_TIMEOUT If there was an SMP time-out, so that no more security
+ * operations can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE If the connection handle is invalid.
+ * @retval NRF_ERROR_NOT_FOUND If the security parameters have not been set, either by
+ * @ref pm_sec_params_set or by @ref pm_conn_sec_params_reply.
+ * @retval NRF_ERROR_INVALID_DATA If the peer is bonded, but no LTK was found in the stored
+ * bonding data. Repairing was not requested.
+ * @retval NRF_ERROR_STORAGE_FULL If there is no more space in persistent storage.
+ * @retval NRF_ERROR_NO_MEM If no more authentication procedures can run in parallel
+ * for the given role. See @ref sd_ble_gap_authenticate.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_conn_secure(uint16_t conn_handle, bool force_repairing);
+
+
+/**@brief Function for providing security configuration for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_CONFIG_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, a default configuration is used. See @ref pm_conn_sec_config_t
+ * for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the configuration for.
+ * @param[in] p_conn_sec_config The configuration.
+ */
+void pm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config);
+
+
+/**@brief Function for providing security parameters for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_PARAMS_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, the parameters given in @ref pm_sec_params_set are used. See @ref
+ * pm_conn_sec_config_t for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the parameters for.
+ * @param[in] p_sec_params The parameters. If NULL, the security procedure is rejected.
+ * @param[in] p_context The context found in the request event that this function replies to.
+ *
+ * @retval NRF_SUCCESS Successful reply.
+ * @retval NRF_ERROR_NULL p_sec_params or p_context was null.
+ * @retval NRF_ERROR_INVALID_PARAM Value of p_sec_params was invalid.
+ * @retval NRF_ERROR_INVALID_STATE This module is not initialized.
+ */
+ret_code_t pm_conn_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context);
+
+
+/**@brief Function for manually informing that the local database has changed.
+ *
+ * @details This function sends a service changed indication to all bonded and/or connected peers
+ * that subscribe to this indication. If a bonded peer is not connected, the indication is
+ * sent when it reconnects. Every time an indication is sent, a @ref
+ * PM_EVT_SERVICE_CHANGED_IND_SENT event occurs, followed by a @ref
+ * PM_EVT_SERVICE_CHANGED_IND_CONFIRMED when the peer sends its confirmation. Peers that
+ * are not subscribed to the service changed indication when this function is called do not
+ * receive an indication, and no events are sent to the user. Likewise, if the service
+ * changed characteristic is not present in the local database, or if the @ref
+ * PM_SERVICE_CHANGED_ENABLED is set to 0, no indications are sent peers, and no events are
+ * sent to the user.
+ */
+void pm_local_database_has_changed(void);
+
+
+/**@brief Function for getting the security status of a connection.
+ *
+ * @param[in] conn_handle Connection handle of the link as provided by the SoftDevice.
+ * @param[out] p_conn_sec_status Security status of the link.
+ *
+ * @retval NRF_SUCCESS If pairing was initiated successfully.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE If the connection handle is invalid.
+ * @retval NRF_ERROR_NULL If @p p_conn_sec_status was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_conn_sec_status_get(uint16_t conn_handle, pm_conn_sec_status_t * p_conn_sec_status);
+
+
+/**@brief Experimental function for specifying the public key to use for LESC operations.
+ *
+ * @details This function can be called multiple times. The specified public key will be used for
+ * all subsequent LESC (LE Secure Connections) operations until the next time this function
+ * is called.
+ *
+ * @note The key must continue to reside in application memory as it is not copied by Peer Manager.
+ *
+ * @param[in] p_public_key The public key to use for all subsequent LESC operations.
+ *
+ * @retval NRF_SUCCESS If pairing was initiated successfully.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key);
+
+
+/**@brief Function for setting or clearing the whitelist.
+ *
+ * When using the S13x SoftDevice v3.x, this function sets or clears the whitelist.
+ * When using the S13x SoftDevice v2.x, this function caches a list of
+ * peers that can be retrieved later by @ref pm_whitelist_get to pass to the @ref lib_ble_advertising.
+ *
+ * To clear the current whitelist, pass either NULL as @p p_peers or zero as @p peer_cnt.
+ *
+ * @param[in] p_peers The peers to add to the whitelist. Pass NULL to clear the current whitelist.
+ * @param[in] peer_cnt The number of peers to add to the whitelist. The number must not be greater than
+ * @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. Pass zero to clear the current
+ * whitelist.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully set or cleared.
+ * @retval BLE_GAP_ERROR_WHITELIST_IN_USE If a whitelist is already in use and cannot be set.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If a peer in @p p_peers has an address that cannot
+ * be used for whitelisting.
+ * @retval NRF_ERROR_NOT_FOUND If any of the peers in @p p_peers cannot be found.
+ * @retval NRF_ERROR_DATA_SIZE If @p peer_cnt is greater than
+ * @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt);
+
+
+/**@brief Function for retrieving the previously set whitelist.
+ *
+ * The function retrieves the whitelist of GAP addresses and IRKs that was
+ * previously set by @ref pm_whitelist_set.
+ *
+ * To retrieve only GAP addresses or only IRKs, provide only one of the
+ * buffers. If a buffer is provided, its size must be specified.
+ *
+ * @param[out] p_addrs The buffer where to store GAP addresses. Pass NULL to retrieve
+ * only IRKs (in that case, @p p_irks must not be NULL).
+ * @param[in,out] p_addr_cnt In: The size of the @p p_addrs buffer.
+ * May be NULL if and only if @p p_addrs is NULL.
+ * Out: The number of GAP addresses copied into the buffer.
+ * If @p p_addrs is NULL, this parameter remains unchanged.
+ * @param[out] p_irks The buffer where to store IRKs. Pass NULL to retrieve
+ * only GAP addresses (in that case, @p p_addrs must not NULL).
+ * @param[in,out] p_irk_cnt In: The size of the @p p_irks buffer.
+ * May be NULL if and only if @p p_irks is NULL.
+ * Out: The number of IRKs copied into the buffer.
+ * If @p p_irks is NULL, this paramater remains unchanged.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully retrieved.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If a peer has an address that cannot be used for
+ * whitelisting (this error can occur only
+ * when using the S13x SoftDevice v2.x).
+ * @retval NRF_ERROR_NULL If a required parameter is NULL.
+ * @retval NRF_ERROR_NO_MEM If the provided buffers are too small.
+ * @retval NRF_ERROR_NOT_FOUND If the data for any of the cached whitelisted peers
+ * cannot be found. It might have been deleted.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt);
+
+
+/**@brief Function for setting and clearing the device identities list.
+ *
+ * @param[in] p_peers The peers to add to the device identities list. Pass NULL to clear
+ * the device identities list.
+ * @param[in] peer_cnt The number of peers. Pass zero to clear the device identities list.
+ *
+ * @retval NRF_SUCCESS If the device identities list was successfully
+ * set or cleared.
+ * @retval NRF_ERROR_NOT_FOUND If a peer is invalid or its data could not
+ * be found in flash.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If a peer has an address that cannot be
+ * used for whitelisting.
+ * @retval BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE If the device identities list is in use and
+ * cannot be set.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_NOT_SUPPORTED If using a SoftDevice that does not support
+ * device identities, e.g. S130 v2.0.
+ */
+ret_code_t pm_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt);
+
+
+/**@brief Function for setting the local <em>Bluetooth</em> identity address.
+ *
+ * @details The local <em>Bluetooth</em> identity address is the address that identifies the device
+ * to other peers. The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC. The identity address cannot be changed while roles are running.
+ *
+ * The SoftDevice sets a default address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC when it is
+ * enabled. This default address is a random number that is populated during the IC manufacturing
+ * process. It remains unchanged for the lifetime of each IC, but the application can use this
+ * function to assign a different identity address.
+ *
+ * The identity address is distributed to the peer during bonding. Changing the identity address
+ * means bonded devices might not recognize us.
+ *
+ * @note The SoftDevice functions @ref sd_ble_gap_addr_set and @ref sd_ble_gap_privacy_set must not
+ * be called when using the Peer Manager. Use the Peer Manager equivalents instead.
+ *
+ * @param[in] p_addr The GAP address to be set.
+ *
+ * @retval NRF_SUCCESS If the identity address was set successfully.
+ * @retval NRF_ERROR_NULL If @p p_addr is NULL.
+ * @retval NRF_ERROR_INVALID_ADDR If the @p p_addr pointer is invalid.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If the BLE address is invalid.
+ * @retval NRF_ERROR_BUSY If the SoftDevice was busy. Process SoftDevice events
+ * and retry.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized or if this function
+ * was called while advertising, scanning, or while connected.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_id_addr_set(ble_gap_addr_t const * p_addr);
+
+
+/**@brief Function for retrieving the local <em>Bluetooth</em> identity address.
+ *
+ * This function always returns the identity address, irrespective of the privacy settings.
+ * This means that the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC.
+ *
+ * @param[out] p_addr Pointer to the address structure to be filled in.
+ *
+ * @retval NRF_SUCCESS If the address was retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_addr is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_id_addr_get(ble_gap_addr_t * p_addr);
+
+
+/**@brief Function for configuring privacy settings.
+ *
+ * The privacy settings cannot be configured while advertising, scanning, or while in a connection.
+ *
+ * @note The SoftDevice functions @ref sd_ble_gap_addr_set
+ * and @ref sd_ble_gap_privacy_set must not be called when using the Peer Manager.
+ * Use this function instead.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS If the privacy settings were configured successfully.
+ * @retval NRF_ERROR_NULL If @p p_privacy_params is NULL.
+ * @retval NRF_ERROR_BUSY If the operation could not be performed at this time.
+ * Process SoftDevice events and retry.
+ * @retval NRF_ERROR_INVALID_PARAM If the address type is invalid.
+ * @retval NRF_ERROR_INVALID_STATE If this function is called while BLE roles using
+ * privacy are enabled.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_privacy_set(pm_privacy_params_t const * p_privacy_params);
+
+
+/**@brief Function for retrieving privacy settings.
+ *
+ * The privacy settings that are returned include the current IRK as well.
+ *
+ * @param[out] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS If the privacy settings were retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_privacy_params or @p p_privacy_params->p_device_irk is
+ * NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_privacy_get(pm_privacy_params_t * p_privacy_params);
+
+
+/**@brief Function for resolving a resolvable address with an identity resolution key (IRK).
+ *
+ * @param[in] p_addr A private random resolvable address.
+ * @param[in] p_irk An identity resolution key (IRK).
+ *
+ * @retval true The IRK used matched the one used to create the address.
+ * @retval false The IRK used did not match the one used to create the address, or an argument was
+ * NULL or invalid.
+ */
+bool pm_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
+
+
+/**@brief Function for getting the connection handle of the connection with a bonded peer.
+ *
+ * @param[in] peer_id The peer ID of the bonded peer.
+ * @param[out] p_conn_handle Connection handle, or @ref BLE_ERROR_INVALID_CONN_HANDLE if the peer
+ * is not connected.
+ *
+ * @retval NRF_SUCCESS If the connection handle was retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_conn_handle was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_conn_handle_get(pm_peer_id_t peer_id, uint16_t * p_conn_handle);
+
+
+/**@brief Function for retrieving the ID of a peer, given its connection handle.
+ *
+ * @param[in] conn_handle The connection handle of the peer.
+ * @param[out] p_peer_id The peer ID, or @ref PM_PEER_ID_INVALID if the peer is not bonded or
+ * @p conn_handle does not refer to a valid connection.
+ *
+ * @retval NRF_SUCCESS If the peer ID was retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_peer_id was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_id_get(uint16_t conn_handle, pm_peer_id_t * p_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs.
+ *
+ * @details This function can be used to loop through all used peer IDs. The order in which
+ * peer IDs are returned should be considered unpredictable. @ref PM_PEER_ID_INVALID
+ * is considered to be before the first and after the last used peer ID.
+ *
+ * @details To loop through all peer IDs exactly once, use the following constuct:
+ * @code{c}
+ * pm_peer_id_t current_peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
+ * while (current_peer_id != PM_PEER_ID_INVALID)
+ * {
+ * // Do something with current_peer_id.
+ * current_peer_id = pm_next_peer_id_get(current_peer_id)
+ * }
+ * @endcode
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID. If @p prev_peer_id was @ref PM_PEER_ID_INVALID, the
+ * next peer ID is the first used peer ID. If @p prev_peer_id was the last
+ * used peer ID, the function returns @ref PM_PEER_ID_INVALID.
+ */
+pm_peer_id_t pm_next_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for querying the number of valid peer IDs that are available.
+ *
+ * @details This function returns the number of peers for which there is data in persistent storage.
+ *
+ * @return The number of valid peer IDs.
+ */
+uint32_t pm_peer_count(void);
+
+
+
+
+/**@anchor PM_PEER_DATA_FUNCTIONS
+ * @name Functions (Peer Data)
+ * Functions for manipulating peer data.
+ * @{
+ */
+
+/**
+ * @{
+ */
+
+/**@brief Function for retrieving stored data of a peer.
+ *
+ * @note The length of the provided buffer must be a multiple of 4.
+ *
+ * @param[in] peer_id Peer ID to get data for.
+ * @param[in] data_id Which type of data to read.
+ * @param[out] p_data Where to put the retrieved data. The documentation for
+ * @ref pm_peer_data_id_t specifies what data type each data ID is stored as.
+ * @param[inout] p_len In: The length in bytes of @p p_data.
+ * Out: The length in bytes of the read data, if the read was successful.
+ *
+ * @retval NRF_SUCCESS If the data was read successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If the the data type or the peer ID was invalid or unallocated,
+ * or if the length in @p p_length was not a multiple of 4.
+ * @retval NRF_ERROR_NULL If a pointer parameter was NULL.
+ * @retval NRF_ERROR_NOT_FOUND If no stored data was found for this peer ID/data ID combination.
+ * @retval NRF_ERROR_DATA_SIZE If the provided buffer was not large enough.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void * p_data,
+ uint16_t * p_len);
+
+/**@brief Function for reading a peer's bonding data (@ref PM_PEER_DATA_ID_BONDING).
+ * @details See @ref pm_peer_data_load for parameters and return values. */
+ret_code_t pm_peer_data_bonding_load(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t * p_data);
+
+/**@brief Function for reading a peer's remote DB values. (@ref PM_PEER_DATA_ID_GATT_REMOTE).
+ * @details See @ref pm_peer_data_load for parameters and return values. */
+ret_code_t pm_peer_data_remote_db_load(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t * p_data,
+ uint16_t * p_len);
+
+/**@brief Function for reading a peer's application data. (@ref PM_PEER_DATA_ID_APPLICATION).
+ * @details See @ref pm_peer_data_load for parameters and return values. */
+ret_code_t pm_peer_data_app_data_load(pm_peer_id_t peer_id,
+ void * p_data,
+ uint16_t * p_len);
+/** @}*/
+
+
+/**
+ * @{
+ */
+
+/**@brief Function for setting or updating stored data of a peer.
+ *
+ * @note Writing the data to persistent storage happens asynchronously. Therefore, the buffer
+ * that contains the data must be kept alive until the operation has completed.
+ *
+ * @note The data written using this function might later be overwritten as a result of internal
+ * operations in the Peer Manager. A Peer Manager event is sent each time data is updated,
+ * regardless of whether the operation originated internally or from action by the user.
+ *
+ * @param[in] peer_id Peer ID to set data for.
+ * @param[in] data_id Which type of data to set.
+ * @param[in] p_data New value to set. The documentation for @ref pm_peer_data_id_t specifies
+ * what data type each data ID should be stored as.
+ * @param[in] len The length in bytes of @p p_data.
+ * @param[out] p_token A token that identifies this particular store operation. The token can be
+ * used to identify events that pertain to this operation. This parameter can
+ * be NULL.
+ *
+ * @retval NRF_SUCCESS If the data is scheduled to be written to persistent storage.
+ * @retval NRF_ERROR_NULL If @p p_data is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If no peer was found for the peer ID.
+ * @retval NRF_ERROR_BUSY If the underlying flash handler is busy with other flash
+ * operations. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_FORBIDDEN If data ID is @ref PM_PEER_DATA_ID_BONDING and the new bonding
+ * data also corresponds to another bonded peer. No data is written
+ * so duplicate entries are avoided.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void const * p_data,
+ uint16_t len,
+ pm_store_token_t * p_token);
+
+/**@brief Function for setting or updating a peer's bonding data (@ref PM_PEER_DATA_ID_BONDING).
+ * @details See @ref pm_peer_data_store for parameters and return values. */
+ret_code_t pm_peer_data_bonding_store(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t const * p_data,
+ pm_store_token_t * p_token);
+
+/**@brief Function for setting or updating a peer's remote DB values. (@ref PM_PEER_DATA_ID_GATT_REMOTE).
+ * @details See @ref pm_peer_data_store for parameters and return values. */
+ret_code_t pm_peer_data_remote_db_store(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t const * p_data,
+ uint16_t len,
+ pm_store_token_t * p_token);
+
+/**@brief Function for setting or updating a peer's application data. (@ref PM_PEER_DATA_ID_APPLICATION).
+ * @details See @ref pm_peer_data_store for parameters and return values. */
+ret_code_t pm_peer_data_app_data_store(pm_peer_id_t peer_id,
+ void const * p_data,
+ uint16_t len,
+ pm_store_token_t * p_token);
+/** @}*/
+
+
+/**
+ * @{
+ */
+
+/**@brief Function for deleting a peer's stored pieces of data.
+ *
+ * @details This function deletes specific data that is stored for a peer. Note that bonding data
+ * cannot be cleared separately.
+ *
+ * To delete all data for a peer (including bonding data), use @ref pm_peer_delete.
+ *
+ * @note Clearing data in persistent storage happens asynchronously.
+ *
+ * @param[in] peer_id Peer ID to clear data for.
+ * @param[in] data_id Which data to clear.
+ *
+ * @retval NRF_SUCCESS If the clear procedure was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p data_id was PM_PEER_DATA_ID_BONDING or invalid, or
+ * @p peer_id was invalid.
+ * @retval NRF_ERROR_NOT_FOUND If there was no data to clear for this peer ID/data ID combination.
+ * @retval NRF_ERROR_BUSY If the underlying flash handler is busy with other flash
+ * operations. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for manually adding a peer to the persistent storage.
+ *
+ * @details This function allocates a new peer ID and stores bonding data for the new peer. The
+ * bonding data is necessary to prevent ambiguity/inconsistency in peer data.
+ *
+ * @param[in] p_bonding_data The bonding data of the new peer (must contain a public/static
+ * address or a non-zero IRK).
+ * @param[out] p_new_peer_id Peer ID for the new peer, or an existing peer if a match was found.
+ * @param[out] p_token A token that identifies this particular store operation (storing the
+ * bonding data). The token can be used to identify events that pertain
+ * to this operation. This parameter can be NULL.
+ *
+ * @retval NRF_SUCCESS If the store operation for bonding data was initiated successfully.
+ * @retval NRF_ERROR_NULL If @p p_bonding_data or @p p_new_peer_id is NULL.
+ * @retval NRF_ERROR_STORAGE_FULL If there is no more space in persistent storage.
+ * @retval NRF_ERROR_NO_MEM If there are no more available peer IDs.
+ * @retval NRF_ERROR_BUSY If the underlying flash filesystem is busy with other flash
+ * operations. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_peer_new(pm_peer_id_t * p_new_peer_id,
+ pm_peer_data_bonding_t * p_bonding_data,
+ pm_store_token_t * p_token);
+
+
+/**@brief Function for freeing persistent storage for a peer.
+ *
+ * @details This function deletes every piece of data that is associated with the specified peer and
+ * frees the peer ID to be used for another peer. The deletion happens asynchronously, and
+ * the peer ID is not freed until the data is deleted. When the operation finishes, a @ref
+ * PM_EVT_PEER_DELETE_SUCCEEDED or @ref PM_EVT_PEER_DELETE_FAILED event is sent.
+ *
+ * @warning Use this function only when not connected to or connectable for the peer that is being
+ * deleted. If the peer is or becomes connected or data is manually written in flash during
+ * this procedure (until the success or failure event happens), the behavior is undefined.
+ *
+ * @param[in] peer_id Peer ID to be freed and have all associated data deleted.
+ *
+ * @retval NRF_SUCCESS If the operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If the peer ID was not valid.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_delete(pm_peer_id_t peer_id);
+
+
+/**@brief Function for deleting all data stored for all peers.
+ *
+ * @details This function sends either a @ref PM_EVT_PEERS_DELETE_SUCCEEDED or a @ref
+ * PM_EVT_PEERS_DELETE_FAILED event. In addition, a @ref PM_EVT_PEER_DELETE_SUCCEEDED or
+ * @ref PM_EVT_PEER_DELETE_FAILED event is sent for each deleted peer.
+ *
+ * @note When there is no peer data in flash the @ref PM_EVT_PEER_DELETE_SUCCEEDED event is sent synchronously.
+ *
+ * @warning Use this function only when not connected or connectable. If a peer is or becomes
+ * connected or a @ref PM_PEER_DATA_FUNCTIONS function is used during this procedure (until
+ * the success or failure event happens), the behavior is undefined.
+ *
+ * @retval NRF_SUCCESS If the deletion process was initiated successfully.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_peers_delete(void);
+/** @}*/
+
+
+/**
+ * @{
+ */
+
+
+/**@brief Function for finding the highest and lowest ranked peers.
+ *
+ * @details The rank is saved in persistent storage under the data ID @ref PM_PEER_DATA_ID_PEER_RANK.
+ *
+ * @details The interpretation of rank is up to the user, because the rank is only updated by
+ * calling @ref pm_peer_rank_highest or by manipulating the value using a @ref
+ * PM_PEER_DATA_FUNCTIONS function.
+ *
+ * @note Any argument that is NULL is ignored.
+ *
+ * @param[out] p_highest_ranked_peer The peer ID with the highest rank of all peers, for example,
+ * the most recently used peer.
+ * @param[out] p_highest_rank The highest rank.
+ * @param[out] p_lowest_ranked_peer The peer ID with the lowest rank of all peers, for example,
+ * the least recently used peer.
+ * @param[out] p_lowest_rank The lowest rank.
+ *
+ * @retval NRF_SUCCESS If the operation completed successfully.
+ * @retval NRF_ERROR_NOT_FOUND If no peers were found.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ * @retval NRF_ERROR_NOT_SUPPORTED If peer rank functionality has been disabled via the @ref
+ * PM_PEER_RANKS_ENABLED configuration option.
+ */
+ret_code_t pm_peer_ranks_get(pm_peer_id_t * p_highest_ranked_peer,
+ uint32_t * p_highest_rank,
+ pm_peer_id_t * p_lowest_ranked_peer,
+ uint32_t * p_lowest_rank);
+
+
+/**@brief Function for updating the rank of a peer to be highest among all stored peers.
+ *
+ * @details If this function returns @ref NRF_SUCCESS, either a @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or a
+ * @ref PM_EVT_PEER_DATA_UPDATE_FAILED event is sent with a @ref
+ * PM_STORE_TOKEN_INVALID store token when the operation is complete. Until the operation
+ * is complete, this function returns @ref NRF_ERROR_BUSY.
+ *
+ * When the operation is complete, the peer is the highest ranked peer as reported by
+ * @ref pm_peer_ranks_get.
+ *
+ * @note The @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event can arrive before the function returns if the peer
+ * is already ranked highest. In this case, the @ref pm_peer_data_update_succeeded_evt_t::flash_changed flag
+ * in the event will be false.
+ *
+ * @param[in] peer_id The peer to rank highest.
+ *
+ * @retval NRF_SUCCESS If the peer's rank is, or will be updated to be highest.
+ * @retval NRF_ERROR_BUSY If the underlying flash handler is busy with other flash
+ * operations, or if a previous call to this function has not
+ * completed. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_RESOURCES If the highest rank is UINT32_MAX, so the new rank would wrap
+ * around to 0. To fix this, manually update all ranks to smaller
+ * values, while still keeping their order.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ * @retval NRF_ERROR_NOT_SUPPORTED If peer rank functionality has been disabled via the @ref
+ * PM_PEER_RANKS_ENABLED configuration option.
+ */
+ret_code_t pm_peer_rank_highest(pm_peer_id_t peer_id);
+
+/** @}*/
+
+/** @} */
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PEER_MANAGER_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h
new file mode 100644
index 0000000..59bb811
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_MANAGER_INTERNAL_H__
+#define PEER_MANAGER_INTERNAL_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @file peer_manager_types.h
+ *
+ * @addtogroup peer_manager
+ * @brief File containing definitions used solely inside the Peer Manager's modules.
+ * @{
+ */
+
+ANON_UNIONS_ENABLE;
+
+/**@brief One piece of data associated with a peer, together with its type.
+ *
+ * @note This type is deprecated.
+ */
+typedef struct
+{
+ uint16_t length_words; /**< @brief The length of the data in words. */
+ pm_peer_data_id_t data_id; /**< @brief ID that specifies the type of data (defines which member of the union is used). */
+ union
+ {
+ pm_peer_data_bonding_t * p_bonding_data; /**< @brief The exchanged bond information in addition to metadata of the bonding. */
+ uint32_t * p_peer_rank; /**< @brief A value locally assigned to this peer. Its interpretation is up to the user. The rank is not set automatically by the Peer Manager, but it is assigned by the user using either @ref pm_peer_rank_highest or a @ref PM_PEER_DATA_FUNCTIONS function. */
+ bool * p_service_changed_pending; /**< @brief Whether a service changed indication should be sent to the peer. */
+ pm_peer_data_local_gatt_db_t * p_local_gatt_db; /**< @brief Persistent information pertaining to a peer GATT client. */
+ ble_gatt_db_srv_t * p_remote_gatt_db; /**< @brief Persistent information pertaining to a peer GATT server. */
+ uint8_t * p_application_data; /**< @brief Arbitrary data to associate with the peer. This data can be freely used by the application. */
+ void * p_all_data; /**< @brief Generic access pointer to the data. It is used only to handle the data without regard to type. */
+ }; /**< @brief The data. */
+} pm_peer_data_t;
+
+
+/**@brief Immutable version of @ref pm_peer_data_t.
+ *
+ * @note This type is deprecated.
+ */
+typedef struct
+{
+ uint16_t length_words; /**< @brief The length of the data in words. */
+ pm_peer_data_id_t data_id; /**< @brief ID that specifies the type of data (defines which member of the union is used). */
+ union
+ {
+ pm_peer_data_bonding_t const * p_bonding_data; /**< @brief Immutable @ref pm_peer_data_t::p_bonding_data. */
+ uint32_t const * p_peer_rank; /**< @brief Immutable @ref pm_peer_data_t::p_peer_rank. */
+ bool const * p_service_changed_pending; /**< @brief Immutable @ref pm_peer_data_t::p_service_changed_pending. */
+ pm_peer_data_local_gatt_db_t const * p_local_gatt_db; /**< @brief Immutable @ref pm_peer_data_t::p_local_gatt_db. */
+ ble_gatt_db_srv_t const * p_remote_gatt_db; /**< @brief Immutable @ref pm_peer_data_t::p_remote_gatt_db. */
+ uint8_t const * p_application_data; /**< @brief Immutable @ref pm_peer_data_t::p_application_data. */
+ void const * p_all_data; /**< @brief Immutable @ref pm_peer_data_t::p_all_data. */
+ }; /**< @brief The data. */
+} pm_peer_data_const_t;
+
+ANON_UNIONS_DISABLE;
+
+
+/**@brief Version of @ref pm_peer_data_t that reflects the structure of peer data in flash.
+ *
+ * @note This type is deprecated.
+ */
+typedef pm_peer_data_const_t pm_peer_data_flash_t;
+
+
+/**@brief Event handler for events from the @ref peer_manager module.
+ *
+ * @sa pm_register
+ *
+ * @param[in] p_event The event that has occurred.
+ */
+typedef void (*pm_evt_handler_internal_t)(pm_evt_t * p_event);
+
+
+/**@brief Macro for calculating the flash size of bonding data.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_BONDING_DATA_N_WORDS() BYTES_TO_WORDS(sizeof(pm_peer_data_bonding_t))
+
+
+/**@brief Macro for calculating the flash size of service changed pending state.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_SC_STATE_N_WORDS() BYTES_TO_WORDS(sizeof(bool))
+
+
+/**@brief Macro for calculating the flash size of local GATT database data.
+ *
+ * @param[in] local_db_len The length, in bytes, of the database as reported by the SoftDevice.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_LOCAL_DB_N_WORDS(local_db_len) \
+ BYTES_TO_WORDS((local_db_len) + PM_LOCAL_DB_LEN_OVERHEAD_BYTES)
+
+
+/**@brief Macro for calculating the length of a local GATT database attribute array.
+ *
+ * @param[in] n_words The number of words that the data takes in flash.
+ *
+ * @return The length of the database attribute array.
+ */
+#define PM_LOCAL_DB_LEN(n_words) (((n_words) * BYTES_PER_WORD) - PM_LOCAL_DB_LEN_OVERHEAD_BYTES)
+
+
+/**@brief Macro for calculating the flash size of remote GATT database data.
+ *
+ * @param[in] service_count The number of services in the service array.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_REMOTE_DB_N_WORDS(service_count) BYTES_TO_WORDS(sizeof(ble_gatt_db_srv_t) * (service_count))
+
+
+/**@brief Macro for calculating the flash size of remote GATT database data.
+ *
+ * @param[in] n_words The length in number of words.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_REMOTE_DB_N_SERVICES(n_words) (((n_words) * BYTES_PER_WORD) / sizeof(ble_gatt_db_srv_t))
+
+
+/**@brief Function for calculating the flash size of the usage index.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_USAGE_INDEX_N_WORDS() BYTES_TO_WORDS(sizeof(uint32_t))
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef NRF_PM_DEBUG
+
+ #define NRF_PM_DEBUG_CHECK(condition) \
+ if (!(condition)) \
+ { \
+ __asm("bkpt #0"); \
+ }
+
+#else
+
+ // Prevent "variable set but never used" compiler warnings.
+ #define NRF_PM_DEBUG_CHECK(condition) (void)(condition)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_MANAGER_INTERNAL_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h
new file mode 100644
index 0000000..34fd328
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h
@@ -0,0 +1,354 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file peer_manager_types.h
+ *
+ * @addtogroup peer_manager
+ * @{
+ */
+
+#ifndef PEER_MANAGER_TYPES_H__
+#define PEER_MANAGER_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "nrf.h"
+#include "ble_gap.h"
+#include "ble_hci.h"
+#include "ble_gatt_db.h"
+#include "app_util.h"
+#include "app_util_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Handle to uniquely identify a peer for which we have persistently stored data.
+ */
+typedef uint16_t pm_peer_id_t;
+
+/**@brief Type that is used for write prepares (used to reserve space in flash).
+ */
+typedef uint32_t pm_prepare_token_t;
+
+/**@brief Type that is used to hold a reference to a stored item in flash.
+ */
+typedef uint32_t pm_store_token_t;
+
+/**@brief Errors from security procedures in Peer Manager.
+ *
+ * @details Possible values are defined in @ref PM_SEC_ERRORS and @ref BLE_GAP_SEC_STATUS.
+ */
+typedef uint16_t pm_sec_error_code_t;
+
+
+//lint -emacro(516,PM_LOCAL_DB_LEN_OVERHEAD_BYTES)
+
+#define PM_PEER_ID_INVALID 0xFFFF /**< @brief Invalid value for @ref pm_peer_id_t. */
+#define PM_STORE_TOKEN_INVALID 0 /**< @brief Invalid value for store token. */
+#define PM_PEER_ID_N_AVAILABLE_IDS 256 /**< @brief The number of available peer IDs. */
+#define PM_LOCAL_DB_LEN_OVERHEAD_BYTES offsetof(pm_peer_data_local_gatt_db_t, data) /**< @brief The static-length part of the local GATT data struct. */
+
+
+#define PM_CONN_SEC_ERROR_BASE 0x1000 /**< @brief The base for Peer Manager defined errors. See @ref PM_SEC_ERRORS and @ref pm_sec_error_code_t. */
+
+
+/**@defgroup PM_SEC_ERRORS Peer Manager defined security errors
+ *
+ * @details The first 256 numbers in this range correspond to the status codes in
+ * @ref BLE_HCI_STATUS_CODES.
+ * @{ */
+#define PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING (PM_CONN_SEC_ERROR_BASE + 0x06) /**< @brief Encryption failed because the peripheral has lost the LTK for this bond. See also @ref BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING and Table 3.7 ("Pairing Failed Reason Codes") in the Bluetooth Core Specification 4.2, section 3.H.3.5.5 (@linkBLEcore). */
+#define PM_CONN_SEC_ERROR_MIC_FAILURE (PM_CONN_SEC_ERROR_BASE + 0x3D) /**< @brief Encryption ended with disconnection because of mismatching keys or a stray packet during a procedure. See the SoftDevice GAP Message Sequence Charts on encryption (@linkBLEMSCgap), the Bluetooth Core Specification 4.2, sections 6.B.5.1.3.1 and 3.H.3.5.5 (@linkBLEcore), and @ref BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE. */
+#define PM_CONN_SEC_ERROR_DISCONNECT (PM_CONN_SEC_ERROR_BASE + 0x100) /**< @brief Pairing or encryption did not finish before the link disconnected for an unrelated reason. */
+#define PM_CONN_SEC_ERROR_SMP_TIMEOUT (PM_CONN_SEC_ERROR_BASE + 0x101) /**< @brief Pairing/bonding could not start because an SMP time-out has already happened on this link. This means that no more pairing or bonding can happen on this link. To be able to pair or bond, the link must be disconnected and then reconnected. See Bluetooth Core Specification 4.2 section 3.H.3.4 (@linkBLEcore). */
+ /** @} */
+
+
+
+/**@defgroup PM_PEER_ID_VERSIONS All versions of Peer IDs.
+ * @brief The data ID for each iteration of the data formats in flash.
+ * @details Each time the format (in flash) of a piece of peer data changes, the data ID will also
+ * be updated. This list of defines is a record of each data ID that has ever existed, and
+ * code that caters to legacy formats can find the relevant IDs here.
+ * @{ */
+#define PM_PEER_DATA_ID_FIRST_VX 0 /**< @brief The smallest data ID. */
+#define PM_PEER_DATA_ID_BONDING_V1 0 /**< @brief The data ID of the first version of bonding data. */
+#define PM_PEER_DATA_ID_BONDING_V2 7 /**< @brief The data ID of the second version of bonding data. */
+#define PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING_V1 1 /**< @brief The data ID of the first version of the service changed pending flag. */
+#define PM_PEER_DATA_ID_GATT_LOCAL_V1 2 /**< @brief The data ID of the first version of local GATT data. */
+#define PM_PEER_DATA_ID_GATT_LOCAL_V2 8 /**< @brief The data ID of the second version of local GATT data. */
+#define PM_PEER_DATA_ID_GATT_REMOTE_V1 3 /**< @brief The data ID of the first version of remote GATT data. */
+#define PM_PEER_DATA_ID_APPLICATION_V1 4 /**< @brief The data ID of the first version of application data. */
+#define PM_PEER_DATA_ID_GATT_REMOTE_V2 5 /**< @brief The data ID of the second version of remote GATT data. */
+#define PM_PEER_DATA_ID_PEER_RANK_V1 6 /**< @brief The data ID of the first version of the rank. */
+#define PM_PEER_DATA_ID_LAST_VX 9 /**< @brief The data ID after the last valid one. */
+#define PM_PEER_DATA_ID_INVALID_VX 0xFF /**< @brief A data ID guaranteed to be invalid. */
+/**@}*/
+
+
+/**@brief The different types of data associated with a peer.
+ */
+typedef enum
+{
+ PM_PEER_DATA_ID_FIRST = PM_PEER_DATA_ID_FIRST_VX, /**< @brief The smallest data ID. */
+ PM_PEER_DATA_ID_BONDING = PM_PEER_DATA_ID_BONDING_V2, /**< @brief The data ID for bonding data. Type: @ref pm_peer_data_bonding_t. */
+ PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING_V1, /**< @brief The data ID for service changed state. Type: bool. */
+ PM_PEER_DATA_ID_GATT_LOCAL = PM_PEER_DATA_ID_GATT_LOCAL_V2, /**< @brief The data ID for local GATT data (sys attributes). Type: @ref pm_peer_data_local_gatt_db_t. */
+ PM_PEER_DATA_ID_GATT_REMOTE = PM_PEER_DATA_ID_GATT_REMOTE_V2, /**< @brief The data ID for remote GATT data. Type: uint8_t array. */
+ PM_PEER_DATA_ID_PEER_RANK = PM_PEER_DATA_ID_PEER_RANK_V1, /**< @brief The data ID for peer rank. See @ref pm_peer_rank_highest. Type: uint32_t. */
+ PM_PEER_DATA_ID_APPLICATION = PM_PEER_DATA_ID_APPLICATION_V1, /**< @brief The data ID for application data. Type: uint8_t array. */
+ PM_PEER_DATA_ID_LAST = PM_PEER_DATA_ID_LAST_VX, /**< @brief One more than the highest data ID. */
+ PM_PEER_DATA_ID_INVALID = PM_PEER_DATA_ID_INVALID_VX, /**< @brief A data ID guaranteed to be invalid. */
+} pm_peer_data_id_t;
+
+
+/**@brief Different procedures that can lead to an encrypted link.
+ */
+typedef enum
+{
+ PM_CONN_SEC_PROCEDURE_ENCRYPTION, /**< @brief Using an LTK that was shared during a previous bonding procedure to encrypt the link. */
+ PM_CONN_SEC_PROCEDURE_BONDING, /**< @brief A pairing procedure, followed by a bonding procedure. */
+ PM_CONN_SEC_PROCEDURE_PAIRING, /**< @brief A pairing procedure with no bonding. */
+} pm_conn_sec_procedure_t;
+
+
+/**@brief Configuration of a security procedure.
+ */
+typedef struct
+{
+ bool allow_repairing; /** @brief Whether to allow the peer to pair if it wants to, but is already bonded. If this is false, the procedure is rejected, and no more events are sent. Default: false. */
+} pm_conn_sec_config_t;
+
+
+/**@brief Data associated with a bond to a peer.
+ */
+typedef struct
+{
+ uint8_t own_role; /**< @brief The BLE role of the local device during bonding. See @ref BLE_GAP_ROLES. */
+ ble_gap_id_key_t peer_ble_id; /**< @brief The peer's Bluetooth address and identity resolution key (IRK). */
+ ble_gap_enc_key_t peer_ltk; /**< @brief The peer's long-term encryption key (LTK) and master ID. */
+ ble_gap_enc_key_t own_ltk; /**< @brief Locally generated long-term encryption key (LTK) and master ID, distributed to the peer. */
+} pm_peer_data_bonding_t;
+
+
+/**@brief Data on a local GATT database.
+ */
+typedef struct
+{
+ uint32_t flags; /**< @brief Flags that describe the database attributes. */
+ uint16_t len; /**< @brief Size of the attribute array. */
+ uint8_t data[1]; /**< @brief Array to hold the database attributes. */
+} pm_peer_data_local_gatt_db_t;
+
+
+/**@brief Device Privacy.
+ *
+ * The privacy feature provides a way for the device to avoid being tracked over a period of
+ * time. The privacy feature, when enabled, hides the local device identity and replaces it
+ * with a private address that is automatically refreshed at a specified interval.
+ *
+ * If a device still wants to be recognized by other peers, it needs to share it's Identity
+ * Resolving Key (IRK). With this key, a device can generate a random private address that
+ * can only be recognized by peers in possession of that key, and devices can establish
+ * connections without revealing their real identities.
+ *
+ * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all
+ * bonding procedures performed after @ref sd_ble_gap_privacy_set returns.
+ * The IRK distributed during bonding procedure is the device IRK that is active when @ref
+ * sd_ble_gap_sec_params_reply is called.
+ */
+typedef ble_gap_privacy_params_t pm_privacy_params_t;
+
+
+/**@brief Types of events that can come from the @ref peer_manager module.
+ */
+typedef enum
+{
+ PM_EVT_BONDED_PEER_CONNECTED, /**< @brief A connected peer has been identified as one with which we have a bond. When performing bonding with a peer for the first time, this event will not be sent until a new connection is established with the peer. When we are central, this event is always sent when the Peer Manager receives the @ref BLE_GAP_EVT_CONNECTED event. When we are peripheral, this event might in rare cases arrive later. */
+ PM_EVT_CONN_SEC_START, /**< @brief A security procedure has started on a link, initiated either locally or remotely. The security procedure is using the last parameters provided via @ref pm_sec_params_set. This event is always followed by either a @ref PM_EVT_CONN_SEC_SUCCEEDED or a @ref PM_EVT_CONN_SEC_FAILED event. This is an informational event; no action is needed for the procedure to proceed. */
+ PM_EVT_CONN_SEC_SUCCEEDED, /**< @brief A link has been encrypted, either as a result of a call to @ref pm_conn_secure or a result of an action by the peer. The event structure contains more information about the circumstances. This event might contain a peer ID with the value @ref PM_PEER_ID_INVALID, which means that the peer (central) used an address that could not be identified, but it used an encryption key (LTK) that is present in the database. */
+ PM_EVT_CONN_SEC_FAILED, /**< @brief A pairing or encryption procedure has failed. In some cases, this means that security is not possible on this link (temporarily or permanently). How to handle this error depends on the application. */
+ PM_EVT_CONN_SEC_CONFIG_REQ, /**< @brief The peer (central) has requested pairing, but a bond already exists with that peer. Reply by calling @ref pm_conn_sec_config_reply before the event handler returns. If no reply is sent, a default is used. */
+ PM_EVT_CONN_SEC_PARAMS_REQ, /**< @brief Security parameters (@ref ble_gap_sec_params_t) are needed for an ongoing security procedure. Reply with @ref pm_conn_sec_params_reply before the event handler returns. If no reply is sent, the parameters given in @ref pm_sec_params_set are used. If a peripheral connection, the central's sec_params will be available in the event. */
+ PM_EVT_STORAGE_FULL, /**< @brief There is no more room for peer data in flash storage. To solve this problem, delete data that is not needed anymore and run a garbage collection procedure in FDS. */
+ PM_EVT_ERROR_UNEXPECTED, /**< @brief An unrecoverable error happened inside Peer Manager. An operation failed with the provided error. */
+ PM_EVT_PEER_DATA_UPDATE_SUCCEEDED, /**< @brief A piece of peer data was stored, updated, or cleared in flash storage. This event is sent for all successful changes to peer data, also those initiated internally in Peer Manager. To identify an operation, compare the store token in the event with the store token received during the initiating function call. Events from internally initiated changes might have invalid store tokens. */
+ PM_EVT_PEER_DATA_UPDATE_FAILED, /**< @brief A piece of peer data could not be stored, updated, or cleared in flash storage. This event is sent instead of @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED for the failed operation. */
+ PM_EVT_PEER_DELETE_SUCCEEDED, /**< @brief A peer was cleared from flash storage, for example because a call to @ref pm_peer_delete succeeded. This event can also be sent as part of a call to @ref pm_peers_delete or internal cleanup. */
+ PM_EVT_PEER_DELETE_FAILED, /**< @brief A peer could not be cleared from flash storage. This event is sent instead of @ref PM_EVT_PEER_DELETE_SUCCEEDED for the failed operation. */
+ PM_EVT_PEERS_DELETE_SUCCEEDED, /**< @brief A call to @ref pm_peers_delete has completed successfully. Flash storage now contains no peer data. */
+ PM_EVT_PEERS_DELETE_FAILED, /**< @brief A call to @ref pm_peers_delete has failed, which means that at least one of the peers could not be deleted. Other peers might have been deleted, or might still be queued to be deleted. No more @ref PM_EVT_PEERS_DELETE_SUCCEEDED or @ref PM_EVT_PEERS_DELETE_FAILED events are sent until the next time @ref pm_peers_delete is called. */
+ PM_EVT_LOCAL_DB_CACHE_APPLIED, /**< @brief Local database values for a peer (taken from flash storage) have been provided to the SoftDevice. */
+ PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED, /**< @brief Local database values for a peer (taken from flash storage) were rejected by the SoftDevice, which means that either the database has changed or the user has manually set the local database to an invalid value (using @ref pm_peer_data_store). */
+ PM_EVT_SERVICE_CHANGED_IND_SENT, /**< @brief A service changed indication has been sent to a peer, as a result of a call to @ref pm_local_database_has_changed. This event will be followed by a @ref PM_EVT_SERVICE_CHANGED_IND_CONFIRMED event if the peer acknowledges the indication. */
+ PM_EVT_SERVICE_CHANGED_IND_CONFIRMED, /**< @brief A service changed indication that was sent has been confirmed by a peer. The peer can now be considered aware that the local database has changed. */
+ PM_EVT_SLAVE_SECURITY_REQ, /**< @brief The peer (peripheral) has requested link encryption, which has been enabled. */
+ PM_EVT_FLASH_GARBAGE_COLLECTED, /**< @brief The flash has been garbage collected (By FDS), possibly freeing up space. */
+} pm_evt_id_t;
+
+
+/**@brief Events parameters specific to the @ref PM_EVT_CONN_SEC_START event.
+ */
+typedef struct
+{
+ pm_conn_sec_procedure_t procedure; /**< @brief The procedure that has started. */
+} pm_conn_sec_start_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_CONN_SEC_SUCCEEDED event.
+ */
+typedef struct
+{
+ pm_conn_sec_procedure_t procedure; /**< @brief The procedure that led to securing the link. */
+ bool data_stored; /**< @brief Whether bonding data was successfully requested to be stored. This is false if: No bonding happened, or an internal error occurred when trying to store the data, or if the data was rejected via @ref pm_conn_sec_config_reply. */
+} pm_conn_secured_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_CONN_SEC_FAILED event.
+ */
+typedef struct
+{
+ pm_conn_sec_procedure_t procedure; /**< @brief The procedure that failed. */
+ pm_sec_error_code_t error; /**< @brief An error code that describes the failure. */
+ uint8_t error_src; /**< @brief The party that raised the error, see @ref BLE_GAP_SEC_STATUS_SOURCES. */
+} pm_conn_secure_failed_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_CONN_SEC_PARAMS_REQ event.
+ */
+typedef struct
+{
+ ble_gap_sec_params_t const * p_peer_params; /**< @brief Peer security parameters, if role is peripheral. Otherwise, this is NULL. */
+ void const * p_context; /**< @brief This pointer must be provided in the reply if the reply function takes a p_context argument. */
+} pm_conn_sec_params_req_evt_t;
+
+
+/**@brief Actions that can be performed to peer data in persistent storage.
+ */
+typedef enum
+{
+ PM_PEER_DATA_OP_UPDATE, /**< @brief Writing or overwriting the data. */
+ PM_PEER_DATA_OP_DELETE, /**< @brief Removing the data. */
+} pm_peer_data_op_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event.
+ */
+typedef struct
+{
+ pm_peer_data_id_t data_id; /**< @brief The type of the data that was changed. */
+ pm_peer_data_op_t action; /**< @brief What happened to the data. */
+ pm_store_token_t token; /**< @brief Token that identifies the operation. For @ref PM_PEER_DATA_OP_DELETE actions, this token can be disregarded. For @ref PM_PEER_DATA_OP_UPDATE actions, compare this token with the token that is received from a call to a @ref PM_PEER_DATA_FUNCTIONS function. */
+ uint8_t flash_changed : 1; /**< @brief If this is false, no operation was done in flash, because the value was already what it should be. Please note that in certain scenarios, this flag will be true even if the new value is the same as the old. */
+} pm_peer_data_update_succeeded_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_FAILED event.
+ */
+typedef struct
+{
+ pm_peer_data_id_t data_id; /**< @brief The type of the data that was supposed to be changed. */
+ pm_peer_data_op_t action; /**< @brief The action that failed. */
+ pm_store_token_t token; /**< @brief Token that identifies the operation. For @ref PM_PEER_DATA_OP_DELETE actions, this token can be disregarded. For @ref PM_PEER_DATA_OP_UPDATE actions, compare this token with the token that is received from a call to a @ref PM_PEER_DATA_FUNCTIONS function. */
+ ret_code_t error; /**< @brief An error code that describes the failure. */
+} pm_peer_data_update_failed_t;
+
+
+/**@brief Standard parameters for failure events.
+ */
+typedef struct
+{
+ ret_code_t error; /**< @brief The error that occurred. */
+} pm_failure_evt_t;
+
+
+/**@brief Events parameters specific to the @ref PM_EVT_SLAVE_SECURITY_REQ event.
+ */
+typedef struct
+{
+ bool bond; /**< @brief Whether the peripheral requested bonding. */
+ bool mitm; /**< @brief Whether the peripheral requested man-in-the-middle protection. */
+} pm_evt_slave_security_req_t;
+
+
+/**@brief An event from the @ref peer_manager module.
+ *
+ * @details The structure contains both standard parameters and parameters that are specific to some events.
+ */
+typedef struct
+{
+ pm_evt_id_t evt_id; /**< @brief The type of the event. */
+ uint16_t conn_handle; /**< @brief The connection that this event pertains to, or @ref BLE_CONN_HANDLE_INVALID. */
+ pm_peer_id_t peer_id; /**< @brief The bonded peer that this event pertains to, or @ref PM_PEER_ID_INVALID. */
+ union
+ {
+ pm_conn_sec_start_evt_t conn_sec_start; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_START event. */
+ pm_conn_secured_evt_t conn_sec_succeeded; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_SUCCEEDED event. */
+ pm_conn_secure_failed_evt_t conn_sec_failed; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_FAILED event. */
+ pm_conn_sec_params_req_evt_t conn_sec_params_req; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_PARAMS_REQ event. */
+ pm_peer_data_update_succeeded_evt_t peer_data_update_succeeded; /**< @brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event. */
+ pm_peer_data_update_failed_t peer_data_update_failed; /**< @brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_FAILED event. */
+ pm_failure_evt_t peer_delete_failed; /**< @brief Parameters specific to the @ref PM_EVT_PEER_DELETE_FAILED event. */
+ pm_failure_evt_t peers_delete_failed_evt; /**< @brief Parameters specific to the @ref PM_EVT_PEERS_DELETE_FAILED event. */
+ pm_failure_evt_t error_unexpected; /**< @brief Parameters specific to the @ref PM_EVT_ERROR_UNEXPECTED event. */
+ pm_evt_slave_security_req_t slave_security_req; /**< @brief Parameters specific to the @ref PM_EVT_SLAVE_SECURITY_REQ event. */
+ } params;
+} pm_evt_t;
+
+
+/**@brief Event handler for events from the @ref peer_manager module.
+ *
+ * @sa pm_register
+ *
+ * @param[in] p_event The event that has occurred.
+ */
+typedef void (*pm_evt_handler_t)(pm_evt_t const * p_event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_MANAGER_TYPES_H__ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c
new file mode 100644
index 0000000..4fdbb34
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "pm_buffer.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include "nrf_error.h"
+#include "pm_mutex.h"
+
+
+#define BUFFER_IS_VALID(p_buffer) ((p_buffer != NULL) \
+ && (p_buffer->p_memory != NULL) \
+ && (p_buffer->p_mutex != NULL))
+
+
+
+ret_code_t pm_buffer_init(pm_buffer_t * p_buffer,
+ uint8_t * p_buffer_memory,
+ uint32_t buffer_memory_size,
+ uint8_t * p_mutex_memory,
+ uint32_t mutex_memory_size,
+ uint32_t n_blocks,
+ uint32_t block_size)
+{
+ if ( (p_buffer != NULL)
+ && (p_buffer_memory != NULL)
+ && (p_mutex_memory != NULL)
+ && (buffer_memory_size >= (n_blocks * block_size))
+ && (mutex_memory_size >= MUTEX_STORAGE_SIZE(n_blocks))
+ && (n_blocks != 0)
+ && (block_size != 0))
+ {
+ p_buffer->p_memory = p_buffer_memory;
+ p_buffer->p_mutex = p_mutex_memory;
+ p_buffer->n_blocks = n_blocks;
+ p_buffer->block_size = block_size;
+ pm_mutex_init(p_buffer->p_mutex, n_blocks);
+
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+}
+
+
+uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks)
+{
+ if (!BUFFER_IS_VALID(p_buffer))
+ {
+ return ( PM_BUFFER_INVALID_ID );
+ }
+
+ uint8_t first_locked_mutex = PM_BUFFER_INVALID_ID;
+
+ for (uint8_t i = 0; i < p_buffer->n_blocks; i++)
+ {
+ if (pm_mutex_lock(p_buffer->p_mutex, i))
+ {
+ if (first_locked_mutex == PM_BUFFER_INVALID_ID)
+ {
+ first_locked_mutex = i;
+ }
+ if ((i - first_locked_mutex + 1) == n_blocks)
+ {
+ return first_locked_mutex;
+ }
+ }
+ else if (first_locked_mutex != PM_BUFFER_INVALID_ID)
+ {
+ for (uint8_t j = first_locked_mutex; j < i; j++)
+ {
+ pm_buffer_release(p_buffer, j);
+ }
+ first_locked_mutex = PM_BUFFER_INVALID_ID;
+ }
+ }
+
+ return ( PM_BUFFER_INVALID_ID );
+}
+
+
+uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id)
+{
+ if (!BUFFER_IS_VALID(p_buffer))
+ {
+ return ( NULL );
+ }
+
+ if ( (id != PM_BUFFER_INVALID_ID)
+ && pm_mutex_lock_status_get(p_buffer->p_mutex, id) )
+ {
+ return ( &p_buffer->p_memory[id * p_buffer->block_size] );
+ }
+ else
+ {
+ return ( NULL );
+ }
+}
+
+
+void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id)
+{
+ if ( BUFFER_IS_VALID(p_buffer)
+ && (id != PM_BUFFER_INVALID_ID)
+ && pm_mutex_lock_status_get(p_buffer->p_mutex, id))
+ {
+ pm_mutex_unlock(p_buffer->p_mutex, id);
+ }
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h
new file mode 100644
index 0000000..619af1d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef BUFFER_H__
+#define BUFFER_H__
+
+#include <stdint.h>
+#include "compiler_abstraction.h"
+#include "sdk_errors.h"
+#include "pm_mutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup pm_buffer Buffer
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module provides a simple buffer.
+ */
+
+
+#define PM_BUFFER_INVALID_ID 0xFF //!< Invalid buffer block ID.
+
+
+/**@brief Convenience macro for declaring memory and initializing a buffer instance.
+ *
+ * @param[out] p_buffer The buffer instance to initialize.
+ * @param[in] n_blocks The desired number of blocks in the buffer.
+ * @param[in] block_size The desired block size of the buffer.
+ * @param[out] err_code The return code from @ref pm_buffer_init.
+ */
+#define PM_BUFFER_INIT(p_buffer, n_blocks, block_size, err_code) \
+do \
+{ \
+ __ALIGN(4) static uint8_t buffer_memory[(n_blocks) * (block_size)]; \
+ static uint8_t mutex_memory[MUTEX_STORAGE_SIZE(n_blocks)]; \
+ err_code = pm_buffer_init((p_buffer), \
+ buffer_memory, \
+ (n_blocks) * (block_size), \
+ mutex_memory, \
+ MUTEX_STORAGE_SIZE(n_blocks), \
+ (n_blocks), \
+ (block_size)); \
+} while (0)
+
+
+typedef struct
+{
+ uint8_t * p_memory; /**< The storage for all buffer entries. The size of the buffer must be n_blocks*block_size. */
+ uint8_t * p_mutex; /**< A mutex group with one mutex for each buffer entry. */
+ uint32_t n_blocks; /**< The number of allocatable blocks in the buffer. */
+ uint32_t block_size; /**< The size of each block in the buffer. */
+} pm_buffer_t;
+
+/**@brief Function for initializing a buffer instance.
+ *
+ * @param[out] p_buffer The buffer instance to initialize.
+ * @param[in] p_buffer_memory The memory this buffer will use.
+ * @param[in] buffer_memory_size The size of p_buffer_memory. This must be at least
+ * n_blocks*block_size.
+ * @param[in] p_mutex_memory The memory for the mutexes. This must be at least
+ * @ref MUTEX_STORAGE_SIZE(n_blocks).
+ * @param[in] mutex_memory_size The size of p_mutex_memory.
+ * @param[in] n_blocks The number of blocks in the buffer.
+ * @param[in] block_size The size of each block.
+ *
+ * @retval NRF_SUCCESS Successfully initialized buffer instance.
+ * @retval NRF_ERROR_INVALID_PARAM A parameter was 0 or NULL or a size was too small.
+ */
+ret_code_t pm_buffer_init(pm_buffer_t * p_buffer,
+ uint8_t * p_buffer_memory,
+ uint32_t buffer_memory_size,
+ uint8_t * p_mutex_memory,
+ uint32_t mutex_memory_size,
+ uint32_t n_blocks,
+ uint32_t block_size);
+
+
+/**@brief Function for acquiring a buffer block in a buffer.
+ *
+ * @param[in] p_buffer The buffer instance acquire from.
+ * @param[in] n_blocks The number of contiguous blocks to acquire.
+ *
+ * @return The id of the acquired block, if successful.
+ * @retval PM_BUFFER_INVALID_ID If unsuccessful.
+ */
+uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks);
+
+
+/**@brief Function for getting a pointer to a specific buffer block.
+ *
+ * @param[in] p_buffer The buffer instance get from.
+ * @param[in] id The id of the buffer to get the pointer for.
+ *
+ * @return A pointer to the buffer for the specified id, if the id is valid.
+ * @retval NULL If the id is invalid.
+ */
+uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id);
+
+
+/**@brief Function for releasing a buffer block.
+ *
+ * @param[in] p_buffer The buffer instance containing the block to release.
+ * @param[in] id The id of the block to release.
+ */
+void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BUFFER_H__
+
+/**
+ * @}
+ * @endcond
+ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c
new file mode 100644
index 0000000..543a99b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "pm_mutex.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include "nrf_error.h"
+#include "app_util_platform.h"
+
+
+
+/**@brief Locks the mutex defined by the mask.
+ *
+ * @param p_mutex pointer to the mutex storage.
+ * @param mutex_mask the mask identifying the mutex position.
+ *
+ * @retval true if the mutex could be locked.
+ * @retval false if the mutex was already locked.
+ */
+static bool lock_by_mask(uint8_t * p_mutex, uint8_t mutex_mask)
+{
+ bool success = false;
+
+ if ( (*p_mutex & mutex_mask) == 0 )
+ {
+ CRITICAL_REGION_ENTER();
+ if ( (*p_mutex & mutex_mask) == 0 )
+ {
+ *p_mutex |= mutex_mask;
+
+ success = true;
+ }
+ CRITICAL_REGION_EXIT();
+ }
+
+ return ( success );
+}
+
+
+void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size)
+{
+ if (p_mutex != NULL)
+ {
+ memset(&p_mutex[0], 0, MUTEX_STORAGE_SIZE(mutex_size));
+ }
+}
+
+
+bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_id)
+{
+ if (p_mutex != NULL)
+ {
+ return ( lock_by_mask(&(p_mutex[mutex_id >> 3]), (1 << (mutex_id & 0x07))) );
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_id)
+{
+ uint8_t mutex_base = mutex_id >> 3;
+ uint8_t mutex_mask = (1 << (mutex_id & 0x07));
+
+ if ((p_mutex != NULL)
+ && (p_mutex[mutex_base] & mutex_mask))
+ {
+ CRITICAL_REGION_ENTER();
+ p_mutex[mutex_base] &= ~mutex_mask;
+ CRITICAL_REGION_EXIT();
+ }
+}
+
+
+uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size)
+{
+ if (p_mutex != NULL)
+ {
+ for ( uint16_t i = 0; i < mutex_size; i++ )
+ {
+ if ( lock_by_mask(&(p_mutex[i >> 3]), 1 << (i & 0x07)) )
+ {
+ return ( i );
+ }
+ }
+ }
+
+ return ( mutex_size );
+}
+
+
+bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_id)
+{
+ if (p_mutex != NULL)
+ {
+ return ( (p_mutex[mutex_id >> 3] & (1 << (mutex_id & 0x07))) );
+ }
+ else
+ {
+ return true;
+ }
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h
new file mode 100644
index 0000000..c598d3d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef MUTEX_H__
+#define MUTEX_H__
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup pm_mutex Mutex
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module provides thread-safe mutexes.
+ */
+
+
+/**@brief Defines the storage size of a specified mutex group.
+ *
+ * @param number_of_mutexes the number of mutexes in the group.
+ */
+#define MUTEX_STORAGE_SIZE(number_of_mutexes) ((7 + (number_of_mutexes)) >> 3)
+
+
+/**@brief Initializes a mutex group.
+ *
+ * @param[in] p_mutex Pointer to the mutex group. See @ref MUTEX_STORAGE_SIZE().
+ * @param[in] mutex_size The size of the mutex group in number of mutexes.
+ */
+void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size);
+
+
+/**@brief Locks the mutex specified by the bit id.
+ *
+ * @param[inout] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_bit_id The bit id of the mutex.
+ *
+ * @retval true if it was possible to lock the mutex.
+ * @retval false otherwise.
+ */
+bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_bit_id);
+
+
+/**@brief Locks the first unlocked mutex within the mutex group.
+ *
+ * @param[in, out] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_size The size of the mutex group.
+ *
+ * @return The first unlocked mutex id in the group.
+ * @retval group-size if there was no unlocked mutex available.
+ */
+uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size);
+
+
+/**@brief Unlocks the mutex specified by the bit id.
+ *
+ * @param[in, out] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_bit_id The bit id of the mutex.
+ */
+void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_bit_id);
+
+
+/**@brief Gets the locking status of the specified mutex.
+ *
+ * @param[in, out] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_bit_id The bit id of the mutex.
+ *
+ * @retval true if the mutex was locked.
+ * @retval false otherwise.
+ */
+bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_bit_id);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MUTEX_H__
+
+/** @}
+ * @endcond
+ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c
new file mode 100644
index 0000000..462bd62
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c
@@ -0,0 +1,1110 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "security_dispatcher.h"
+
+#include <string.h>
+#include "ble.h"
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "ble_conn_state.h"
+#include "peer_manager_types.h"
+#include "peer_database.h"
+#include "id_manager.h"
+
+#ifndef PM_CENTRAL_ENABLED
+ #define PM_CENTRAL_ENABLED 1
+#endif
+
+// The number of registered event handlers.
+#define SMD_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+STATIC_ASSERT((NRF_SDH_BLE_CENTRAL_LINK_COUNT == 0) || PM_CENTRAL_ENABLED,
+ "Peer Manager Central operation must be enabled when using central links.");
+
+// Security Dispacher event handlers in Security Manager and GATT Cache Manager.
+extern void sm_smd_evt_handler(pm_evt_t * p_event);
+
+// Security Dispatcher events' handlers.
+// The number of elements in this array is SMD_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ sm_smd_evt_handler
+};
+
+static bool m_module_initialized;
+
+static ble_conn_state_user_flag_id_t m_flag_sec_proc = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_sec_proc_pairing = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_sec_proc_bonding = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_sec_proc_new_peer = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_allow_repairing = BLE_CONN_STATE_USER_FLAG_INVALID;
+
+static ble_gap_lesc_p256_pk_t m_peer_pk;
+
+
+static __INLINE bool sec_procedure(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc);
+}
+
+static __INLINE bool pairing(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc_pairing);
+}
+
+static __INLINE bool bonding(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc_bonding);
+}
+
+static __INLINE bool peer_created(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc_new_peer);
+}
+
+static __INLINE bool allow_repairing(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_allow_repairing);
+}
+
+
+/**@brief Function for sending an SMD event to all event handlers.
+ *
+ * @param[in] p_event The event to pass to all event handlers.
+ */
+static void evt_send(pm_evt_t * p_event)
+{
+ p_event->peer_id = im_peer_id_get_by_conn_handle(p_event->conn_handle);
+
+ for (uint32_t i = 0; i < SMD_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+/**@brief Function for sending a PM_EVT_CONN_SEC_START event.
+ *
+ * @param[in] conn_handle The connection handle the event pertains to.
+ * @param[in] procedure The procedure that has started on the connection.
+ */
+static void sec_start_send(uint16_t conn_handle,
+ pm_conn_sec_procedure_t procedure)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_CONN_SEC_START,
+ .conn_handle = conn_handle,
+ .params = {.conn_sec_start = {.procedure = procedure}}
+ };
+ evt_send(&evt);
+}
+
+
+/**@brief Function for sending a PM_EVT_ERROR_UNEXPECTED event.
+ *
+ * @param[in] conn_handle The connection handle the event pertains to.
+ * @param[in] err_code The unexpected error that occurred.
+ */
+static void send_unexpected_error(uint16_t conn_handle, ret_code_t err_code)
+{
+ pm_evt_t error_evt =
+ {
+ .evt_id = PM_EVT_ERROR_UNEXPECTED,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .error_unexpected =
+ {
+ .error = err_code,
+ }
+ }
+ };
+ evt_send(&error_evt);
+}
+
+
+/**@brief Function for cleaning up after a failed security procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the security procedure happens on.
+ * @param[in] procedure The procedure that failed.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The party that raised the error. See @ref BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static void conn_sec_failure(uint16_t conn_handle,
+ pm_conn_sec_procedure_t procedure,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_CONN_SEC_FAILED,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .conn_sec_failed =
+ {
+ .procedure = procedure,
+ .error = error,
+ .error_src = error_src,
+ }
+ }
+ };
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc, false);
+
+ evt_send(&evt);
+ return;
+}
+
+
+/**@brief Function for cleaning up after a failed pairing procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the pairing procedure happens on.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The source of the error (local or remote). See @ref
+ * BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static void pairing_failure(uint16_t conn_handle,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ pm_conn_sec_procedure_t procedure = bonding(conn_handle) ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING;
+
+ if (peer_created(conn_handle))
+ {
+ // The peer_id was created during the procedure, and should be freed, because no data is
+ // stored under it.
+ err_code = im_peer_free(peer_id); // Attempt to free allocated peer.
+ UNUSED_VARIABLE(err_code);
+ }
+ else if(peer_id != PM_PEER_ID_INVALID)
+ {
+ err_code = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_BONDING);
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_NOT_FOUND /* No buffer was allocated */))
+ {
+ send_unexpected_error(conn_handle, err_code);
+ }
+ }
+
+ conn_sec_failure(conn_handle, procedure, error, error_src);
+
+ return;
+}
+
+
+/**@brief Function for cleaning up after a failed encryption procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the encryption procedure happens on.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The party that raised the error. See @ref BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static __INLINE void encryption_failure(uint16_t conn_handle,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ conn_sec_failure(conn_handle, PM_CONN_SEC_PROCEDURE_ENCRYPTION, error, error_src);
+
+ return;
+}
+
+
+/**@brief Function for possibly cleaning up after a failed pairing or encryption procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the pairing procedure happens on.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The party that raised the error. See @ref BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static void link_secure_failure(uint16_t conn_handle,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ if (sec_procedure(conn_handle))
+ {
+ if (pairing(conn_handle))
+ {
+ pairing_failure(conn_handle, error, error_src);
+ }
+ else
+ {
+ encryption_failure(conn_handle, error, error_src);
+ }
+ }
+}
+
+
+/**@brief Function for administrative actions to be taken when a security process has started.
+ *
+ * @param[in] conn_handle The connection the security process was attempted on.
+ * @param[in] success Whether the procedure was started successfully.
+ * @param[in] procedure The procedure that was started.
+ */
+static void sec_proc_start(uint16_t conn_handle,
+ bool success,
+ pm_conn_sec_procedure_t procedure)
+{
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc, success);
+ if (success)
+ {
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_sec_proc_pairing,
+ (procedure != PM_CONN_SEC_PROCEDURE_ENCRYPTION));
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_sec_proc_bonding,
+ (procedure == PM_CONN_SEC_PROCEDURE_BONDING));
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc_new_peer, false);
+ sec_start_send(conn_handle, procedure);
+ }
+}
+
+
+
+/**@brief Function for administrative actions to be taken during the course of a security process.
+ *
+ * @param[in] conn_handle The connection the security process was attempted on.
+ * @param[in] peer_id The peer ID given to the connected peer.
+ * @param[in] success Whether the process was started successfully.
+ * @param[in] new_peer_created Whether a new peer was created during the process attempt.
+ */
+static void sec_proc_housekeeping(uint16_t conn_handle,
+ pm_peer_id_t peer_id,
+ bool success,
+ bool new_peer_created)
+{
+ if (success)
+ {
+ if (new_peer_created)
+ {
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc_new_peer, true);
+ im_new_peer_id(conn_handle, peer_id);
+ }
+ }
+ else
+ {
+ if (new_peer_created)
+ {
+ ret_code_t err_code = im_peer_free(peer_id); // Attempt to free allocated peer.
+ UNUSED_VARIABLE(err_code);
+ }
+ }
+}
+
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_SEC_INFO_REQUEST event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void sec_info_request_process(ble_gap_evt_t const * p_gap_evt)
+{
+ ret_code_t err_code;
+ ble_gap_enc_info_t const * p_enc_info = NULL;
+ pm_peer_data_flash_t peer_data;
+ pm_peer_id_t peer_id = im_peer_id_get_by_master_id(
+ &p_gap_evt->params.sec_info_request.master_id);
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ peer_id = im_peer_id_get_by_conn_handle(p_gap_evt->conn_handle);
+ }
+ else
+ {
+ // The peer might have been unrecognized until now (since connecting). E.g. if using a
+ // random non-resolvable advertising address. Report the discovered peer ID just in case.
+ im_new_peer_id(p_gap_evt->conn_handle, peer_id);
+ }
+
+ sec_proc_start(p_gap_evt->conn_handle, true, PM_CONN_SEC_PROCEDURE_ENCRYPTION);
+
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_BONDING, &peer_data);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // There is stored bonding data for this peer.
+ ble_gap_enc_key_t const * p_existing_key = &peer_data.p_bonding_data->own_ltk;
+
+ if ( p_existing_key->enc_info.lesc
+ || (im_master_ids_compare(&p_existing_key->master_id,
+ &p_gap_evt->params.sec_info_request.master_id)))
+ {
+ p_enc_info = &p_existing_key->enc_info;
+ }
+ }
+ }
+
+ err_code = sd_ble_gap_sec_info_reply(p_gap_evt->conn_handle, p_enc_info, NULL, NULL);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ sec_proc_housekeeping(p_gap_evt->conn_handle, peer_id, false, false);
+ send_unexpected_error(p_gap_evt->conn_handle, err_code);
+ }
+ else if (p_enc_info == NULL)
+ {
+ sec_proc_housekeeping(p_gap_evt->conn_handle, peer_id, false, false);
+ encryption_failure(p_gap_evt->conn_handle,
+ PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING,
+ BLE_GAP_SEC_STATUS_SOURCE_LOCAL);
+ }
+
+ return;
+}
+
+
+/**@brief Function for sending a CONFIG_REQ event.
+ *
+ * @param[in] conn_handle The connection the sec parameters are needed for.
+ */
+static void send_config_req(uint16_t conn_handle)
+{
+ pm_evt_t evt;
+ memset(&evt, 0, sizeof(evt));
+
+ evt.evt_id = PM_EVT_CONN_SEC_CONFIG_REQ;
+ evt.conn_handle = conn_handle;
+
+ evt_send(&evt);
+}
+
+
+void smd_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_conn_sec_config != NULL);
+
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_allow_repairing,
+ p_conn_sec_config->allow_repairing);
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_DISCONNECT event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void disconnect_process(ble_gap_evt_t const * p_gap_evt)
+{
+ pm_sec_error_code_t error = (p_gap_evt->params.disconnected.reason
+ == BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE)
+ ? PM_CONN_SEC_ERROR_MIC_FAILURE : PM_CONN_SEC_ERROR_DISCONNECT;
+
+ link_secure_failure(p_gap_evt->conn_handle, error, BLE_GAP_SEC_STATUS_SOURCE_LOCAL);
+}
+
+
+/**@brief Function for sending a PARAMS_REQ event.
+ *
+ * @param[in] conn_handle The connection the security parameters are needed for.
+ * @param[in] p_peer_params The security parameters from the peer. Can be NULL if the peer's parameters
+ * are not yet available.
+ */
+static void send_params_req(uint16_t conn_handle, ble_gap_sec_params_t const * p_peer_params)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_CONN_SEC_PARAMS_REQ,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .conn_sec_params_req =
+ {
+ .p_peer_params = p_peer_params
+ },
+ },
+ };
+
+ evt_send(&evt);
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void sec_params_request_process(ble_gap_evt_t const * p_gap_evt)
+{
+ if (ble_conn_state_role(p_gap_evt->conn_handle) == BLE_GAP_ROLE_PERIPH)
+ {
+ sec_proc_start(p_gap_evt->conn_handle,
+ true,
+ p_gap_evt->params.sec_params_request.peer_params.bond
+ ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING);
+ }
+
+ send_params_req(p_gap_evt->conn_handle, &p_gap_evt->params.sec_params_request.peer_params);
+ return;
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_AUTH_STATUS event from the SoftDevice, when
+ * the auth_status is success.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void auth_status_success_process(ble_gap_evt_t const * p_gap_evt)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ uint16_t conn_handle = p_gap_evt->conn_handle;
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ pm_peer_id_t new_peer_id = peer_id;
+ pm_peer_data_t peer_data;
+ bool data_stored = false;
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc, false);
+
+ if (p_gap_evt->params.auth_status.bonded)
+ {
+ pm_peer_id_t duplicate_peer_id = PM_PEER_ID_INVALID;
+ data_stored = true;
+
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_BONDING, 1, &peer_data);
+ if (err_code != NRF_SUCCESS)
+ {
+ send_unexpected_error(conn_handle, err_code);
+ data_stored = false;
+ }
+ else
+ {
+ duplicate_peer_id = im_find_duplicate_bonding_data(peer_data.p_bonding_data,
+ PM_PEER_ID_INVALID);
+ }
+
+ if (duplicate_peer_id != PM_PEER_ID_INVALID)
+ {
+ // The peer has been identified as someone we have already bonded with.
+ new_peer_id = duplicate_peer_id;
+ im_new_peer_id(conn_handle, new_peer_id);
+
+ // If the flag is true, the configuration has been requested before.
+ if (!allow_repairing(conn_handle))
+ {
+ send_config_req(conn_handle);
+ if (!allow_repairing(conn_handle))
+ {
+ data_stored = false;
+ }
+ }
+ }
+
+ if (data_stored)
+ {
+ err_code = pdb_write_buf_store(peer_id, PM_PEER_DATA_ID_BONDING, new_peer_id);
+ if (err_code != NRF_SUCCESS)
+ {
+ /* Unexpected */
+ send_unexpected_error(conn_handle, err_code);
+ data_stored = false;
+ }
+ }
+
+ if ((duplicate_peer_id != PM_PEER_ID_INVALID) && peer_created(conn_handle))
+ {
+ // We already have a bond with the peer. Now that the data has been stored for the
+ // existing peer, the peer created for this bonding procedure can be freed.
+ ret_code_t err_code_free = im_peer_free(peer_id);
+ UNUSED_VARIABLE(err_code_free); // Errors can be safely ignored.
+ }
+ }
+ else if (peer_created(conn_handle))
+ {
+ ret_code_t err_code_free = im_peer_free(peer_id);
+ UNUSED_VARIABLE(err_code_free); // Errors can be safely ignored.
+ }
+ else
+ {
+ // No action.
+ }
+
+ pm_evt_t pairing_success_evt;
+
+ pairing_success_evt.evt_id = PM_EVT_CONN_SEC_SUCCEEDED;
+ pairing_success_evt.conn_handle = conn_handle;
+ pairing_success_evt.params.conn_sec_succeeded.procedure = p_gap_evt->params.auth_status.bonded
+ ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING;
+ pairing_success_evt.params.conn_sec_succeeded.data_stored = data_stored;
+
+ evt_send(&pairing_success_evt);
+
+ return;
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_AUTH_STATUS event from the SoftDevice, when
+ * the auth_status is failure.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void auth_status_failure_process(ble_gap_evt_t const * p_gap_evt)
+{
+ link_secure_failure(p_gap_evt->conn_handle,
+ p_gap_evt->params.auth_status.auth_status,
+ p_gap_evt->params.auth_status.error_src);
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_AUTH_STATUS event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void auth_status_process(ble_gap_evt_t const * p_gap_evt)
+{
+ switch (p_gap_evt->params.auth_status.auth_status)
+ {
+ case BLE_GAP_SEC_STATUS_SUCCESS:
+ auth_status_success_process(p_gap_evt);
+ break;
+
+ default:
+ auth_status_failure_process(p_gap_evt);
+ break;
+ }
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_CONN_SEC_UPDATE event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void conn_sec_update_process(ble_gap_evt_t const * p_gap_evt)
+{
+ if (!pairing(p_gap_evt->conn_handle))
+ {
+ // This is an encryption procedure (not pairing), so this event marks the end of the procedure.
+
+ if (!ble_conn_state_encrypted(p_gap_evt->conn_handle))
+ {
+ encryption_failure(p_gap_evt->conn_handle,
+ PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING,
+ BLE_GAP_SEC_STATUS_SOURCE_REMOTE);
+ }
+ else
+ {
+ ble_conn_state_user_flag_set(p_gap_evt->conn_handle, m_flag_sec_proc, false);
+
+ pm_evt_t evt;
+
+ evt.evt_id = PM_EVT_CONN_SEC_SUCCEEDED;
+ evt.conn_handle = p_gap_evt->conn_handle;
+ evt.params.conn_sec_succeeded.procedure = PM_CONN_SEC_PROCEDURE_ENCRYPTION;
+ evt.params.conn_sec_succeeded.data_stored = false;
+
+ evt_send(&evt);
+ }
+ }
+}
+
+
+/**@brief Funtion for initializing a BLE Connection State user flag.
+ *
+ * @param[out] flag_id The flag to initialize.
+ */
+static void flag_id_init(ble_conn_state_user_flag_id_t * p_flag_id)
+{
+ if (*p_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ *p_flag_id = ble_conn_state_user_flag_acquire();
+ }
+}
+
+
+ret_code_t smd_init(void)
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ flag_id_init(&m_flag_sec_proc);
+ flag_id_init(&m_flag_sec_proc_pairing);
+ flag_id_init(&m_flag_sec_proc_bonding);
+ flag_id_init(&m_flag_sec_proc_new_peer);
+ flag_id_init(&m_flag_allow_repairing);
+
+ if ((m_flag_sec_proc == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_sec_proc_pairing == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_sec_proc_bonding == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_sec_proc_new_peer == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_allow_repairing == BLE_CONN_STATE_USER_FLAG_INVALID))
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for putting retrieving a buffer and putting pointers into a @ref ble_gap_sec_keyset_t.
+ *
+ * @param[in] conn_handle The connection the security procedure is happening on.
+ * @param[in] peer_id The peer the security procedure is happening with.
+ * @param[in] role Our role in the connection.
+ * @param[in] p_public_key Pointer to a buffer holding the public key, or NULL.
+ * @param[out] p_sec_keyset Pointer to the keyset to be filled.
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_STORAGE_FULL Not enough room in persistent storage.
+ * @retval NRF_ERROR_BUSY Could not process request at this time. Reattempt later.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
+ * @retval NRF_ERROR_INTERNAL Fatal error.
+ */
+static ret_code_t sec_keyset_fill(uint16_t conn_handle,
+ pm_peer_id_t peer_id,
+ uint8_t role,
+ ble_gap_lesc_p256_pk_t * p_public_key,
+ ble_gap_sec_keyset_t * p_sec_keyset)
+{
+ ret_code_t err_code;
+ pm_peer_data_t peer_data;
+
+ if (p_sec_keyset == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ // Acquire a memory buffer to receive bonding data into.
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_BONDING, 1, &peer_data);
+
+ if (err_code == NRF_ERROR_BUSY)
+ {
+ // No action.
+ }
+ else if (err_code != NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else /* if (err_code == NRF_SUCCESS) */
+ {
+ memset(peer_data.p_bonding_data, 0, sizeof(pm_peer_data_bonding_t));
+
+ peer_data.p_bonding_data->own_role = role;
+
+ p_sec_keyset->keys_own.p_enc_key = &peer_data.p_bonding_data->own_ltk;
+ p_sec_keyset->keys_own.p_pk = p_public_key;
+ p_sec_keyset->keys_peer.p_enc_key = &peer_data.p_bonding_data->peer_ltk;
+ p_sec_keyset->keys_peer.p_id_key = &peer_data.p_bonding_data->peer_ble_id;
+ p_sec_keyset->keys_peer.p_pk = &m_peer_pk;
+
+ // Retrieve the address the peer used during connection establishment.
+ // This address will be overwritten if ID is shared. Should not fail.
+ err_code = im_ble_addr_get(conn_handle, &peer_data.p_bonding_data->peer_ble_id.id_addr_info);
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ // Buffer is OK, reserve room in flash for the data.
+ err_code = pdb_write_buf_store_prepare(peer_id, PM_PEER_DATA_ID_BONDING);
+ if (err_code == NRF_ERROR_NOT_FOUND)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+
+ return err_code;
+}
+
+
+ret_code_t smd_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ ble_gap_lesc_p256_pk_t * p_public_key)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint8_t role = ble_conn_state_role(conn_handle);
+ pm_peer_id_t peer_id = PM_PEER_ID_INVALID;
+ ret_code_t err_code = NRF_SUCCESS;
+ uint8_t sec_status = BLE_GAP_SEC_STATUS_SUCCESS;
+ bool new_peer_created = peer_created(conn_handle);
+ ble_gap_sec_keyset_t sec_keyset;
+
+ memset(&sec_keyset, 0, sizeof(ble_gap_sec_keyset_t));
+ if (role == BLE_GAP_ROLE_PERIPH)
+ {
+ // Set the default value for allowing repairing at the start of the sec proc. (for peripheral)
+ ble_conn_state_user_flag_set(conn_handle, m_flag_allow_repairing, false);
+ }
+
+ if (role == BLE_GAP_ROLE_INVALID)
+ {
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+
+ if (p_sec_params == NULL)
+ {
+ // NULL params means reject pairing.
+ sec_status = BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP;
+ }
+ else if (!p_sec_params->bond)
+ {
+ // Pairing, no bonding.
+
+ sec_keyset.keys_own.p_pk = p_public_key;
+ sec_keyset.keys_peer.p_pk = &m_peer_pk;
+ }
+ else
+ {
+ // Bonding is to be performed, prepare to receive bonding data.
+
+ peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ // Peer is unknown to us, allocate a new peer ID for it.
+ peer_id = pdb_peer_allocate();
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ new_peer_created = true;
+ }
+ else
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ else if (role == BLE_GAP_ROLE_PERIPH && !allow_repairing(conn_handle))
+ {
+ // Bond already exists. Reject the pairing request if the user doesn't intervene.
+ // send_config_req(conn_handle, peer_id);
+ send_config_req(conn_handle);
+ if (!allow_repairing(conn_handle))
+ {
+ // Reject pairing.
+ sec_status = BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP;
+ }
+ }
+
+ if ((sec_status != BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP) && (err_code == NRF_SUCCESS))
+ {
+ err_code = sec_keyset_fill(conn_handle, peer_id, role, p_public_key, &sec_keyset);
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Everything OK, reply to SoftDevice. If an error happened, the user is given an
+ // opportunity to change the parameters and retry the call.
+ if (role == BLE_GAP_ROLE_PERIPH)
+ {
+ err_code = sd_ble_gap_sec_params_reply(conn_handle, sec_status, p_sec_params, &sec_keyset);
+ }
+ else
+ {
+ err_code = sd_ble_gap_sec_params_reply(conn_handle, sec_status, NULL, &sec_keyset);
+ }
+ }
+
+ sec_proc_housekeeping(conn_handle,
+ peer_id,
+ (err_code == NRF_SUCCESS) && (sec_status == BLE_GAP_SEC_STATUS_SUCCESS),
+ new_peer_created);
+
+ return err_code;
+}
+
+
+#if PM_CENTRAL_ENABLED
+/**@brief Function for initiating encryption as a central. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_central_encryption(uint16_t conn_handle,
+ pm_peer_id_t peer_id)
+{
+ pm_peer_data_flash_t peer_data;
+ ret_code_t err_code;
+ ble_gap_enc_key_t const * p_existing_key = NULL;
+ bool lesc = false;
+
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_BONDING, &peer_data);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Use peer's key since they are peripheral.
+ p_existing_key = &(peer_data.p_bonding_data->peer_ltk);
+
+ lesc = peer_data.p_bonding_data->own_ltk.enc_info.lesc;
+ if (lesc) // LESC was used during bonding.
+ {
+ // For LESC, always use own key.
+ p_existing_key = &(peer_data.p_bonding_data->own_ltk);
+ }
+ }
+
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_NOT_FOUND))
+ {
+ if (err_code != NRF_ERROR_BUSY)
+ {
+ // Unexpected error code.
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ else if (p_existing_key == NULL) /* There is no bonding data stored. This means that a bonding
+ procedure is in ongoing, or that the records in flash are
+ in a bad state. */
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+ else if (!lesc && !im_master_id_is_valid(&(p_existing_key->master_id))) /* There is no valid LTK stored. */
+ {
+ // No LTK to encrypt with.
+ err_code = NRF_ERROR_INVALID_DATA;
+ }
+ else
+ {
+ // Encrypt with existing LTK.
+ err_code = sd_ble_gap_encrypt(conn_handle,
+ &(p_existing_key->master_id),
+ &(p_existing_key->enc_info));
+ }
+
+ sec_proc_start(conn_handle, err_code == NRF_SUCCESS, PM_CONN_SEC_PROCEDURE_ENCRYPTION);
+ sec_proc_housekeeping(conn_handle, peer_id, (err_code == NRF_SUCCESS), false);
+
+ return err_code;
+}
+
+
+/**@brief Function for intiating pairing as a central. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_central_pairing(uint16_t conn_handle,
+ pm_peer_id_t peer_id,
+ ble_gap_sec_params_t * p_sec_params)
+{
+ pm_conn_sec_procedure_t procedure = PM_CONN_SEC_PROCEDURE_PAIRING;
+ bool new_peer_created = false;
+ ret_code_t err_code = NRF_SUCCESS;
+ pm_peer_data_t dummy_peer_data;
+
+ if (p_sec_params == NULL)
+ {
+ err_code = sd_ble_gap_authenticate(conn_handle, NULL);
+ }
+ else
+ {
+ if (p_sec_params->bond)
+ {
+ procedure = PM_CONN_SEC_PROCEDURE_BONDING;
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ // New peer is required.
+ peer_id = pdb_peer_allocate();
+ new_peer_created = true;
+ }
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else
+ {
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_BONDING, 1, &dummy_peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = pdb_write_buf_store_prepare(peer_id, PM_PEER_DATA_ID_BONDING);
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = sd_ble_gap_authenticate(conn_handle, p_sec_params);
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ ret_code_t err_code_free = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_BONDING);
+ if ((err_code_free != NRF_SUCCESS) && (err_code_free != NRF_ERROR_NOT_FOUND))
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ }
+
+ if (err_code == NRF_ERROR_NO_MEM)
+ {
+ // sd_ble_gap_authenticate() returned NRF_ERROR_NO_MEM. Too many other sec procedures running.
+ err_code = NRF_ERROR_BUSY;
+ }
+
+ sec_proc_start(conn_handle, err_code == NRF_SUCCESS, procedure);
+ sec_proc_housekeeping(conn_handle, peer_id, (err_code == NRF_SUCCESS), new_peer_created);
+
+ return err_code;
+}
+
+
+
+/**@brief Function for intiating security as a central. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_central(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ bool force_repairing)
+{
+ ret_code_t err_code;
+ pm_peer_id_t peer_id;
+
+ if (p_sec_params == NULL)
+ {
+ return sd_ble_gap_authenticate(conn_handle, NULL);
+ }
+
+ // Set the default value for allowing repairing at the start of the sec proc. (for central)
+ ble_conn_state_user_flag_set(conn_handle, m_flag_allow_repairing, force_repairing);
+
+ peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+
+ if ((peer_id != PM_PEER_ID_INVALID) && !force_repairing)
+ {
+ // There is already data in flash for this peer, and repairing has not been requested, so
+ // link will be encrypted with the existing keys.
+ err_code = link_secure_central_encryption(conn_handle, peer_id);
+ }
+ else
+ {
+ // There are no existing keys, or repairing has been explicitly requested, so pairing
+ // (possibly including bonding) will be performed to encrypt the link.
+ err_code = link_secure_central_pairing(conn_handle, peer_id, p_sec_params);
+ }
+
+ return err_code;
+}
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_SEC_REQUEST event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void sec_request_process(ble_gap_evt_t const * p_gap_evt)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_SLAVE_SECURITY_REQ,
+ .conn_handle = p_gap_evt->conn_handle,
+ .params =
+ {
+ .slave_security_req =
+ {
+ .bond = p_gap_evt->params.sec_request.bond,
+ .mitm = p_gap_evt->params.sec_request.mitm,
+ }
+ }
+ };
+ evt_send(&evt);
+ return;
+}
+#endif // PM_CENTRAL_ENABLED
+
+
+/**@brief Function for asking the central to secure the link. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_peripheral(uint16_t conn_handle, ble_gap_sec_params_t * p_sec_params)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+
+ if (p_sec_params != NULL)
+ {
+ err_code = sd_ble_gap_authenticate(conn_handle, p_sec_params);
+ }
+
+ return err_code;
+}
+
+
+ret_code_t smd_link_secure(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ bool force_repairing)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint8_t role = ble_conn_state_role(conn_handle);
+
+ switch (role)
+ {
+#if PM_CENTRAL_ENABLED
+ case BLE_GAP_ROLE_CENTRAL:
+ return link_secure_central(conn_handle, p_sec_params, force_repairing);
+#endif
+
+ case BLE_GAP_ROLE_PERIPH:
+ return link_secure_peripheral(conn_handle, p_sec_params);
+
+ default:
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+}
+
+
+void smd_ble_evt_handler(ble_evt_t const * p_ble_evt)
+{
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_DISCONNECTED:
+ disconnect_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ sec_params_request_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+ case BLE_GAP_EVT_SEC_INFO_REQUEST:
+ sec_info_request_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+#if PM_CENTRAL_ENABLED
+ case BLE_GAP_EVT_SEC_REQUEST:
+ sec_request_process(&(p_ble_evt->evt.gap_evt));
+ break;
+#endif
+
+ case BLE_GAP_EVT_AUTH_STATUS:
+ auth_status_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+ case BLE_GAP_EVT_CONN_SEC_UPDATE:
+ conn_sec_update_process(&(p_ble_evt->evt.gap_evt));
+ break;
+ };
+}
+#endif //NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h
new file mode 100644
index 0000000..0699276
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef SECURITY_DISPATCHER_H__
+#define SECURITY_DISPATCHER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup security_dispatcher Security Dispatcher
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for streamlining pairing, bonding, and
+ * encryption, including flash storage of shared data.
+ *
+ */
+
+
+/**@brief Function for initializing the Security Dispatcher module.
+ *
+ * @retval NRF_SUCCESS Initialization was successful.
+ * @retval NRF_ERROR_INTERNAL An unexpected fatal error occurred.
+ */
+ret_code_t smd_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the Security Dispatcher module.
+ *
+ * @param[in] ble_evt The SoftDevice event.
+ */
+void smd_ble_evt_handler(ble_evt_t const * ble_evt);
+
+
+/**@brief Function for providing security configuration for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_CONFIG_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, a default configuration is used. See @ref pm_conn_sec_config_t
+ * for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the configuration for.
+ * @param[in] p_conn_sec_config The configuration.
+ */
+void smd_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config);
+
+
+/**@brief Function for providing pairing and bonding parameters to use for the current pairing
+ * procedure on a connection.
+ *
+ * @note If this function returns an @ref NRF_ERROR_NULL, @ref NRF_ERROR_INVALID_PARAM, @ref
+ * BLE_ERROR_INVALID_CONN_HANDLE, or @ref NRF_ERROR_STORAGE_FULL, this function can be called
+ * again after corrective action.
+ *
+ * @note To reject a request, call this function with NULL p_sec_params.
+ *
+ * @param[in] conn_handle The connection handle of the connection the pairing is happening on.
+ * @param[in] p_sec_params The security parameters to use for this link.
+ * @param[in] p_public_key A pointer to the public key to use if using LESC, or NULL.
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_INVALID_STATE No parameters have been requested on that conn_handle, or
+ * the link is disconnecting.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid combination of parameters (not including conn_handle).
+ * @retval NRF_ERROR_TIMEOUT There has been an SMP timeout, so no more SMP operations
+ * can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval NRF_ERROR_STORAGE_FULL No more room in flash. Fix and reattempt after the next
+ * FDS garbage collection procedure.
+ * @retval NRF_ERROR_BUSY No write buffer. Reattempt later.
+ * @retval NRF_ERROR_INTERNAL A fatal error occurred.
+ */
+ret_code_t smd_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ ble_gap_lesc_p256_pk_t * p_public_key);
+
+
+/**@brief Function for initiating security on the link, with the specified parameters.
+ *
+ * @note If the connection is a peripheral connection, this will send a security request to the
+ * master, but the master is not obligated to initiate pairing or encryption in response.
+ * @note If the connection is a central connection and a key is available, the parameters will be
+ * used to determine whether to re-pair or to encrypt using the existing key. If no key is
+ * available, pairing will be started.
+ *
+ * @param[in] conn_handle Handle of the connection to initiate pairing on.
+ * @param[in] p_sec_params The security parameters to use for this link. As a central, this can
+ * be NULL to reject a slave security request.
+ * @param[in] force_repairing Whether to force a pairing procedure to happen regardless of whether
+ * an encryption key already exists. This argument is only relevant for
+ * the central role. Recommended value: false
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_NULL p_sec_params was NULL (peripheral only).
+ * @retval NRF_ERROR_INVALID_STATE A security procedure is already in progress on the link,
+ * or the link is disconnecting.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid combination of parameters (not including conn_handle).
+ * @retval NRF_ERROR_INVALID_DATA Peer is bonded, but no LTK was found, and repairing was
+ * not requested.
+ * @retval NRF_ERROR_BUSY Unable to initiate procedure at this time.
+ * @retval NRF_ERROR_TIMEOUT There has been an SMP timeout, so no more SMP operations
+ * can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval NRF_ERROR_STORAGE_FULL No more room in flash. Fix and reattempt after the next
+ * FDS garbage collection procedure.
+ * @retval NRF_ERROR_INTERNAL No more available peer IDs.
+ */
+ret_code_t smd_link_secure(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ bool force_repairing);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURITY_DISPATCHER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c
new file mode 100644
index 0000000..86da8a0
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c
@@ -0,0 +1,675 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "security_manager.h"
+
+#include <string.h>
+#include "ble_err.h"
+#include "security_dispatcher.h"
+#include "peer_database.h"
+#include "ble_conn_state.h"
+#include "id_manager.h"
+#include "sdk_common.h"
+
+
+// The number of registered event handlers.
+#define SM_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Security Manager event handler in Peer Manager.
+extern void pm_sm_evt_handler(pm_evt_t * p_sm_evt);
+
+// Security Manager events' handlers.
+// The number of elements in this array is SM_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pm_sm_evt_handler
+};
+
+
+// The context type that is used in PM_EVT_CONN_SEC_PARAMS_REQ events and in calls to sm_sec_params_reply().
+typedef struct
+{
+ ble_gap_sec_params_t * p_sec_params; //!< The security parameters to use in the call to the security_dispatcher
+ ble_gap_sec_params_t sec_params_mem; //!< The buffer for holding the security parameters.
+ bool params_reply_called; //!< Whether @ref sm_sec_params_reply has been called for this context instance.
+} sec_params_reply_context_t;
+
+static bool m_module_initialized; //!< Whether the Security Manager module has been initialized.
+
+static ble_gap_sec_params_t m_sec_params; //!< The buffer for the default security parameters set by @ref sm_sec_params_set.
+static ble_gap_sec_params_t * mp_sec_params = NULL; //!< The default security parameters set by @ref sm_sec_params_set.
+static bool m_sec_params_set = false; //!< Whether @ref sm_sec_params_set has been called.
+
+static ble_gap_lesc_p256_pk_t * m_p_public_key; //!< Pointer, provided by the user, to the public key to use for LESC procedures.
+
+static ble_conn_state_user_flag_id_t m_flag_link_secure_pending_busy = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_link_secure because it returned @ref NRF_ERROR_BUSY.
+static ble_conn_state_user_flag_id_t m_flag_link_secure_pending_flash_full = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_link_secure because it returned @ref NRF_ERROR_STORAGE_FULL.
+static ble_conn_state_user_flag_id_t m_flag_link_secure_force_repairing = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a pending call to @ref sm_link_secure should be called with true for the force_repairing parameter.
+static ble_conn_state_user_flag_id_t m_flag_link_secure_null_params = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a pending call to @ref sm_link_secure should be called with NULL security parameters.
+static ble_conn_state_user_flag_id_t m_flag_params_reply_pending_busy = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_sec_params_reply because it returned @ref NRF_ERROR_BUSY.
+static ble_conn_state_user_flag_id_t m_flag_params_reply_pending_flash_full = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_sec_params_reply because it returned @ref NRF_ERROR_STORAGE_FULL.
+
+
+/**@brief Function for sending an SM event to all registered event handlers.
+ *
+ * @param[in] p_event The event to send.
+ */
+static void evt_send(pm_evt_t * p_event)
+{
+ for (uint32_t i = 0; i < SM_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+/**@brief Function for setting or clearing user flags based on error codes returned from @ref
+ * smd_link_secure or @ref smd_params_reply.
+ *
+ * @param[in] conn_handle The connection the call pertained to.
+ * @param[in] err_code The error code returned from @ref smd_link_secure or
+ * @ref smd_params_reply.
+ * @param[in] params_reply Whether the call was to @ref smd_params_reply.
+ */
+static void flags_set_from_err_code(uint16_t conn_handle, ret_code_t err_code, bool params_reply)
+{
+ bool flag_value_flash_full = false;
+ bool flag_value_busy = false;
+
+ if ((err_code == NRF_ERROR_STORAGE_FULL))
+ {
+ flag_value_busy = false;
+ flag_value_flash_full = true;
+ }
+ else if (err_code == NRF_ERROR_BUSY)
+ {
+ flag_value_busy = true;
+ flag_value_flash_full = false;
+ }
+ else
+ {
+ flag_value_busy = false;
+ flag_value_flash_full = false;
+ }
+
+ if (params_reply)
+ {
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_params_reply_pending_flash_full,
+ flag_value_flash_full);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_params_reply_pending_busy,
+ flag_value_busy);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_flash_full,
+ false);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_busy,
+ false);
+ }
+ else
+ {
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_flash_full,
+ flag_value_flash_full);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_busy,
+ flag_value_busy);
+ }
+}
+
+
+/**@brief Function for sending an event based on error codes returned from @ref smd_link_secure or
+ * @ref smd_params_reply.
+ *
+ * @param[in] conn_handle The connection the event pertains to.
+ * @param[in] err_code The error code returned from @ref smd_link_secure or
+ * @ref smd_params_reply.
+ * @param[in] p_sec_params The security parameters attempted to pass in the call to
+ * @ref smd_link_secure or @ref smd_params_reply.
+ */
+static void events_send_from_err_code(uint16_t conn_handle,
+ ret_code_t err_code,
+ ble_gap_sec_params_t * p_sec_params)
+{
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_INVALID_STATE))
+ {
+ pm_evt_t evt =
+ {
+ .conn_handle = conn_handle,
+ .peer_id = im_peer_id_get_by_conn_handle(conn_handle),
+ };
+ if (err_code == NRF_ERROR_TIMEOUT)
+ {
+ evt.evt_id = PM_EVT_CONN_SEC_FAILED;
+ evt.params.conn_sec_failed.procedure = ((p_sec_params != NULL) && p_sec_params->bond)
+ ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING;
+ evt.params.conn_sec_failed.error_src = BLE_GAP_SEC_STATUS_SOURCE_LOCAL;
+ evt.params.conn_sec_failed.error = PM_CONN_SEC_ERROR_SMP_TIMEOUT;
+ }
+ else if (err_code == NRF_ERROR_STORAGE_FULL)
+ {
+ evt.evt_id = PM_EVT_STORAGE_FULL;
+ }
+ else
+ {
+ evt.evt_id = PM_EVT_ERROR_UNEXPECTED;
+ evt.params.error_unexpected.error = err_code;
+ }
+ evt_send(&evt);
+ }
+}
+
+
+/**@brief Function for sending an PM_EVT_CONN_SEC_PARAMS_REQ event.
+ *
+ * @param[in] conn_handle The connection the event pertains to.
+ * @param[in] p_peer_params The peer's security parameters to include in the event. Can be NULL.
+ * @param[in] p_context Pointer to a context that the user must include in the call to @ref
+ * sm_sec_params_reply().
+ */
+static void params_req_send(uint16_t conn_handle,
+ ble_gap_sec_params_t const * p_peer_params,
+ sec_params_reply_context_t * p_context)
+{
+ pm_evt_t evt;
+ evt.evt_id = PM_EVT_CONN_SEC_PARAMS_REQ;
+ evt.conn_handle = conn_handle;
+ evt.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ evt.params.conn_sec_params_req.p_peer_params = p_peer_params;
+ evt.params.conn_sec_params_req.p_context = p_context;
+
+ evt_send(&evt);
+}
+
+
+/**@brief Function for creating a new @ref sec_params_reply_context_t with the correct initial values.
+ *
+ * @return The new context.
+ */
+static sec_params_reply_context_t new_context_get(void)
+{
+ sec_params_reply_context_t new_context =
+ {
+ .p_sec_params = mp_sec_params,
+ .params_reply_called = false
+ };
+ return new_context;
+}
+
+
+/**@brief Internal function corresponding to @ref sm_link_secure.
+ *
+ * @param[in] conn_handle The connection to secure.
+ * @param[in] null_params Whether to pass NULL security parameters to the security_dispatcher.
+ * @param[in] force_repairing Whether to force rebonding if peer exists.
+ * @param[in] send_events Whether to send events based on the result of @ref smd_link_secure.
+ *
+ * @return Same return codes as @ref sm_link_secure.
+ */
+static ret_code_t link_secure(uint16_t conn_handle,
+ bool null_params,
+ bool force_repairing,
+ bool send_events)
+{
+ ret_code_t err_code;
+ ret_code_t return_err_code;
+ ble_gap_sec_params_t * p_sec_params;
+
+ if (null_params)
+ {
+ p_sec_params = NULL;
+ }
+ else
+ {
+ sec_params_reply_context_t context = new_context_get();
+ params_req_send(conn_handle, NULL, &context);
+ p_sec_params = context.p_sec_params;
+
+ if (!m_sec_params_set && !context.params_reply_called)
+ {
+ // Security parameters have not been set.
+ return NRF_ERROR_NOT_FOUND;
+ }
+ }
+
+
+ err_code = smd_link_secure(conn_handle, p_sec_params, force_repairing);
+
+ flags_set_from_err_code(conn_handle, err_code, false);
+
+ switch (err_code)
+ {
+ case NRF_ERROR_BUSY:
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_null_params, null_params);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_force_repairing, force_repairing);
+ return_err_code = NRF_SUCCESS;
+ break;
+ case NRF_ERROR_STORAGE_FULL:
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_null_params, null_params);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_force_repairing, force_repairing);
+ /* fallthrough */
+ case NRF_SUCCESS:
+ case NRF_ERROR_TIMEOUT:
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ case NRF_ERROR_INVALID_STATE:
+ case NRF_ERROR_INVALID_DATA:
+ return_err_code = err_code;
+ break;
+ default:
+ return_err_code = NRF_ERROR_INTERNAL;
+ break;
+ }
+
+ if (send_events)
+ {
+ events_send_from_err_code(conn_handle, err_code, p_sec_params);
+ }
+
+ return return_err_code;
+}
+
+
+/**@brief Function for requesting security parameters from the user and passing them to the security_dispatcher.
+ *
+ * @param[in] conn_handle The connection that needs security parameters.
+ * @param[in] p_peer_params The peer's security parameters if present. Otherwise NULL.
+ */
+static void smd_params_reply_perform(uint16_t conn_handle, ble_gap_sec_params_t const * p_peer_params)
+{
+ ret_code_t err_code;
+ sec_params_reply_context_t context = new_context_get();
+
+ params_req_send(conn_handle, p_peer_params, &context);
+
+ err_code = smd_params_reply(conn_handle, context.p_sec_params, m_p_public_key);
+
+ flags_set_from_err_code(conn_handle, err_code, true);
+ events_send_from_err_code(conn_handle, err_code, context.p_sec_params);
+}
+
+
+/**@brief Function for handling @ref PM_EVT_CONN_SEC_PARAMS_REQ events.
+ *
+ * @param[in] p_event The @ref PM_EVT_CONN_SEC_PARAMS_REQ event.
+ */
+static __INLINE void params_req_process(pm_evt_t const * p_event)
+{
+ smd_params_reply_perform(p_event->conn_handle, p_event->params.conn_sec_params_req.p_peer_params);
+}
+
+
+/**@brief Function for handling @ref PM_EVT_SLAVE_SECURITY_REQ events.
+ *
+ * @param[in] p_event The @ref PM_EVT_SLAVE_SECURITY_REQ event.
+ */
+static void sec_req_process(pm_evt_t const * p_event)
+{
+ bool null_params = false;
+ if (mp_sec_params == NULL)
+ {
+ null_params = true;
+ }
+ else if ((bool)m_sec_params.bond < (bool)p_event->params.slave_security_req.bond)
+ {
+ null_params = true;
+ }
+ else if ((bool)m_sec_params.mitm < (bool)p_event->params.slave_security_req.mitm)
+ {
+ null_params = true;
+ }
+ else
+ {
+ // No action.
+ }
+ ret_code_t err_code = link_secure(p_event->conn_handle, null_params, false, true);
+ UNUSED_VARIABLE(err_code); // It is acceptable to ignore the return code because it is
+ // acceptable to ignore a security request.
+}
+
+
+/**@brief Function for translating an SMD event to an SM event and passing it on to SM event handlers.
+ *
+ * @param[in] p_event The event to forward.
+ */
+static void evt_forward(pm_evt_t * p_event)
+{
+ evt_send(p_event);
+}
+
+
+/**@brief Event handler for events from the Security Dispatcher module.
+ * This handler is extern in Security Dispatcher.
+ *
+ * @param[in] p_event The event that has happened.
+ */
+void sm_smd_evt_handler(pm_evt_t * p_event)
+{
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_CONN_SEC_PARAMS_REQ:
+ params_req_process(p_event);
+ break;
+ case PM_EVT_SLAVE_SECURITY_REQ:
+ sec_req_process(p_event);
+ /* fallthrough */
+ default:
+ // Forward the event to all registered Security Manager event handlers.
+ evt_forward(p_event);
+ break;
+ }
+}
+
+
+/**@brief Function handling a pending params_reply. See @ref ble_conn_state_user_function_t.
+ */
+static void params_reply_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ smd_params_reply_perform(conn_handle, NULL);
+}
+
+
+/**@brief Function handling a pending link_secure. See @ref ble_conn_state_user_function_t.
+ */
+static void link_secure_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+
+ bool force_repairing = ble_conn_state_user_flag_get(conn_handle, m_flag_link_secure_force_repairing);
+ bool null_params = ble_conn_state_user_flag_get(conn_handle, m_flag_link_secure_null_params);
+
+ // If this fails, it will be automatically retried.
+ ret_code_t err_code = link_secure(conn_handle, null_params, force_repairing, true);
+ UNUSED_VARIABLE(err_code);
+}
+
+
+/**@brief Event handler for events from the Peer Database module.
+ * This handler is extern in Peer Database.
+ *
+ * @param[in] p_event The event that has happened.
+ */
+void sm_pdb_evt_handler(pm_evt_t * p_event)
+{
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_FLASH_GARBAGE_COLLECTED:
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_params_reply_pending_flash_full,
+ params_reply_pending_handle,
+ NULL);
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_link_secure_pending_flash_full,
+ link_secure_pending_handle,
+ NULL);
+ /* fallthrough */
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ case PM_EVT_PEER_DELETE_SUCCEEDED:
+ case PM_EVT_PEER_DELETE_FAILED:
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_params_reply_pending_busy,
+ params_reply_pending_handle,
+ NULL);
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_link_secure_pending_busy,
+ link_secure_pending_handle,
+ NULL);
+ break;
+ default:
+ // Do nothing.
+ break;
+ }
+}
+
+
+/**@brief Funtion for initializing a BLE Connection State user flag.
+ *
+ * @param[out] flag_id The flag to initialize.
+ */
+static void flag_id_init(ble_conn_state_user_flag_id_t * p_flag_id)
+{
+ if (*p_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ *p_flag_id = ble_conn_state_user_flag_acquire();
+ }
+}
+
+
+ret_code_t sm_init(void)
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ flag_id_init(&m_flag_link_secure_pending_busy);
+ flag_id_init(&m_flag_link_secure_pending_flash_full);
+ flag_id_init(&m_flag_link_secure_force_repairing);
+ flag_id_init(&m_flag_link_secure_null_params);
+ flag_id_init(&m_flag_params_reply_pending_busy);
+ flag_id_init(&m_flag_params_reply_pending_flash_full);
+
+ if (m_flag_params_reply_pending_flash_full == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+void sm_ble_evt_handler(ble_evt_t const * p_ble_evt)
+{
+ NRF_PM_DEBUG_CHECK(p_ble_evt != NULL);
+
+ smd_ble_evt_handler(p_ble_evt);
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_link_secure_pending_busy,
+ link_secure_pending_handle,
+ NULL);
+}
+
+
+/**@brief Funtion for checking whether security parameters are valid.
+ *
+ * @param[out] p_sec_params The security parameters to verify.
+ *
+ * @return Whether the security parameters are valid.
+ */
+static bool sec_params_verify(ble_gap_sec_params_t * p_sec_params)
+{
+ // NULL check.
+ if (p_sec_params == NULL)
+ {
+ return false;
+ }
+
+ // OOB not allowed unless MITM.
+ if (!p_sec_params->mitm && p_sec_params->oob)
+ {
+ return false;
+ }
+
+ // IO Capabilities must be one of the valid values from @ref BLE_GAP_IO_CAPS.
+ if (p_sec_params->io_caps > BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY)
+ {
+ return false;
+ }
+
+ // Must have either IO capabilities or OOB if MITM.
+ if (p_sec_params->mitm && (p_sec_params->io_caps == BLE_GAP_IO_CAPS_NONE) && !p_sec_params->oob)
+ {
+ return false;
+ }
+
+ // Minimum key size cannot be larger than maximum key size.
+ if (p_sec_params->min_key_size > p_sec_params->max_key_size)
+ {
+ return false;
+ }
+
+ // Key size cannot be below 7 bytes.
+ if (p_sec_params->min_key_size < 7)
+ {
+ return false;
+ }
+
+ // Key size cannot be above 16 bytes.
+ if (p_sec_params->max_key_size > 16)
+ {
+ return false;
+ }
+
+ // Signing is not supported.
+ if (p_sec_params->kdist_own.sign || p_sec_params->kdist_peer.sign)
+ {
+ return false;
+ }
+
+ // link bit must be 0.
+ if (p_sec_params->kdist_own.link || p_sec_params->kdist_peer.link)
+ {
+ return false;
+ }
+
+ // If bonding is not enabled, no keys can be distributed.
+ if (!p_sec_params->bond && ( p_sec_params->kdist_own.enc
+ || p_sec_params->kdist_own.id
+ || p_sec_params->kdist_peer.enc
+ || p_sec_params->kdist_peer.id))
+ {
+ return false;
+ }
+
+ // If bonding is enabled, one or more keys must be distributed.
+ if ( p_sec_params->bond
+ && !p_sec_params->kdist_own.enc
+ && !p_sec_params->kdist_own.id
+ && !p_sec_params->kdist_peer.enc
+ && !p_sec_params->kdist_peer.id)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+ret_code_t sm_sec_params_set(ble_gap_sec_params_t * p_sec_params)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ if (p_sec_params == NULL)
+ {
+ mp_sec_params = NULL;
+ m_sec_params_set = true;
+ return NRF_SUCCESS;
+ }
+ else if (sec_params_verify(p_sec_params))
+ {
+ m_sec_params = *p_sec_params;
+ mp_sec_params = &m_sec_params;
+ m_sec_params_set = true;
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+}
+
+
+void sm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_conn_sec_config != NULL);
+
+ smd_conn_sec_config_reply(conn_handle, p_conn_sec_config);
+}
+
+
+ret_code_t sm_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ VERIFY_PARAM_NOT_NULL(p_context);
+
+ sec_params_reply_context_t * p_sec_params_reply_context = (sec_params_reply_context_t *)p_context;
+ if (p_sec_params == NULL)
+ {
+ // Set the store pointer to NULL, so that NULL is passed to the SoftDevice.
+ p_sec_params_reply_context->p_sec_params = NULL;
+ }
+ else if (sec_params_verify(p_sec_params))
+ {
+ // Copy the provided sec_params into the store.
+ p_sec_params_reply_context->sec_params_mem = *p_sec_params;
+ p_sec_params_reply_context->p_sec_params = &p_sec_params_reply_context->sec_params_mem;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ p_sec_params_reply_context->params_reply_called = true;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t sm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ m_p_public_key = p_public_key;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t sm_link_secure(uint16_t conn_handle, bool force_repairing)
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ ret = link_secure(conn_handle, false, force_repairing, false);
+ return ret;
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h
new file mode 100644
index 0000000..a91c15d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef SECURITY_MANAGER_H__
+#define SECURITY_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "security_dispatcher.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup security_manager Security Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for streamlining pairing, bonding, and
+ * encryption, including flash storage of shared data.
+ */
+
+
+/**@brief Function for initializing the Security Manager module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t sm_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the Security Manager module.
+ *
+ * @param[in] ble_evt The SoftDevice event.
+ */
+void sm_ble_evt_handler(ble_evt_t const * ble_evt);
+
+
+/**@brief Function for providing pairing and bonding parameters to use for pairing procedures.
+ *
+ * @details Until this is called, all bonding procedures initiated by the peer will be rejected.
+ * This function can be called multiple times, even with NULL p_sec_params, in which case
+ * it will go back to rejecting all procedures.
+ *
+ * @param[in] p_sec_params The security parameters to use for this link. Can be NULL to reject
+ * all pairing procedures.
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid combination of parameters.
+ */
+ret_code_t sm_sec_params_set(ble_gap_sec_params_t * p_sec_params);
+
+
+/**@brief Function for providing security configuration for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_CONFIG_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, a default configuration is used. See @ref pm_conn_sec_config_t
+ * for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the configuration for.
+ * @param[in] p_conn_sec_config The configuration.
+ */
+void sm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config);
+
+
+/**@brief Function for providing security parameters for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_PARAMS_REQ event, before the Security Manager event handler returns. If
+ * it is not called in time, the parameters given in @ref sm_sec_params_set are used. See
+ * @ref pm_conn_sec_config_t for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the parameters for.
+ * @param[in] p_sec_params The parameters. If NULL, the security procedure is rejected.
+ * @param[in] p_context The context found in the request event that this function replies to.
+ *
+ * @retval NRF_SUCCESS Successful reply.
+ * @retval NRF_ERROR_NULL p_context was null.
+ * @retval NRF_ERROR_INVALID_PARAM Value of p_sec_params was invalid.
+ * @retval NRF_ERROR_INVALID_STATE This module is not initialized.
+ */
+ret_code_t sm_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context);
+
+
+/**@brief Experimental function for specifying the public key to use for LESC operations.
+ *
+ * @details This function can be called multiple times. The specified public key will be used for
+ * all subsequent LESC (LE Secure Connections) operations until the next time this function
+ * is called.
+ *
+ * @note The key must continue to reside in application memory as it is not copied by Peer Manager.
+ *
+ * @param[in] p_public_key The public key to use for all subsequent LESC operations.
+ *
+ * @retval NRF_SUCCESS Pairing initiated successfully.
+ * @retval NRF_ERROR_INVALID_STATE This module is not initialized.
+ */
+ret_code_t sm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key);
+
+
+
+/**@brief Function for initiating security on the link, with the specified parameters.
+ *
+ * @note If the connection is a peripheral connection, this will send a security request to the
+ * master, but the master is not obligated to initiate pairing or encryption in response.
+ * @note If the connection is a central connection and a key is available, the parameters will be
+ * used to determine whether to re-pair or to encrypt using the existing key. If no key is
+ * available, pairing will be started.
+ *
+ * @param[in] conn_handle Handle of the connection to initiate pairing on.
+ * @param[in] force_repairing Whether to force a pairing procedure to happen regardless of whether
+ * an encryption key already exists. This argument is only relevant for
+ * the central role. Recommended value: false
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_TIMEOUT There has been an SMP timeout, so no more SMP operations
+ * can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval NRF_ERROR_INVALID_DATA Peer is bonded, but no LTK was found, and repairing was
+ * not requested.
+ * @retval NRF_ERROR_NOT_FOUND Security parameters have not been set.
+ * @retval NRF_ERROR_INVALID_STATE A security procedure is already in progress on the link,
+ * or the link is disconnecting.
+ * @retval NRF_ERROR_INTERNAL An unexpected error occurred.
+ */
+ret_code_t sm_link_secure(uint16_t conn_handle, bool force_repairing);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURITY_MANAGER_H__ */