Nordic stack and drivers for the mbed BLE API

Fork of nRF51822 by Nordic Semiconductor

Revision:
640:c90ae1400bf2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TARGET_MCU_NRF51822/sdk/source/ble/device_manager/device_manager_peripheral.c	Wed Sep 14 14:39:43 2016 +0100
@@ -0,0 +1,2934 @@
+/*
+ * Copyright (c) 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 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 other
+ *   contributors to this software may be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 "device_manager.h"
+#include "pstorage.h"
+#include "ble_hci.h"
+#include "app_error.h"
+
+#if defined ( __CC_ARM )
+    #ifndef __ALIGN
+        #define __ALIGN(x)      __align(x)                  /**< Forced aligment keyword for ARM Compiler */
+    #endif
+#elif defined ( __ICCARM__ )
+    #ifndef __ALIGN
+        #define __ALIGN(x)                                  /**< Forced aligment keyword for IAR Compiler */
+    #endif
+#elif defined   ( __GNUC__ )
+    #ifndef __ALIGN
+        #define __ALIGN(x)      __attribute__((aligned(x))) /**< Forced aligment keyword for GNU Compiler */
+    #endif
+#endif
+
+#define INVALID_ADDR_TYPE 0xFF   /**< Identifier for an invalid address type. */
+#define EDIV_INIT_VAL     0xFFFF /**< Initial value for diversifier. */
+
+/**
+ * @defgroup device_manager_app_states Connection Manager Application States
+ * @{
+ */
+#define STATE_CONTROL_PROCEDURE_IN_PROGRESS 0x01 /**< State where a security procedure is ongoing. */
+#define STATE_QUEUED_CONTROL_REQUEST        0x02 /**< State where it is known if there is any queued security request or not. */
+/** @} */
+
+/**
+ * @defgroup device_manager_conn_inst_states Connection Manager Connection Instances States.
+ * @{
+ */
+#define STATE_IDLE             0x01 /**< State where connection instance is free. */
+#define STATE_CONNECTED        0x02 /**< State where connection is successfully established. */
+#define STATE_PAIRING          0x04 /**< State where pairing procedure is in progress. This state is used for pairing and bonding, as pairing is needed for both. */
+#define STATE_BONDED           0x08 /**< State where device is bonded. */
+#define STATE_DISCONNECTING    0x10 /**< State where disconnection is in progress, application will be notified first, but no further active procedures on the link. */
+#define STATE_PAIRING_PENDING  0x20 /**< State where pairing request is pending on the link. */
+#define STATE_BOND_INFO_UPDATE 0x40 /**< State where information has been updated, update the flash. */
+#define STATE_LINK_ENCRYPTED   0x80 /**< State where link is encrypted. */
+/** @} */
+
+/**
+ * @defgroup device_manager_peer_id_defines Peer Identification Information Defines.
+ *
+ * @brief These defines are used to know which of the peer identification is applicable for a peer.
+ *
+ * @details These defines are used for peer identification. Here, bit map is used because it is
+ *          possible that the application has both IRK and address for identification.
+ * @{
+ */
+#define UNASSIGNED            0xFF /**< Peer instance is unassigned/unused. */
+#define IRK_ENTRY             0x01 /**< Peer instance has IRK as identification information. */
+#define ADDR_ENTRY            0x02 /**< Peer instance has address as identification information. */
+#define SERVICE_CONTEXT_ENTRY 0x04 /**< Peer instance has service context set. */
+#define APP_CONTEXT_ENTRY     0x08 /**< Peer instance has an application context set. */
+/** @} */
+
+/**@brief Device store state identifiers. */
+typedef enum
+{
+    STORE_ALL_CONTEXT, /**< Store all context. */
+    FIRST_BOND_STORE,  /**< Store bond. */
+    UPDATE_PEER_ADDR   /**< Update peer address. */
+} device_store_state_t;
+
+/**
+ * @defgroup device_manager_context_offsets Context Offsets
+ * @{
+ *
+ * @brief Context offsets each of the context information in persistent memory.
+ *
+ * @details Below is a layout showing how each how the context information is stored in persistent
+ *          memory.
+ *
+ * All Device context is stored in the flash as follows:
+ * +---------+---------+---------+------------------+----------------+--------------------+
+ * | Block / Device ID + Layout of stored information in storage block                    |
+ * +---------+---------+---------+------------------+----------------+--------------------+
+ * | Block 0 | Device 0| Peer Id | Bond Information | Service Context| Application Context|
+ * +---------+---------+---------+------------------+----------------+--------------------+
+ * | Block 1 | Device 1| Peer Id | Bond Information | Service Context| Application Context|
+ * +---------+---------+---------+------------------+----------------+--------------------+
+ * |  ...              | ....                                                             |
+ * +---------+---------+---------+------------------+----------------+--------------------+
+ * | Block N | Device N| Peer Id | Bond Information | Service Context| Application Context|
+ * +---------+---------+---------+------------------+----------------+--------------------+
+ *
+ * The following defines are used to get offset of each of the components within a block.
+ */
+
+#define PEER_ID_STORAGE_OFFSET     0                                               /**< Offset at which peer id is stored in the block. */
+#define BOND_STORAGE_OFFSET        PEER_ID_SIZE                                    /**< Offset at which bond information is stored in the block. */
+#define SERVICE_STORAGE_OFFSET     (BOND_STORAGE_OFFSET + BOND_SIZE)               /**< Offset at which service context is stored in the block. */
+#define APP_CONTEXT_STORAGE_OFFSET (SERVICE_STORAGE_OFFSET + SERVICE_CONTEXT_SIZE) /**< Offset at which application context is stored in the block. */
+/** @} */
+
+/**
+ * @defgroup device_manager_context_size Context size.
+ * @{
+ *
+ * @brief This group defines the size of each of the context information.
+ */
+#define PEER_ID_SIZE               (sizeof(peer_id_t))                                             /**< Size of peer identification information. */
+#define BOND_SIZE                  (sizeof(bond_context_t))                                        /**< Size of bond information. */
+#define DEVICE_CONTEXT_SIZE        (PEER_ID_SIZE + BOND_SIZE)                                      /**< Size of Device context, include peer identification and bond information. */
+#define GATTS_SERVICE_CONTEXT_SIZE (sizeof(dm_gatts_context_t))                                    /**< Size of GATTS service context. */
+#define GATTC_SERVICE_CONTEXT_SIZE (sizeof(dm_gatt_client_context_t))                              /**< Size of GATTC service context. */
+#define SERVICE_CONTEXT_SIZE       (GATTS_SERVICE_CONTEXT_SIZE + GATTC_SERVICE_CONTEXT_SIZE)       /**< Combined size of GATTS and GATTC service contexts. */
+#define APP_CONTEXT_MIN_SIZE       4                                                               /**< Minimum size for application context data. */
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+#define APP_CONTEXT_SIZE           (sizeof(uint32_t) + DEVICE_MANAGER_APP_CONTEXT_SIZE)            /**< Size of application context including length field. */
+#else //DEVICE_MANAGER_APP_CONTEXT_SIZE
+#define APP_CONTEXT_SIZE           0                                                               /**< Size of application context. */
+#endif // DEVICE_MANAGER_APP_CONTEXT_SIZE
+#define ALL_CONTEXT_SIZE           (DEVICE_CONTEXT_SIZE + SERVICE_CONTEXT_SIZE + APP_CONTEXT_SIZE) /**< Size of all contexts. */
+/** @} */
+
+
+/**
+ * @defgroup device_manager_log Module's Log Macros
+ *
+ * @details Macros used for creating module logs which can be useful in understanding handling
+ *          of events or actions on API requests. These are intended for debugging purposes and
+ *          can be disabled by defining the DM_DISABLE_LOGS.
+ *
+ * @note That if ENABLE_DEBUG_LOG_SUPPORT is disabled, having DM_DISABLE_LOGS has no effect.
+ * @{
+ */
+#define DM_DISABLE_LOGS        /**< Enable this macro to disable any logs from this module. */
+
+#ifndef DM_DISABLE_LOGS
+#define DM_LOG  app_trace_log  /**< Used for logging details. */
+#define DM_ERR  app_trace_log  /**< Used for logging errors in the module. */
+#define DM_TRC  app_trace_log  /**< Used for getting trace of execution in the module. */
+#define DM_DUMP app_trace_dump /**< Used for dumping octet information to get details of bond information etc. */
+#else //DM_DISABLE_LOGS
+#define DM_DUMP(...)           /**< Disables dumping of octet streams. */
+#define DM_LOG(...)            /**< Disables detailed logs. */
+#define DM_ERR(...)            /**< Disables error logs. */
+#define DM_TRC(...)            /**< Disables traces. */
+#endif //DM_DISABLE_LOGS
+/** @} */
+
+/**
+ * @defgroup device_manager_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
+ *
+ * @details Macros used to lock and unlock modules. Currently the SDK does not use mutexes but
+ *          framework is provided in case need arises to use an alternative architecture.
+ * @{
+ */
+#define DM_MUTEX_LOCK()   SDK_MUTEX_LOCK(m_dm_mutex)   /**< Lock module using mutex. */
+#define DM_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_dm_mutex) /**< Unlock module using mutex. */
+/** @} */
+
+
+/**
+ * @defgroup device_manager_misc_defines Miscellaneous defines used across the module.
+ * @{
+ */
+#define DM_GATT_ATTR_SIZE            6                                                   /**< Size of each GATT attribute to be stored persistently. */
+#define DM_GATT_SERVER_ATTR_MAX_SIZE ((DM_GATT_ATTR_SIZE * DM_GATT_CCCD_COUNT) + 2) /**< Maximum size of GATT attributes to be stored.*/
+#define DM_SERVICE_CONTEXT_COUNT     (DM_PROTOCOL_CNTXT_ALL + 1)                         /**< Maximum number of service contexts. */
+#define DM_EVT_DEVICE_CONTEXT_BASE   0x20                                                /**< Base for device context base. */
+#define DM_EVT_SERVICE_CONTEXT_BASE  0x30                                                /**< Base for service context base. */
+#define DM_EVT_APP_CONTEXT_BASE      0x40                                                /**< Base for application context base. */
+#define DM_LOAD_OPERATION_ID         0x01                                                /**< Load operation identifier. */
+#define DM_STORE_OPERATION_ID        0x02                                                /**< Store operation identifier. */
+#define DM_CLEAR_OPERATION_ID        0x03                                                /**< Clear operation identifier. */
+/** @} */
+
+#define DM_GATTS_INVALID_SIZE        0xFFFFFFFF                                     /**< Identifer for GATTS invalid size. */
+
+/**
+ * @defgroup api_param_check API Parameters check macros.
+ *
+ * @details Macros for verifying parameters passed to the module in the APIs. These macros
+ *          could be mapped to nothing in the final version of the code in order to save execution 
+ *          time and program size.
+ * @{
+ */
+
+//#define DM_DISABLE_API_PARAM_CHECK /**< Macro to disable API parameters check. */
+
+#ifndef DM_DISABLE_API_PARAM_CHECK
+
+/**@brief Macro for verifying NULL parameters are not passed to API.
+ *
+ * @param[in] PARAM Parameter checked for NULL.
+ *
+ * @retval (NRF_ERROR_NULL | DEVICE_MANAGER_ERR_BASE) when @ref PARAM is NULL.
+ */
+#define NULL_PARAM_CHECK(PARAM)                            \
+    if ((PARAM) == NULL)                                   \
+    {                                                      \
+        return (NRF_ERROR_NULL | DEVICE_MANAGER_ERR_BASE); \
+    }
+/**@} */
+
+
+/**@brief Macro for verifying module's initialization status.
+ *
+ * @retval (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE) when module is not initialized.
+ */
+#define VERIFY_MODULE_INITIALIZED()                                     \
+    do                                                                  \
+    {                                                                   \
+        if (!m_module_initialized)                                      \
+        {                                                               \
+            return (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE); \
+        }                                                               \
+    } while (0)
+
+
+/**@brief Macro for verifying module's initialization status. Returns in case it is not initialized.
+ */
+#define VERIFY_MODULE_INITIALIZED_VOID() \
+    do                                   \
+    {                                    \
+        if (!m_module_initialized)       \
+        {                                \
+            return;                      \
+        }                                \
+    } while (0)
+
+
+/**@brief Macro for verifying that the application is registered.
+ *
+ * @param[in] X Application instance identifier.
+ *
+ * @retval (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE) when module API is called without
+ *         registering an application with the module.
+ */
+#define VERIFY_APP_REGISTERED(X)                                        \
+    do                                                                  \
+    {                                                                   \
+        if (((X) >= DEVICE_MANAGER_MAX_APPLICATIONS) ||                 \
+            (m_application_table[(X)].ntf_cb == NULL))                  \
+        {                                                               \
+            return (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE); \
+        }                                                               \
+    } while (0)
+
+
+/**@brief Macro for verifying that the application is registered. Returns in case it is not
+ *        registered.
+ *
+ * @param[in] X Application instance identifier.
+ */
+#define VERIFY_APP_REGISTERED_VOID(X)                   \
+    do                                                  \
+    {                                                   \
+        if (((X) >= DEVICE_MANAGER_MAX_APPLICATIONS) || \
+            (m_application_table[(X)].ntf_cb == NULL))  \
+        {                                               \
+            return;                                     \
+        }                                               \
+    } while (0)
+
+
+/**@brief Macro for verifying connection instance is allocated.
+ *
+ * @param[in] X Connection instance identifier.
+ *
+ * @retval (NRF_ERROR_INVALID_ADDR | DEVICE_MANAGER_ERR_BASE) when connection instance is not
+ *         allocated.
+ */
+#define VERIFY_CONNECTION_INSTANCE(X)                                  \
+    do                                                                 \
+    {                                                                  \
+        if (((X) >= DEVICE_MANAGER_MAX_CONNECTIONS) ||                 \
+            (m_connection_table[(X)].state == STATE_IDLE))             \
+        {                                                              \
+            return (NRF_ERROR_INVALID_ADDR | DEVICE_MANAGER_ERR_BASE); \
+        }                                                              \
+    } while (0)
+
+
+/**@brief Macro for verifying if device instance is allocated.
+ *
+ * @param[in] X Device instance identifier.
+ *
+ * @retval (NRF_ERROR_INVALID_ADDR | DEVICE_MANAGER_ERR_BASE) when device instance is not allocated.
+ */
+#define VERIFY_DEVICE_INSTANCE(X)                                      \
+    do                                                                 \
+    {                                                                  \
+        if (((X) >= DEVICE_MANAGER_MAX_BONDS) ||                       \
+            (m_peer_table[(X)].id_bitmap == UNASSIGNED))               \
+        {                                                              \
+            return (NRF_ERROR_INVALID_ADDR | DEVICE_MANAGER_ERR_BASE); \
+        }                                                              \
+    } while (0)
+
+/**@brief Macro for verifying if device is bonded and thus can store data persistantly.
+ *
+ * @param[in] X Connection instance identifier.
+ *
+ * @retval (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE) when device is not bonded.
+ */
+#define VERIFY_DEVICE_BOND(X)                                              \
+    do                                                                     \
+    {                                                                      \
+        if ((m_connection_table[(X)].state & STATE_BONDED) != STATE_BONDED)\
+        {                                                                  \
+            return (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE);    \
+        }                                                                  \
+    } while (0)
+#else
+#define NULL_PARAM_CHECK(X)
+#define VERIFY_MODULE_INITIALIZED()
+#define VERIFY_MODULE_INITIALIZED_VOID()
+#define VERIFY_APP_REGISTERED(X)
+#define VERIFY_APP_REGISTERED_VOID(X)
+#define VERIFY_CONNECTION_INSTANCE(X)
+#define VERIFY_DEVICE_INSTANCE(X)
+#endif //DM_DISABLE_API_PARAM_CHECK
+/** @} */
+
+#define INVALID_CONTEXT_LEN 0xFFFFFFFF /**< Identifier for invalid context length. */
+/**@brief Macro for checking that application context size is greater that minimal size.
+ *
+ * @param[in] X Size of application context.
+ *
+ * @retval (NRF_ERROR_INVALID_PARAM) when size is smaller than minimun required size.
+ */
+#define SIZE_CHECK_APP_CONTEXT(X)                                      \
+    if ((X) < (APP_CONTEXT_MIN_SIZE))                                  \
+    {                                                                  \
+        return NRF_ERROR_INVALID_PARAM;                                \
+    }
+
+
+/**
+ * @defgroup dm_data_types Module's internal data types.
+ *
+ * @brief This section describes a module's internal data structures.
+ * @{
+ */
+/**@brief Peer identification information.
+ */
+typedef struct
+{ 
+    ble_gap_id_key_t peer_id;   /**< IRK and/or address of peer. */
+    uint16_t         ediv;      /**< Peer's encrypted diversifier. */
+    uint8_t          id_bitmap; /**< Contains information if above field is valid. */
+} peer_id_t;
+
+STATIC_ASSERT(sizeof(peer_id_t) % 4 == 0); /**< Check to ensure Peer identification information is a multiple of 4. */
+
+/**@brief Portion of bonding information exchanged by a device during bond creation that needs to
+ *        be stored persistently.
+ *
+ * @note  An entry is not made in this table unless device is bonded.
+ */
+typedef struct
+{
+    ble_gap_enc_key_t peer_enc_key; /**< Local LTK info, central IRK and address */
+} bond_context_t;
+
+STATIC_ASSERT(sizeof(bond_context_t) % 4 == 0); /**< Check to ensure bond information is a multiple of 4. */
+
+/**@brief GATT Server Attributes size and data.
+ */
+typedef struct
+{
+    uint32_t flags;                                    /**< Flags identifying the stored attributes. */
+    uint32_t size;                                     /**< Size of stored attributes. */
+    uint8_t  attributes[DM_GATT_SERVER_ATTR_MAX_SIZE]; /**< Array to hold the server attributes. */
+} dm_gatts_context_t;
+
+STATIC_ASSERT(sizeof(dm_gatts_context_t) % 4 == 0); /**< Check to ensure GATT Server Attributes size and data information is a multiple of 4. */
+
+/**@brief GATT Client context information. Placeholder for now.
+ */
+typedef struct
+{
+    void * p_dummy; /**< Placeholder, currently unused. */
+} dm_gatt_client_context_t;
+
+STATIC_ASSERT(sizeof(dm_gatt_client_context_t) % 4 == 0);  /**< Check to ensure GATT Client context information is a multiple of 4. */
+STATIC_ASSERT((DEVICE_MANAGER_APP_CONTEXT_SIZE % 4) == 0); /**< Check to ensure device manager application context information is a multiple of 4. */
+
+/**@brief Connection instance definition. Maintains information with respect to an active peer.
+ */
+typedef struct
+{
+    ble_gap_addr_t peer_addr;     /**< Peer identification information. This information is retained as long as the connection session exists, once disconnected, for non-bonded devices this information is not stored persistently. */
+    uint16_t       conn_handle;   /**< Connection handle for the device. */
+    uint8_t        state;         /**< Link state. */
+    uint8_t        bonded_dev_id; /**< In case the device is bonded, this points to the corresponding bonded device. This index can be used to index service and bond context as well. */
+} connection_instance_t;
+
+/**@brief Application instance definition. Maintains information with respect to a registered
+ *        application.
+ */
+typedef struct
+{
+    dm_event_cb_t        ntf_cb;    /**< Callback registered with the application. */
+    ble_gap_sec_params_t sec_param; /**< Local security parameters registered by the application. */
+    uint8_t              state;     /**< Application state. Currently this is used only for knowing if any security procedure is in progress and/or a security procedure is pending to be requested. */
+    uint8_t              service;   /**< Service registered by the application. */
+} application_instance_t;
+
+/**@brief Function for performing necessary action of storing each of the service context as
+ *        registered by the application.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is stored.
+ *
+ * @retval Operation result code.
+ */
+typedef ret_code_t (* service_context_access_t)(pstorage_handle_t const * p_block_handle,
+                                                dm_handle_t const       * p_handle);
+
+/**@brief Function for performing necessary action of applying the context information.
+ *
+ * @param[in] p_handle Device handle identifying device that is stored.
+ *
+ * @retval Operation result code.
+ */
+typedef ret_code_t (* service_context_apply_t)(dm_handle_t * p_handle);
+
+/**@brief Function for performing necessary functions of storing or updating.
+ *
+ * @param[in] p_dest Destination address where data is stored persistently.
+ * @param[in] p_src  Source address containing data to be stored.
+ * @param[in] size   Size of data to be stored expressed in bytes. Must be word aligned.
+ * @param[in] offset Offset in bytes to be applied when writing to the block.
+ *
+ * @retval Operation result code.
+ */
+typedef uint32_t (* storage_operation)(pstorage_handle_t * p_dest,
+                                       uint8_t           * p_src,
+                                       pstorage_size_t     size,
+                                       pstorage_size_t     offset);
+/** @} */
+
+/**
+ * @defgroup dm_tables Module's internal tables.
+ *
+ * @brief This section describes the module's internal tables and the static global variables
+ *        needed for its functionality.
+ * @{
+ */
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+static uint8_t * m_app_context_table[DEVICE_MANAGER_MAX_BONDS];                     /**< Table to remember application contexts of bonded devices. */
+#endif //DEVICE_MANAGER_APP_CONTEXT_SIZE
+__ALIGN(sizeof(uint32_t))
+static peer_id_t              m_peer_table[DEVICE_MANAGER_MAX_BONDS] ;              /**< Table to maintain bonded devices' identification information, an instance is allocated in the table when a device is bonded and freed when bond information is deleted. */
+__ALIGN(sizeof(uint32_t))
+static bond_context_t         m_bond_table[DEVICE_MANAGER_MAX_CONNECTIONS];         /**< Table to maintain bond information for active peers. */
+static dm_gatts_context_t     m_gatts_table[DEVICE_MANAGER_MAX_CONNECTIONS];        /**< Table for service information for active connection instances. */
+static connection_instance_t  m_connection_table[DEVICE_MANAGER_MAX_CONNECTIONS];   /**< Table to maintain active peer information. An instance is allocated in the table when a new connection is established and freed on disconnection. */
+static application_instance_t m_application_table[DEVICE_MANAGER_MAX_APPLICATIONS]; /**< Table to maintain application instances. */
+static pstorage_handle_t      m_storage_handle;                                     /**< Persistent storage handle for blocks requested by the module. */
+static uint32_t               m_peer_addr_update;                                   /**< 32-bit bitmap to remember peer device address update. */
+static ble_gap_id_key_t       m_local_id_info;                                      /**< ID information of central in case resolvable address is used. */
+static bool                   m_module_initialized = false;                         /**< State indicating if module is initialized or not. */
+static uint8_t                m_irk_index_table[DEVICE_MANAGER_MAX_BONDS];          /**< List maintaining IRK index list. */
+
+SDK_MUTEX_DEFINE(m_dm_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+/** @} */
+
+static __INLINE ret_code_t no_service_context_store(pstorage_handle_t const * p_block_handle,
+                                                    dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t gatts_context_store(pstorage_handle_t const * p_block_handle,
+                                               dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t gattc_context_store(pstorage_handle_t const * p_block_handle,
+                                               dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t gattsc_context_store(pstorage_handle_t const * p_block_handle,
+                                                dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t no_service_context_load(pstorage_handle_t const * p_block_handle,
+                                                   dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t gatts_context_load(pstorage_handle_t const * p_block_handle,
+                                              dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t gattc_context_load(pstorage_handle_t const * p_block_handle,
+                                              dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t gattsc_context_load(pstorage_handle_t const * p_block_handle,
+                                               dm_handle_t const       * p_handle);
+
+static __INLINE ret_code_t no_service_context_apply(dm_handle_t * p_handle);
+
+static __INLINE ret_code_t gatts_context_apply(dm_handle_t * p_handle);
+
+static __INLINE ret_code_t gattc_context_apply(dm_handle_t * p_handle);
+
+static __INLINE ret_code_t gattsc_context_apply(dm_handle_t * p_handle);
+
+
+/**< Array of function pointers based on the types of service registered. */
+const service_context_access_t m_service_context_store[DM_SERVICE_CONTEXT_COUNT] =
+{
+    no_service_context_store, /**< Dummy function, when there is no service context registered. */
+    gatts_context_store,      /**< GATT Server context store function. */
+    gattc_context_store,      /**< GATT Client context store function. */
+    gattsc_context_store      /**< GATT Server & Client context store function. */
+};
+
+
+/**< Array of function pointers based on the types of service registered. */
+const service_context_access_t m_service_context_load[DM_SERVICE_CONTEXT_COUNT] =
+{
+    no_service_context_load,  /**< Dummy function, when there is no service context registered. */
+    gatts_context_load,       /**< GATT Server context load function. */
+    gattc_context_load,       /**< GATT Client context load function. */
+    gattsc_context_load       /**< GATT Server & Client context load function. */
+};
+
+
+/**< Array of function pointers based on the types of service registered. */
+const service_context_apply_t m_service_context_apply[DM_SERVICE_CONTEXT_COUNT] =
+{
+    no_service_context_apply, /**< Dummy function, when there is no service context registered. */
+    gatts_context_apply,      /**< GATT Server context apply function. */
+    gattc_context_apply,      /**< GATT Client context apply function. */
+    gattsc_context_apply      /**< GATT Server & Client context apply function. */
+};
+
+
+const uint32_t m_context_init_len = 0xFFFFFFFF; /**< Constant used to update the initial value for context in the flash. */
+
+/**@brief Function for setting update status for the device identified by 'index'.
+ *
+ * @param[in] index Device identifier.
+ */
+static __INLINE void update_status_bit_set(uint32_t index)
+{
+    m_peer_addr_update |= (BIT_0 << index);
+}
+
+
+/**@brief Function for resetting update status for device identified by 'index'.
+ *
+ * @param[in] index Device identifier.
+ */
+static __INLINE void update_status_bit_reset(uint32_t index)
+{
+    m_peer_addr_update &= (~((uint32_t)BIT_0 << index));
+}
+
+
+/**@brief Function for providing update status for the device identified by 'index'.
+ *
+ * @param[in] index Device identifier.
+ *
+ * @retval true if the bit is set, false otherwise.
+ */
+static __INLINE bool update_status_bit_is_set(uint32_t index)
+{
+    return ((m_peer_addr_update & (BIT_0 << index)) ? true : false);
+}
+
+
+/**@brief Function for initialiasing the application instance identified by 'index'.
+ *
+ * @param[in] index Device identifier.
+ */
+static __INLINE void application_instance_init(uint32_t index)
+{
+    DM_TRC("[DM]: Initializing Application Instance 0x%08X.\r\n", index);
+
+    m_application_table[index].ntf_cb  = NULL;
+    m_application_table[index].state   = 0x00;
+    m_application_table[index].service = 0x00;
+}
+
+
+/**@brief Function for initialiasing the connection instance identified by 'index'.
+ *
+ * @param[in] index Device identifier.
+ */
+static __INLINE void connection_instance_init(uint32_t index)
+{
+    DM_TRC("[DM]: Initializing Connection Instance 0x%08X.\r\n", index);
+    
+    m_connection_table[index].state         = STATE_IDLE;
+    m_connection_table[index].conn_handle   = BLE_CONN_HANDLE_INVALID;
+    m_connection_table[index].bonded_dev_id = DM_INVALID_ID;
+    
+    memset(&m_connection_table[index].peer_addr, 0, sizeof (ble_gap_addr_t));
+}
+
+
+/**@brief Function for initialiasing the peer device instance identified by 'index'.
+ *
+ * @param[in] index Device identifier.
+ */
+static __INLINE void peer_instance_init(uint32_t index)
+{
+    DM_TRC("[DM]: Initializing Peer Instance 0x%08X.\r\n", index);
+    
+    memset(m_peer_table[index].peer_id.id_addr_info.addr, 0, BLE_GAP_ADDR_LEN);
+    memset(m_peer_table[index].peer_id.id_info.irk, 0, BLE_GAP_SEC_KEY_LEN);
+
+    //Initialize the address type to invalid.
+    m_peer_table[index].peer_id.id_addr_info.addr_type = INVALID_ADDR_TYPE;
+
+    //Initialize the identification bit map to unassigned.
+    m_peer_table[index].id_bitmap = UNASSIGNED;
+
+    // Initialize diversifier.
+    m_peer_table[index].ediv      = EDIV_INIT_VAL;
+
+
+    //Reset the status bit.
+    update_status_bit_reset(index);
+
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+    //Initialize the application context for bond device.
+    m_app_context_table[index] = NULL;
+#endif //DEVICE_MANAGER_APP_CONTEXT_SIZE
+}
+
+
+/**@brief Function for searching connection instance matching the connection handle and the state
+ *        requested.
+ *
+ * @details Connection handle and state information is used to get a connection instance, it
+ *          is possible to ignore the connection handle by using BLE_CONN_HANDLE_INVALID.
+ *
+ * @param[in]  conn_handle Connection handle.
+ * @param[in]  state       Connection instance state.
+ * @param[out] p_instance  Connection instance.
+ *
+ * @retval NRF_SUCCESS             Operation success.
+ * @retval NRF_ERROR_INVALID_STATE Operation failure. Invalid state
+ * @retval NRF_ERROR_NOT_FOUND     Operation failure. Not found
+ */
+static ret_code_t connection_instance_find(uint16_t   conn_handle,
+                                           uint8_t    state,
+                                           uint32_t * p_instance)
+{
+    ret_code_t err_code;
+    uint32_t   index;
+
+    err_code = NRF_ERROR_INVALID_STATE;
+
+    for (index = 0; index < DEVICE_MANAGER_MAX_CONNECTIONS; index++)
+    {
+        //Search only based on the state.
+        if (state & m_connection_table[index].state)
+        {
+            //Ignore the connection handle.
+            if ((conn_handle == BLE_CONN_HANDLE_INVALID) ||
+                (conn_handle == m_connection_table[index].conn_handle))
+            {
+                //Search for matching connection handle.
+                (*p_instance) = index;
+                err_code      = NRF_SUCCESS;
+
+                break;
+            }
+            else
+            {
+                err_code = NRF_ERROR_NOT_FOUND;
+            }
+        }
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for allocating device instance for a bonded device.
+ *
+ * @param[out] p_device_index Device index.
+ * @param[in]  p_addr         Peer identification information.
+ *
+ * @retval NRF_SUCCESS            Operation success.
+ * @retval DM_DEVICE_CONTEXT_FULL Operation failure.
+ */
+static __INLINE ret_code_t device_instance_allocate(uint8_t *              p_device_index,
+                                                    ble_gap_addr_t const * p_addr)
+{
+    ret_code_t err_code;
+    uint32_t   index;
+
+    err_code = DM_DEVICE_CONTEXT_FULL;
+
+    for (index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+    {
+        DM_TRC("[DM]:[DI 0x%02X]: Device type 0x%02X.\r\n",
+               index, m_peer_table[index].peer_id.id_addr_info.addr_type);
+        DM_TRC("[DM]: Device Addr 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X.\r\n",
+               m_peer_table[index].peer_id.id_addr_info.addr[0],
+               m_peer_table[index].peer_id.id_addr_info.addr[1],
+               m_peer_table[index].peer_id.id_addr_info.addr[2],
+               m_peer_table[index].peer_id.id_addr_info.addr[3],
+               m_peer_table[index].peer_id.id_addr_info.addr[4],
+               m_peer_table[index].peer_id.id_addr_info.addr[5]);
+
+        if (m_peer_table[index].id_bitmap == UNASSIGNED)
+        {
+            if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+            {
+                m_peer_table[index].id_bitmap            &= (~ADDR_ENTRY);
+                m_peer_table[index].peer_id.id_addr_info  = (*p_addr);
+            }
+            else
+            {
+                m_peer_table[index].id_bitmap &= (~IRK_ENTRY);
+            }
+
+            (*p_device_index) = index;
+            err_code          = NRF_SUCCESS;
+
+            DM_LOG("[DM]: Allocated device instance 0x%02X\r\n", index);
+            
+            break;
+        }
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for freeing a device instance allocated for bonded device.
+ *
+ * @param[in] device_index Device index.
+ *
+ * @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
+ */
+static __INLINE ret_code_t device_instance_free(uint32_t device_index)
+{
+    ret_code_t        err_code;
+    pstorage_handle_t block_handle;
+
+    //Get the block handle.
+    err_code = pstorage_block_identifier_get(&m_storage_handle, device_index, &block_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        DM_TRC("[DM]:[DI 0x%02X]: Freeing Instance.\r\n", device_index);
+
+        //Request clearing of the block.
+        err_code = pstorage_clear(&block_handle, ALL_CONTEXT_SIZE);
+
+        if (err_code == NRF_SUCCESS)
+        {
+            peer_instance_init(device_index);
+        }
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for searching for the device in the bonded device list.
+ *
+ * @param[in]  p_addr         Peer identification information.
+ * @param[out] p_device_index Device index.
+ *
+ * @retval NRF_SUCCESS         Operation success.
+ * @retval NRF_ERROR_NOT_FOUND Operation failure.
+ */
+static ret_code_t device_instance_find(ble_gap_addr_t const * p_addr, uint32_t * p_device_index, uint16_t ediv)
+{
+    ret_code_t err_code;
+    uint32_t   index;
+
+    err_code = NRF_ERROR_NOT_FOUND;
+    
+    if (NULL != p_addr)
+    {
+        DM_TRC("[DM]: Searching for device 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X.\r\n",
+               p_addr->addr[0],
+               p_addr->addr[1],
+               p_addr->addr[2],
+               p_addr->addr[3],
+               p_addr->addr[4],
+               p_addr->addr[5]);
+    }
+
+    for (index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+    {
+        DM_TRC("[DM]:[DI 0x%02X]: Device type 0x%02X.\r\n",
+               index, m_peer_table[index].peer_id.id_addr_info.addr_type);
+        DM_TRC("[DM]: Device Addr 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X.\r\n",
+               m_peer_table[index].peer_id.id_addr_info.addr[0],
+               m_peer_table[index].peer_id.id_addr_info.addr[1],
+               m_peer_table[index].peer_id.id_addr_info.addr[2],
+               m_peer_table[index].peer_id.id_addr_info.addr[3],
+               m_peer_table[index].peer_id.id_addr_info.addr[4],
+               m_peer_table[index].peer_id.id_addr_info.addr[5]);
+
+        if (((NULL == p_addr) && (ediv == m_peer_table[index].ediv)) ||
+            ((NULL != p_addr) && (memcmp(&m_peer_table[index].peer_id.id_addr_info, p_addr, sizeof(ble_gap_addr_t)) == 0)))
+        {
+            DM_LOG("[DM]: Found device at instance 0x%02X\r\n", index);
+
+            (*p_device_index) = index;
+            err_code          = NRF_SUCCESS;
+
+            break;
+        }
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for notifying connection manager event to the application.
+ *
+ * @param[in] p_handle     Device handle identifying device.
+ * @param[in] p_event      Connection manager event details.
+ * @param[in] event_result Event result code.
+ */
+static __INLINE void app_evt_notify(dm_handle_t const * const p_handle,
+                                    dm_event_t const * const  p_event,
+                                    uint32_t                  event_result)
+{
+    dm_event_cb_t app_cb = m_application_table[0].ntf_cb;
+
+    DM_MUTEX_UNLOCK();
+
+    DM_TRC("[DM]: Notifying application of event 0x%02X\r\n", p_event->event_id);
+
+    //No need to do any kind of return value processing thus can be supressed.
+    UNUSED_VARIABLE(app_cb(p_handle, p_event, event_result));
+
+    DM_MUTEX_LOCK();
+}
+
+
+/**@brief Function for allocating instance.
+ *
+ * @details The instance identifier is provided in the 'p_instance' parameter if the routine
+ *          succeeds.
+ *
+ * @param[out] p_instance Connection instance.
+ *
+ * @retval NRF_SUCCESS      Operation success.
+ * @retval NRF_ERROR_NO_MEM Operation failure. No memory.
+ */
+static __INLINE uint32_t connection_instance_allocate(uint32_t * p_instance)
+{
+    uint32_t err_code;
+
+    DM_TRC("[DM]: Request to allocation connection instance\r\n");
+
+    err_code = connection_instance_find(BLE_CONN_HANDLE_INVALID, STATE_IDLE, p_instance);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        DM_LOG("[DM]:[%02X]: Connection Instance Allocated.\r\n", (*p_instance));        
+        m_connection_table[*p_instance].state = STATE_CONNECTED;
+    }
+    else
+    {
+        DM_LOG("[DM]: No free connection instances available\r\n");        
+        err_code = NRF_ERROR_NO_MEM;
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for freeing instance. Instance identifier is provided in the parameter
+ *        'p_instance' in case the routine succeeds.
+ *
+ * @param[in] p_instance Connection instance.
+ */
+static __INLINE void connection_instance_free(uint32_t const * p_instance)
+{
+    DM_TRC("[DM]:[CI 0x%02X]: Freeing connection instance\r\n", (*p_instance));
+
+    if (m_connection_table[*p_instance].state != STATE_IDLE)
+    {
+        DM_LOG("[DM]:[%02X]: Freed connection instance.\r\n", (*p_instance));
+        connection_instance_init(*p_instance);
+    }
+}
+
+
+/**@brief Function for storage operation dummy handler.
+ *
+ * @param[in] p_dest Destination address where data is to be stored persistently.
+ * @param[in] p_src  Source address containing data to be stored. API assumes this to be resident
+ *                   memory and no intermediate copy of data is made by the API.
+ * @param[in] size   Size of data to be stored expressed in bytes. Should be word aligned.
+ * @param[in] offset Offset in bytes to be applied when writing to the block.
+ *                   For example, if within a block of 100 bytes, application wishes to
+ *                   write 20 bytes at offset of 12, then this field should be set to 12.
+ *                   Should be word aligned.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ */
+static uint32_t storage_operation_dummy_handler(pstorage_handle_t * p_dest,
+                                                uint8_t           * p_src,
+                                                pstorage_size_t     size,
+                                                pstorage_size_t     offset)
+{
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for saving the device context persistently.
+ *
+ * @param[in] p_handle Device handle identifying device.
+ * @param[in] state    Device store state.
+ */
+static __INLINE void device_context_store(dm_handle_t const * p_handle, device_store_state_t state)
+{
+    pstorage_handle_t block_handle;
+    storage_operation store_fn;
+    ret_code_t        err_code;
+
+    DM_LOG("[DM]: --> device_context_store\r\n");
+
+    err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                             p_handle->device_id,
+                                             &block_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        if ((STATE_BOND_INFO_UPDATE ==
+             (m_connection_table[p_handle->connection_id].state & STATE_BOND_INFO_UPDATE)) ||
+            (state == UPDATE_PEER_ADDR))
+        {
+            DM_LOG("[DM]:[DI %02X]:[CI %02X]: -> Updating bonding information.\r\n",
+                   p_handle->device_id, p_handle->connection_id);
+
+            store_fn = pstorage_update;
+        }
+        else if (state == FIRST_BOND_STORE)
+        {
+            DM_LOG("[DM]:[DI %02X]:[CI %02X]: -> Storing bonding information.\r\n",
+                   p_handle->device_id, p_handle->connection_id);
+
+            store_fn = pstorage_store;
+        }
+        else
+        {
+            DM_LOG("[DM]:[DI %02X]:[CI %02X]: -> No update in bonding information.\r\n",
+                   p_handle->device_id, p_handle->connection_id);
+
+            //No operation needed.
+            store_fn = storage_operation_dummy_handler;
+        }
+
+        //Store the peer id.
+        err_code = store_fn(&block_handle,
+                            (uint8_t *)&m_peer_table[p_handle->device_id],
+                            PEER_ID_SIZE,
+                            PEER_ID_STORAGE_OFFSET);
+
+        if ((err_code == NRF_SUCCESS) && (state != UPDATE_PEER_ADDR))
+        {
+            m_connection_table[p_handle->connection_id].state &= (~STATE_BOND_INFO_UPDATE);
+
+            //Store the bond information.
+            err_code = store_fn(&block_handle,
+                                (uint8_t *)&m_bond_table[p_handle->connection_id],
+                                BOND_SIZE,
+                                BOND_STORAGE_OFFSET);
+
+            if (err_code != NRF_SUCCESS)
+            {
+                DM_ERR("[DM]:[0x%02X]:Failed to store bond information, reason 0x%08X\r\n",
+                       p_handle->device_id, err_code);
+            }
+        }
+
+        if (state != UPDATE_PEER_ADDR)
+        {
+            //Store the service information
+            err_code = m_service_context_store[m_application_table[p_handle->appl_id].service]
+                    (
+                        &block_handle,
+                        p_handle
+                    );
+
+            if (err_code != NRF_SUCCESS)
+            {
+                //Notify application of an error event.
+                DM_ERR("[DM]: Failed to store service context, reason %08X\r\n", err_code);
+            }
+        }
+    }
+
+    if (err_code != NRF_SUCCESS)
+    {
+        //Notify application of an error event.
+        DM_ERR("[DM]: Failed to store device context, reason %08X\r\n", err_code);
+    }
+}
+
+
+/**@brief Function for storing when there is no service registered.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is loaded.
+ *
+ * @retval NRF_SUCCESS
+ */
+static __INLINE ret_code_t no_service_context_store(pstorage_handle_t const * p_block_handle,
+                                                    dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]: --> no_service_context_store\r\n");
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for storing GATT Server context.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is stored.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ */
+static __INLINE ret_code_t gatts_context_store(pstorage_handle_t const * p_block_handle,
+                                               dm_handle_t const       * p_handle)
+{
+    storage_operation store_fn;
+    uint32_t          attr_flags = BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS;
+    uint16_t          attr_len   = DM_GATT_SERVER_ATTR_MAX_SIZE;
+    uint8_t           sys_data[DM_GATT_SERVER_ATTR_MAX_SIZE];
+
+    DM_LOG("[DM]: --> gatts_context_store\r\n");
+
+    uint32_t err_code = sd_ble_gatts_sys_attr_get(
+        m_connection_table[p_handle->connection_id].conn_handle,
+        sys_data,
+        &attr_len,
+        attr_flags);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        if (memcmp(m_gatts_table[p_handle->connection_id].attributes, sys_data, attr_len) == 0)
+        {
+            //No store operation is needed.
+            DM_LOG("[DM]:[0x%02X]: No change in GATTS Context information.\r\n",
+                   p_handle->device_id);
+
+            if ((m_connection_table[p_handle->connection_id].state & STATE_CONNECTED) !=
+                STATE_CONNECTED)
+            {
+                DM_LOG("[DM]:[0x%02X]: Resetting GATTS for active instance.\r\n",
+                       p_handle->connection_id);
+
+                //Reset GATTS information for the current context.
+                memset(&m_gatts_table[p_handle->connection_id], 0, sizeof(dm_gatts_context_t));
+            }
+        }
+        else
+        {
+            if (m_gatts_table[p_handle->connection_id].size != 0)
+            {
+                //There is data already stored in persistent memory, therefore an update is needed.
+                DM_LOG("[DM]:[0x%02X]: Updating stored service context\r\n", p_handle->device_id);
+
+                store_fn = pstorage_update;
+            }
+            else
+            {
+                //Fresh write, a store is needed.
+                DM_LOG("[DM]:[0x%02X]: Storing service context\r\n", p_handle->device_id);
+
+                store_fn = pstorage_store;
+            }
+
+            m_gatts_table[p_handle->connection_id].flags = attr_flags;
+            m_gatts_table[p_handle->connection_id].size  = attr_len;
+            memcpy(m_gatts_table[p_handle->connection_id].attributes, sys_data, attr_len);
+
+            DM_DUMP((uint8_t *)&m_gatts_table[p_handle->connection_id], sizeof(dm_gatts_context_t));
+
+            DM_LOG("[DM]:[0x%02X]: GATTS Data size 0x%08X\r\n",
+                   p_handle->device_id,
+                   m_gatts_table[p_handle->connection_id].size);
+
+            //Store GATTS information.
+            err_code = store_fn((pstorage_handle_t *)p_block_handle,
+                                (uint8_t *)&m_gatts_table[p_handle->connection_id],
+                                GATTS_SERVICE_CONTEXT_SIZE,
+                                SERVICE_STORAGE_OFFSET);
+
+            if (err_code != NRF_SUCCESS)
+            {
+                DM_ERR("[DM]:[0x%02X]:Failed to store service context, reason 0x%08X\r\n",
+                       p_handle->device_id,
+                       err_code);
+            }
+            else
+            {
+                DM_LOG("[DM]: Service context successfully stored.\r\n");
+            }
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for storing GATT Client context.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is stored.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ */
+static __INLINE ret_code_t gattc_context_store(pstorage_handle_t const * p_block_handle,
+                                               dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]: --> gattc_context_store\r\n");
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for storing GATT Server & Client context.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is stored.
+ *
+ * @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
+ */
+static __INLINE ret_code_t gattsc_context_store(pstorage_handle_t const * p_block_handle,
+                                                dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]: --> gattsc_context_store\r\n");
+
+    ret_code_t err_code = gatts_context_store(p_block_handle, p_handle);
+
+    if (NRF_SUCCESS == err_code)
+    {
+        err_code = gattc_context_store(p_block_handle, p_handle);
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for loading when there is no service registered.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is loaded.
+ *
+ * @retval NRF_SUCCESS
+ */
+static __INLINE ret_code_t no_service_context_load(pstorage_handle_t const * p_block_handle,
+                                                   dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]: --> no_service_context_load\r\n");
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for loading GATT Server context.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is loaded.
+ *
+ * @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
+ */
+static __INLINE ret_code_t gatts_context_load(pstorage_handle_t const * p_block_handle,
+                                              dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]:[CI 0x%02X]:[DI 0x%02X]: --> gatts_context_load\r\n",
+           p_handle->connection_id,
+           p_handle->device_id);
+
+    ret_code_t err_code = pstorage_load((uint8_t *)&m_gatts_table[p_handle->connection_id],
+                                        (pstorage_handle_t *)p_block_handle,
+                                        GATTS_SERVICE_CONTEXT_SIZE,
+                                        SERVICE_STORAGE_OFFSET);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        DM_LOG("[DM]:[%02X]:[Block ID 0x%08X]: Service context loaded, size 0x%08X\r\n",
+               p_handle->connection_id,
+               p_block_handle->block_id,
+               m_gatts_table[p_handle->connection_id].size);
+        DM_DUMP((uint8_t *)&m_gatts_table[p_handle->connection_id], sizeof(dm_gatts_context_t));
+
+        if (m_gatts_table[p_handle->connection_id].size == DM_GATTS_INVALID_SIZE)
+        {
+            m_gatts_table[p_handle->connection_id].size = 0;
+        }
+    }
+    else
+    {
+        DM_ERR("[DM]:[%02X]: Failed to load Service context, reason %08X\r\n",
+               p_handle->connection_id,
+               err_code);
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for loading GATT Client context.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is loaded.
+ *
+ * @retval NRF_SUCCESS
+ */
+static __INLINE ret_code_t gattc_context_load(pstorage_handle_t const * p_block_handle,
+                                              dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]: --> gattc_context_load\r\n");
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for loading GATT Server & Client context.
+ *
+ * @param[in] p_block_handle Storage block identifier.
+ * @param[in] p_handle       Device handle identifying device that is loaded.
+ *
+ * @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
+ */
+static __INLINE ret_code_t gattsc_context_load(pstorage_handle_t const * p_block_handle,
+                                               dm_handle_t const       * p_handle)
+{
+    DM_LOG("[DM]: --> gattsc_context_load\r\n");
+
+    ret_code_t err_code = gatts_context_load(p_block_handle, p_handle);
+
+    if (NRF_SUCCESS == err_code)
+    {
+        err_code = gattc_context_load(p_block_handle, p_handle);
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for applying when there is no service registered.
+ *
+ * @param[in] p_handle Device handle identifying device that is applied.
+ *
+ * @retval NRF_SUCCESS
+ */
+static __INLINE ret_code_t no_service_context_apply(dm_handle_t * p_handle)
+{
+    DM_LOG("[DM]: --> no_service_context_apply\r\n");
+    DM_LOG("[DM]:[CI 0x%02X]: No Service context\r\n", p_handle->connection_id);
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for applying GATT Server context.
+ *
+ * @param[in] p_handle Device handle identifying device that is applied.
+ *
+ * @retval NRF_SUCCESS                    On success.
+ * @retval DM_SERVICE_CONTEXT_NOT_APPLIED On failure.
+ */
+static __INLINE ret_code_t gatts_context_apply(dm_handle_t * p_handle)
+{
+    uint32_t err_code;
+
+    uint8_t * p_gatts_context = NULL;
+    uint16_t  context_len     = 0;
+    uint32_t  context_flags   = 0;
+
+    DM_LOG("[DM]: --> gatts_context_apply\r\n");
+    DM_LOG("[DM]:[CI 0x%02X]: State 0x%02X, Size 0x%08X\r\n",
+           p_handle->connection_id,
+           m_connection_table[p_handle->connection_id].state,
+           m_gatts_table[p_handle->connection_id].size);
+
+    if ((m_gatts_table[p_handle->connection_id].size != 0) &&
+        (
+            ((m_connection_table[p_handle->connection_id].state & STATE_LINK_ENCRYPTED) == STATE_LINK_ENCRYPTED) &&
+            ((m_connection_table[p_handle->connection_id].state & STATE_BOND_INFO_UPDATE)
+             != STATE_BOND_INFO_UPDATE)
+        )
+       )
+    {
+        DM_LOG("[DM]: Setting stored context.\r\n");
+
+        p_gatts_context = &m_gatts_table[p_handle->connection_id].attributes[0];
+        context_len     = m_gatts_table[p_handle->connection_id].size;
+        context_flags   = m_gatts_table[p_handle->connection_id].flags;
+    }
+
+    err_code = sd_ble_gatts_sys_attr_set(m_connection_table[p_handle->connection_id].conn_handle,
+                                         p_gatts_context,
+                                         context_len,
+                                         context_flags);
+
+    if (err_code == NRF_ERROR_INVALID_DATA)
+    {
+        // Indication that the ATT table has changed. Restore the system attributes to system
+        // services only and send a service changed indication if possible.
+        context_flags = BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS;
+        err_code      = sd_ble_gatts_sys_attr_set(m_connection_table[p_handle->connection_id].conn_handle,
+                                                  p_gatts_context,
+                                                  context_len,
+                                                  context_flags);
+    }
+
+    if (err_code != NRF_SUCCESS)
+    {
+        DM_LOG("[DM]: Failed to set system attributes, reason 0x%08X.\r\n", err_code);
+
+        err_code = DM_SERVICE_CONTEXT_NOT_APPLIED;
+    }
+
+    if (context_flags == BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS)
+    {
+        err_code = sd_ble_gatts_service_changed(m_connection_table[p_handle->connection_id].conn_handle,
+                                                0x000C,
+                                                0xFFFF);
+        if (err_code != NRF_SUCCESS)
+        {
+            DM_LOG("[DM]: Failed to send Service Changed indication, reason 0x%08X.\r\n", err_code);
+            if ((err_code != BLE_ERROR_INVALID_CONN_HANDLE) &&
+                (err_code != NRF_ERROR_INVALID_STATE) &&
+                (err_code != BLE_ERROR_NO_TX_BUFFERS) &&
+                (err_code != NRF_ERROR_BUSY))
+            {
+                // Those errors can be expected when sending trying to send Service Changed
+                // Indication if the CCCD is not set to indicate. Thus set the returning error
+                //  code to success.
+                err_code = NRF_SUCCESS;
+            }
+            else
+            {
+                err_code = DM_SERVICE_CONTEXT_NOT_APPLIED;
+            }
+        }
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for applying GATT Client context.
+ *
+ * @param[in] p_handle Device handle identifying device that is applied.
+ *
+ * @retval NRF_SUCCESS On success.
+ */
+static __INLINE ret_code_t gattc_context_apply(dm_handle_t * p_handle)
+{
+    DM_LOG("[DM]: --> gattc_context_apply\r\n");
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for applying GATT Server & Client context.
+ *
+ * @param[in] p_handle Device handle identifying device that is applied.
+ *
+ * @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
+ */
+static __INLINE ret_code_t gattsc_context_apply(dm_handle_t * p_handle)
+{
+    uint32_t err_code;
+
+    DM_LOG("[DM]: --> gattsc_context_apply\r\n");
+
+    err_code = gatts_context_apply(p_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        err_code = gattc_context_apply(p_handle);
+    }
+
+    return err_code;
+}
+
+
+/**@brief Function for pstorage module callback.
+ *
+ * @param[in] p_handle Identifies module and block for which callback is received.
+ * @param[in] op_code  Identifies the operation for which the event is notified.
+ * @param[in] result   Identifies the result of flash access operation.
+ *                     NRF_SUCCESS implies, operation succeeded.
+ * @param[in] p_data   Identifies the application data pointer. In case of store operation, this
+ *                     points to the resident source of application memory that application can now
+ *                     free or reuse. In case of clear, this is NULL as no application pointer is
+ *                     needed for this operation.
+ * @param[in] data_len Length of data provided by the application for the operation.
+ */
+static void dm_pstorage_cb_handler(pstorage_handle_t * p_handle,
+                                   uint8_t             op_code,
+                                   uint32_t            result,
+                                   uint8_t           * p_data,
+                                   uint32_t            data_len)
+{
+    VERIFY_APP_REGISTERED_VOID(0);
+
+    if (data_len > ALL_CONTEXT_SIZE)
+    {
+        //Clearing of all bonds at initialization, no event is generated.
+        return;
+    }
+
+    DM_MUTEX_LOCK();
+
+    dm_event_t        dm_event;
+    dm_handle_t       dm_handle;
+    dm_context_t      context_data;
+    pstorage_handle_t block_handle;
+    uint32_t          index_count;
+    uint32_t          err_code;
+
+    bool app_notify = true;
+
+    err_code = dm_handle_initialize(&dm_handle);
+    APP_ERROR_CHECK(err_code);
+
+    dm_handle.appl_id = 0;
+    dm_event.event_id = 0x00;
+
+    //Construct the event which it is related to.
+
+    //Initialize context data information and length.
+    context_data.p_data = p_data;
+    context_data.len    = data_len;
+
+    for (uint32_t index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+    {
+        err_code = pstorage_block_identifier_get(&m_storage_handle, index, &block_handle);
+        if ((err_code == NRF_SUCCESS) &&
+            (
+                (memcmp(p_handle, &block_handle, sizeof(pstorage_handle_t)) == 0)
+            )
+           )
+        {
+            dm_handle.device_id = index;
+            break;
+        }
+    }
+
+    if (dm_handle.device_id != DM_INVALID_ID)
+    {
+        if (op_code == PSTORAGE_CLEAR_OP_CODE)
+        {
+            if (data_len == ALL_CONTEXT_SIZE)
+            {
+                dm_event.event_id = DM_EVT_DEVICE_CONTEXT_BASE;
+            }
+            else
+            {
+                dm_event.event_id = DM_EVT_APP_CONTEXT_BASE;
+            }
+        }
+        else
+        {
+            //Update or store operation.
+            //Context is identified based on the pointer value. Device context, application context
+            //and service context all have their own value range.
+            index_count = ((uint32_t)(p_data - (uint8_t *)m_peer_table)) / PEER_ID_SIZE;
+
+            if (index_count < DEVICE_MANAGER_MAX_BONDS)
+            {
+                dm_event.event_param.p_device_context = &context_data;
+
+                //Only the peer identification is stored, not bond information. Hence do not notify
+                //the application yet, unless the store operation resulted in a failure.
+                if ((result == NRF_SUCCESS) &&
+                    (
+                        (update_status_bit_is_set(dm_handle.device_id) == false)
+                    )
+                   )
+                {
+                    app_notify = false;
+                }
+                else
+                {
+                    //Reset update status since update is complete.
+                    update_status_bit_reset(dm_handle.device_id);
+
+                    //Notify application of error in storing the context.
+                    dm_event.event_id = DM_EVT_DEVICE_CONTEXT_BASE;
+                }
+            }
+            else
+            {
+                index_count = ((uint32_t)(p_data - (uint8_t *)m_bond_table)) / BOND_SIZE;
+
+                if (index_count < DEVICE_MANAGER_MAX_CONNECTIONS)
+                {
+                    DM_LOG("[DM]:[0x%02X]:[0x%02X]: Bond context Event\r\n",
+                           dm_handle.device_id,
+                           dm_handle.connection_id);
+
+                    dm_event.event_param.p_device_context = &context_data;
+                    dm_event.event_id                     = DM_EVT_DEVICE_CONTEXT_BASE;
+                    dm_handle.connection_id               = index_count;
+
+                    ble_gap_sec_keyset_t keys_exchanged;
+                    keys_exchanged.keys_central.p_enc_key = NULL;
+                    keys_exchanged.keys_central.p_id_key  = &m_local_id_info;
+                    keys_exchanged.keys_periph.p_enc_key  = &m_bond_table[index_count].peer_enc_key;
+                    keys_exchanged.keys_periph.p_id_key   =
+                        &m_peer_table[dm_handle.device_id].peer_id;
+
+                    //Context information updated to provide the keys.
+                    context_data.p_data = (uint8_t *)&keys_exchanged;
+                    context_data.len    = sizeof(ble_gap_sec_keyset_t);
+                }
+                else
+                {
+                    index_count = ((uint32_t)(p_data - (uint8_t *)m_gatts_table)) /
+                                  GATTS_SERVICE_CONTEXT_SIZE;
+
+                    if (index_count < DEVICE_MANAGER_MAX_CONNECTIONS)
+                    {
+                        DM_LOG("[DM]:[0x%02X]:[0x%02X]: Service context Event\r\n",
+                               dm_handle.device_id,
+                               dm_handle.connection_id);
+
+                        //Notify application.
+                        dm_event.event_id       = DM_EVT_SERVICE_CONTEXT_BASE;
+                        dm_handle.connection_id = index_count;
+                        dm_handle.service_id    = DM_PROTOCOL_CNTXT_GATT_SRVR_ID;
+
+                        //Reset the service context now that it was successfully written to the
+                        //application and the link is disconnected.
+                        if ((m_connection_table[index_count].state & STATE_CONNECTED) !=
+                            STATE_CONNECTED)
+                        {
+                            DM_LOG("[DM]:[0x%02X]:[0x%02X]: Resetting bond information for "
+                                   "active instance.\r\n",
+                                   dm_handle.device_id,
+                                   dm_handle.connection_id);
+
+                            memset(&m_gatts_table[dm_handle.connection_id],
+                                   0,
+                                   sizeof(dm_gatts_context_t));
+                        }
+                    }
+                    else
+                    {
+                        DM_LOG("[DM]:[0x%02X]:[0x%02X]: App context Event\r\n",
+                               dm_handle.device_id,
+                               dm_handle.connection_id);
+
+                        app_notify        = false;
+                        dm_event.event_id = DM_EVT_APP_CONTEXT_BASE;
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+
+                        if (p_data == (uint8_t *)(&m_context_init_len))
+                        {
+                            //Context data is deleted.
+                            //This is a workaround to get the right event as on delete operation
+                            //update operation is used instead of clear.
+                            op_code    = PSTORAGE_CLEAR_OP_CODE;
+                            app_notify = true;
+                        }
+                        else if (m_app_context_table[dm_handle.device_id] == p_data)
+                        {
+                            app_notify                         = true;
+                            dm_event.event_param.p_app_context = &context_data;
+
+                            //Verify if the device is connected, if yes set connection instance.
+                            for (uint32_t index = 0;
+                                 index < DEVICE_MANAGER_MAX_CONNECTIONS;
+                                 index++)
+                            {
+                                if (dm_handle.device_id == m_connection_table[index].bonded_dev_id)
+                                {
+                                    dm_handle.connection_id = index;
+                                    break;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            //No implementation needed.
+                        }
+#endif //DEVICE_MANAGER_APP_CONTEXT_SIZE
+                    }
+                }
+            }
+        }
+
+        if (app_notify == true)
+        {
+            if (op_code == PSTORAGE_CLEAR_OP_CODE)
+            {
+                dm_event.event_id |= DM_CLEAR_OPERATION_ID;
+            }
+            else if (op_code == PSTORAGE_LOAD_OP_CODE)
+            {
+                dm_event.event_id |= DM_LOAD_OPERATION_ID;
+            }
+            else
+            {
+                dm_event.event_id |= DM_STORE_OPERATION_ID;
+            }
+
+            dm_event.event_param.p_app_context = &context_data;
+            app_evt_notify(&dm_handle, &dm_event, result);
+        }
+    }
+
+    DM_MUTEX_UNLOCK();
+}
+
+
+ret_code_t dm_init(dm_init_param_t const * const p_init_param)
+{
+    pstorage_module_param_t param;
+    pstorage_handle_t       block_handle;
+    ret_code_t              err_code;
+    uint32_t                index;
+
+    DM_LOG("[DM]: >> dm_init.\r\n");
+
+    NULL_PARAM_CHECK(p_init_param);
+
+    SDK_MUTEX_INIT(m_dm_mutex);
+
+    DM_MUTEX_LOCK();
+
+    for (index = 0; index < DEVICE_MANAGER_MAX_APPLICATIONS; index++)
+    {
+        application_instance_init(index);
+    }
+
+    for (index = 0; index < DEVICE_MANAGER_MAX_CONNECTIONS; index++)
+    {
+        connection_instance_init(index);
+    }
+
+    memset(m_gatts_table, 0, sizeof(m_gatts_table));
+
+    //Initialization of all device instances.
+    for (index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+    {
+        peer_instance_init(index);
+        m_irk_index_table[index] = DM_INVALID_ID;
+    }
+
+    //All context with respect to a particular device is stored contiguously.
+    param.block_size  = ALL_CONTEXT_SIZE;
+    param.block_count = DEVICE_MANAGER_MAX_BONDS;
+    param.cb          = dm_pstorage_cb_handler;
+
+    err_code = pstorage_register(&param, &m_storage_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        m_module_initialized = true;
+
+        if (p_init_param->clear_persistent_data == false)
+        {
+            DM_LOG("[DM]: Storage handle 0x%08X.\r\n", m_storage_handle.block_id);
+
+            //Copy bonded peer device address and IRK to RAM table.
+
+            //Bonded devices are stored in range (0,DEVICE_MANAGER_MAX_BONDS-1). The remaining
+            //range is for active connections that may or may not be bonded.
+            for (index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+            {
+                err_code = pstorage_block_identifier_get(&m_storage_handle, index, &block_handle);
+
+                //Issue read request if you successfully get the block identifier.
+                if (err_code == NRF_SUCCESS)
+                {
+                    DM_TRC("[DM]:[0x%02X]: Block handle 0x%08X.\r\n", index, block_handle.block_id);
+
+                    err_code = pstorage_load((uint8_t *)&m_peer_table[index],
+                                             &block_handle,
+                                             sizeof(peer_id_t),
+                                             0);
+
+                    if (err_code != NRF_SUCCESS)
+                    {
+                        // In case a peer device could not be loaded successfully, rest of the
+                        // initialization procedure are skipped and an error is sent to the
+                        // application.
+                        DM_ERR(
+                            "[DM]: Failed to load peer device %08X from storage, reason %08X.\r\n",
+                            index,
+                            err_code);
+
+                        m_module_initialized = false;
+                        break;
+                    }
+                    else
+                    {
+                        DM_TRC("[DM]:[DI 0x%02X]: Device type 0x%02X.\r\n",
+                               index,
+                               m_peer_table[index].peer_id.id_addr_info.addr_type);
+                        DM_TRC("[DM]: Device Addr 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X.\r\n",
+                               m_peer_table[index].peer_id.id_addr_info.addr[0],
+                               m_peer_table[index].peer_id.id_addr_info.addr[1],
+                               m_peer_table[index].peer_id.id_addr_info.addr[2],
+                               m_peer_table[index].peer_id.id_addr_info.addr[3],
+                               m_peer_table[index].peer_id.id_addr_info.addr[4],
+                               m_peer_table[index].peer_id.id_addr_info.addr[5]);
+                    }
+                }
+                else
+                {
+                    //In case a peer device could not be loaded successfully, rest of the
+                    //initialization procedure are skipped and an error is sent to the application.
+                    DM_LOG("[DM]: Failed to get block handle for instance %08X, reason %08X.\r\n",
+                           index,
+                           err_code);
+
+                    m_module_initialized = false;
+                    break;
+                }
+            }
+        }
+        else
+        {
+            err_code = pstorage_clear(&m_storage_handle, (param.block_size * param.block_count));
+            DM_ERR("[DM]: Successfully requested clear of persistent data.\r\n");
+        }
+    }
+    else
+    {
+        DM_ERR("[DM]: Failed to register with storage module, reason 0x%08X.\r\n", err_code);
+    }
+
+    DM_MUTEX_UNLOCK();
+
+    DM_TRC("[DM]: << dm_init.\r\n");
+
+    return err_code;
+}
+
+
+ret_code_t dm_register(dm_application_instance_t    * p_appl_instance,
+                       dm_application_param_t const * p_appl_param)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_appl_instance);
+    NULL_PARAM_CHECK(p_appl_param);
+    NULL_PARAM_CHECK(p_appl_param->evt_handler);
+
+    DM_MUTEX_LOCK();
+
+    DM_LOG("[DM]: >> dm_register.\r\n");
+
+    uint32_t err_code;
+
+    //Verify if an application instance is available. Currently only one instance is supported.
+    if (m_application_table[0].ntf_cb == NULL)
+    {
+        DM_LOG("[DM]: Application Instance allocated.\r\n");
+
+        //Mark instance as allocated.
+        m_application_table[0].ntf_cb    = p_appl_param->evt_handler;
+        m_application_table[0].sec_param = p_appl_param->sec_param;
+        m_application_table[0].service   = p_appl_param->service_type;
+
+        m_application_table[0].sec_param.kdist_central.enc  = 0;
+        m_application_table[0].sec_param.kdist_central.id   = 1;
+        m_application_table[0].sec_param.kdist_central.sign = 0;
+        m_application_table[0].sec_param.kdist_periph.enc   = 1;
+        m_application_table[0].sec_param.kdist_periph.id    = 1;
+        m_application_table[0].sec_param.kdist_periph.sign  = 0;
+        //Populate application's instance variable with the assigned allocation instance.
+        *p_appl_instance = 0;
+        err_code         = NRF_SUCCESS;
+    }
+    else
+    {
+        err_code = (NRF_ERROR_NO_MEM | DEVICE_MANAGER_ERR_BASE);
+    }
+
+    DM_MUTEX_UNLOCK();
+
+    DM_TRC("[DM]: << dm_register.\r\n");
+
+    return err_code;
+}
+
+
+ret_code_t dm_security_setup_req(dm_handle_t * p_handle)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_CONNECTION_INSTANCE(p_handle->connection_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_LOG("[DM]: >> dm_security_setup_req\r\n");
+
+    uint32_t err_code = (NRF_ERROR_INVALID_STATE | DEVICE_MANAGER_ERR_BASE);
+
+    if ((m_connection_table[p_handle->connection_id].state & STATE_CONNECTED) == STATE_CONNECTED)
+    {
+        err_code = sd_ble_gap_authenticate(m_connection_table[p_handle->connection_id].conn_handle,
+                                           &m_application_table[0].sec_param);
+    }
+
+    DM_TRC("[DM]: << dm_security_setup_req, 0x%08X\r\n", err_code);
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_security_status_req(dm_handle_t const    * p_handle,
+                                  dm_security_status_t * p_status)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_status);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_CONNECTION_INSTANCE(p_handle->connection_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_LOG("[DM]: >> dm_security_status_req\r\n");
+
+    if ((m_connection_table[p_handle->connection_id].state & STATE_PAIRING) ||
+        (m_connection_table[p_handle->connection_id].state & STATE_PAIRING_PENDING))
+    {
+        (*p_status) = ENCRYPTION_IN_PROGRESS;
+    }
+    else if (m_connection_table[p_handle->connection_id].state & STATE_LINK_ENCRYPTED)
+    {
+        (*p_status) = ENCRYPTED;
+    }
+    else
+    {
+        (*p_status) = NOT_ENCRYPTED;
+    }
+
+    DM_TRC("[DM]: << dm_security_status_req\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return NRF_SUCCESS;
+}
+
+
+ret_code_t dm_whitelist_create(dm_application_instance_t const * p_handle,
+                               ble_gap_whitelist_t             * p_whitelist)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_whitelist);
+    NULL_PARAM_CHECK(p_whitelist->pp_addrs);
+    NULL_PARAM_CHECK(p_whitelist->pp_irks);
+    VERIFY_APP_REGISTERED(*p_handle);
+
+    DM_MUTEX_LOCK();
+
+    DM_LOG("[DM]: >> dm_whitelist_create\r\n");
+
+    uint32_t addr_count = 0;
+    uint32_t irk_count  = 0;
+    bool     connected  = false;
+
+    for (uint32_t index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+    {
+        connected = false;
+
+        for (uint32_t c_index = 0; c_index < DEVICE_MANAGER_MAX_CONNECTIONS; c_index++)
+        {
+            if ((index == m_connection_table[c_index].bonded_dev_id) &&
+                ((m_connection_table[c_index].state & STATE_CONNECTED) == STATE_CONNECTED))
+            {
+                connected = true;
+                break;
+            }
+        }
+
+        if (connected == false)
+        {
+            if ((irk_count < p_whitelist->irk_count) &&
+                ((m_peer_table[index].id_bitmap & IRK_ENTRY) == 0))
+            {
+                p_whitelist->pp_irks[irk_count] = &m_peer_table[index].peer_id.id_info;
+                m_irk_index_table[irk_count]    = index;
+                irk_count++;
+            }
+
+            if ((addr_count < p_whitelist->addr_count) &&
+                (m_peer_table[index].id_bitmap & ADDR_ENTRY) == 0)
+            {
+                p_whitelist->pp_addrs[addr_count] = &m_peer_table[index].peer_id.id_addr_info;
+                addr_count++;
+            }
+        }
+    }
+
+    p_whitelist->addr_count = addr_count;
+    p_whitelist->irk_count  = irk_count;
+
+    DM_LOG("[DM]: Created whitelist, number of IRK = 0x%02X, number of addr = 0x%02X\r\n",
+           irk_count,
+           addr_count);
+
+    DM_TRC("[DM]: << dm_whitelist_create\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return NRF_SUCCESS;
+}
+
+
+ret_code_t dm_device_add(dm_handle_t               * p_handle,
+                         dm_device_context_t const * p_context)
+{
+    return (API_NOT_IMPLEMENTED | DEVICE_MANAGER_ERR_BASE);
+}
+
+
+ret_code_t dm_device_delete(dm_handle_t const * p_handle)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_device_delete\r\n");
+
+    uint32_t err_code = device_instance_free(p_handle->device_id);
+
+    DM_TRC("[DM]: << dm_device_delete\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_device_delete_all(dm_application_instance_t const * p_handle)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    VERIFY_APP_REGISTERED((*p_handle));
+
+    DM_MUTEX_LOCK();
+
+    uint32_t err_code = NRF_SUCCESS;
+
+    DM_TRC("[DM]: >> dm_device_delete_all\r\n");
+
+    for (uint32_t index = 0; index < DEVICE_MANAGER_MAX_BONDS; index++)
+    {
+        if (m_peer_table[index].id_bitmap != UNASSIGNED)
+        {
+            err_code = device_instance_free(index);
+        }
+    }
+
+    DM_TRC("[DM]: << dm_device_delete_all\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_service_context_set(dm_handle_t const          * p_handle,
+                                  dm_service_context_t const * p_context)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_context);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_CONNECTION_INSTANCE(p_handle->connection_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_service_context_set\r\n");
+
+    if ((p_context->context_data.p_data != NULL) &&
+        (
+            (p_context->context_data.len != 0) &&
+            (p_context->context_data.len < DM_GATT_SERVER_ATTR_MAX_SIZE)
+        )
+       )
+    {
+        if (p_context->service_type == DM_PROTOCOL_CNTXT_GATT_SRVR_ID)
+        {
+            memcpy(m_gatts_table[p_handle->connection_id].attributes,
+                   p_context->context_data.p_data,
+                   p_context->context_data.len);
+        }
+    }
+
+    pstorage_handle_t block_handle;
+    uint32_t          err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                                               p_handle->device_id,
+                                                               &block_handle);
+
+    err_code = m_service_context_store[p_context->service_type](&block_handle, p_handle);
+
+    DM_TRC("[DM]: << dm_service_context_set\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_service_context_get(dm_handle_t const    * p_handle,
+                                  dm_service_context_t * p_context)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_context);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    if ((m_connection_table[p_handle->connection_id].state & STATE_CONNECTED) != STATE_CONNECTED)
+    {
+        DM_TRC("[DM]: Device must be connected to get context. \r\n");
+
+        return (FEATURE_NOT_ENABLED | DEVICE_MANAGER_ERR_BASE);
+    }
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_service_context_get\r\n");
+
+    if ((p_context->context_data.p_data == NULL) &&
+        (p_context->context_data.len < DM_GATT_SERVER_ATTR_MAX_SIZE))
+    {
+        if (p_context->service_type == DM_PROTOCOL_CNTXT_GATT_SRVR_ID)
+        {
+            p_context->context_data.p_data = m_gatts_table[p_handle->connection_id].attributes;
+            p_context->context_data.len    = m_gatts_table[p_handle->connection_id].size;
+        }
+    }
+
+    pstorage_handle_t block_handle;
+    uint32_t          err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                                               p_handle->device_id,
+                                                               &block_handle);
+
+    err_code = m_service_context_load[p_context->service_type](&block_handle, p_handle);
+
+    DM_TRC("[DM]: << dm_service_context_get\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_service_context_delete(dm_handle_t const * p_handle)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_LOG("[DM]: Context delete is not supported yet.\r\n");
+
+    return (API_NOT_IMPLEMENTED | DEVICE_MANAGER_ERR_BASE);
+}
+
+
+ret_code_t dm_application_context_set(dm_handle_t const              * p_handle,
+                                      dm_application_context_t const * p_context)
+{
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_context);
+    NULL_PARAM_CHECK(p_context->p_data);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+    VERIFY_DEVICE_BOND(p_handle->connection_id);
+    SIZE_CHECK_APP_CONTEXT(p_context->len);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_application_context_set\r\n");
+
+    uint32_t          err_code;
+    uint32_t          context_len;
+    pstorage_handle_t block_handle;
+
+    storage_operation store_fn = pstorage_store;
+
+    err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                             p_handle->device_id,
+                                             &block_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        err_code = pstorage_load((uint8_t *)&context_len,
+                                 &block_handle,
+                                 sizeof(uint32_t),
+                                 APP_CONTEXT_STORAGE_OFFSET);
+
+        if ((err_code == NRF_SUCCESS) && (context_len != INVALID_CONTEXT_LEN))
+        {
+            //Data already exists. Need an update.
+            store_fn = pstorage_update;
+
+            DM_LOG("[DM]:[DI 0x%02X]: Updating existing application context, existing len 0x%08X, "
+                   "new length 0x%08X.\r\n",
+                   p_handle->device_id,
+                   context_len,
+                   p_context->len);
+        }
+        else
+        {
+            DM_LOG("[DM]: Storing application context.\r\n");
+        }
+
+        //Store/update context length.
+        err_code = store_fn(&block_handle,
+                            (uint8_t *)(&p_context->len),
+                            sizeof(uint32_t),
+                            APP_CONTEXT_STORAGE_OFFSET);
+
+        if (err_code == NRF_SUCCESS)
+        {
+            //Update context data is used for application context as flash is never
+            //cleared if a delete of application context is called.
+            err_code = pstorage_update(&block_handle,
+                                       p_context->p_data,
+                                       DEVICE_MANAGER_APP_CONTEXT_SIZE,
+                                       (APP_CONTEXT_STORAGE_OFFSET + sizeof(uint32_t)));
+            if (err_code == NRF_SUCCESS)
+            {
+                m_app_context_table[p_handle->device_id] = p_context->p_data;
+            }
+        }
+    }
+
+    DM_TRC("[DM]: << dm_application_context_set\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+
+#else //DEVICE_MANAGER_APP_CONTEXT_SIZE
+    return (FEATURE_NOT_ENABLED | DEVICE_MANAGER_ERR_BASE);
+#endif //DEVICE_MANAGER_APP_CONTEXT_SIZE
+}
+
+
+ret_code_t dm_application_context_get(dm_handle_t const        * p_handle,
+                                      dm_application_context_t * p_context)
+{
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_context);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_application_context_get\r\n");
+
+    uint32_t          context_len;
+    uint32_t          err_code;
+    pstorage_handle_t block_handle;
+
+    //Check if the context exists.
+    if (NULL == p_context->p_data)
+    {
+        p_context->p_data = m_app_context_table[p_handle->device_id];
+    }
+    else
+    {
+        m_app_context_table[p_handle->device_id] = p_context->p_data;
+    }
+
+    err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                             p_handle->device_id,
+                                             &block_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        err_code = pstorage_load((uint8_t *)&context_len,
+                                 &block_handle,
+                                 sizeof(uint32_t),
+                                 APP_CONTEXT_STORAGE_OFFSET);
+
+        if ((err_code == NRF_SUCCESS) && (context_len != INVALID_CONTEXT_LEN))
+        {
+            err_code = pstorage_load(p_context->p_data,
+                                     &block_handle,
+                                     DEVICE_MANAGER_APP_CONTEXT_SIZE,
+                                     (APP_CONTEXT_STORAGE_OFFSET + sizeof(uint32_t)));
+            if (err_code == NRF_SUCCESS)
+            {
+                p_context->len = context_len;
+            }
+        }
+        else
+        {
+            err_code = DM_NO_APP_CONTEXT;
+        }
+    }
+
+    DM_TRC("[DM]: << dm_application_context_get\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+
+#else //DEVICE_MANAGER_APP_CONTEXT_SIZE
+    return (FEATURE_NOT_ENABLED | DEVICE_MANAGER_ERR_BASE);
+#endif //DEVICE_MANAGER_APP_CONTEXT_SIZE
+}
+
+
+ret_code_t dm_application_context_delete(const dm_handle_t * p_handle)
+{
+#if (DEVICE_MANAGER_APP_CONTEXT_SIZE != 0)
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_application_context_delete\r\n");
+
+    uint32_t          err_code;
+    uint32_t          context_len;
+    pstorage_handle_t block_handle;
+
+    err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                             p_handle->device_id,
+                                             &block_handle);
+
+    if (err_code == NRF_SUCCESS)
+    {
+        err_code = pstorage_load((uint8_t *)&context_len,
+                                 &block_handle,
+                                 sizeof(uint32_t),
+                                 APP_CONTEXT_STORAGE_OFFSET);
+
+        if (context_len != m_context_init_len)
+        {
+            err_code = pstorage_update(&block_handle,
+                                       (uint8_t *)&m_context_init_len,
+                                       sizeof(uint32_t),
+                                       APP_CONTEXT_STORAGE_OFFSET);
+
+            if (err_code != NRF_SUCCESS)
+            {
+                DM_ERR("[DM]: Failed to delete application context, reason 0x%08X\r\n", err_code);
+            }
+            else
+            {
+                m_app_context_table[p_handle->device_id] = NULL;
+            }
+        }
+    }
+
+    DM_TRC("[DM]: << dm_application_context_delete\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+#else //DEVICE_MANAGER_APP_CONTEXT_SIZE
+    return (FEATURE_NOT_ENABLED | DEVICE_MANAGER_ERR_BASE);
+#endif //DEVICE_MANAGER_APP_CONTEXT_SIZE
+}
+
+
+ret_code_t dm_application_instance_set(dm_application_instance_t const * p_appl_instance,
+                                       dm_handle_t                     * p_handle)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_appl_instance);
+    VERIFY_APP_REGISTERED((*p_appl_instance));
+
+    p_handle->appl_id = (*p_appl_instance);
+
+    return NRF_SUCCESS;
+}
+
+
+uint32_t dm_handle_initialize(dm_handle_t * p_handle)
+{
+    NULL_PARAM_CHECK(p_handle);
+
+    p_handle->appl_id       = DM_INVALID_ID;
+    p_handle->connection_id = DM_INVALID_ID;
+    p_handle->device_id     = DM_INVALID_ID;
+    p_handle->service_id    = DM_INVALID_ID;
+
+    return NRF_SUCCESS;
+}
+
+
+ret_code_t dm_peer_addr_set(dm_handle_t const    * p_handle,
+                            ble_gap_addr_t const * p_addr)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_addr);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_peer_addr_set\r\n");
+
+    ret_code_t err_code;
+
+    if ((p_handle->connection_id == DM_INVALID_ID) &&
+        (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE))
+    {
+        m_peer_table[p_handle->device_id].peer_id.id_addr_info = (*p_addr);
+        update_status_bit_set(p_handle->device_id);
+        device_context_store(p_handle, UPDATE_PEER_ADDR);
+        err_code = NRF_SUCCESS;
+    }
+    else
+    {
+        err_code = (NRF_ERROR_INVALID_PARAM | DEVICE_MANAGER_ERR_BASE);
+    }
+
+    DM_TRC("[DM]: << dm_peer_addr_set\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_peer_addr_get(dm_handle_t const * p_handle,
+                            ble_gap_addr_t    * p_addr)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_addr);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_peer_addr_get\r\n");
+
+    ret_code_t err_code;
+
+    err_code = (NRF_ERROR_NOT_FOUND | DEVICE_MANAGER_ERR_BASE);
+
+    if (p_handle->device_id == DM_INVALID_ID)
+    {
+        if ((p_handle->connection_id != DM_INVALID_ID) &&
+            ((m_connection_table[p_handle->connection_id].state & STATE_CONNECTED) ==
+             STATE_CONNECTED))
+        {
+            DM_TRC("[DM]:[CI 0x%02X]: Address get for non bonded active connection.\r\n",
+                   p_handle->connection_id);
+
+            (*p_addr) = m_connection_table[p_handle->connection_id].peer_addr;
+            err_code  = NRF_SUCCESS;
+        }
+    }
+    else
+    {
+        if ((m_peer_table[p_handle->device_id].id_bitmap & ADDR_ENTRY) == 0)
+        {
+            DM_TRC("[DM]:[DI 0x%02X]: Address get for bonded device.\r\n",
+                   p_handle->device_id);
+
+            (*p_addr) = m_peer_table[p_handle->device_id].peer_id.id_addr_info;
+            err_code  = NRF_SUCCESS;
+        }
+    }
+
+    DM_TRC("[DM]: << dm_peer_addr_get\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+ret_code_t dm_distributed_keys_get(dm_handle_t const * p_handle,
+                                   dm_sec_keyset_t   * p_key_dist)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_handle);
+    NULL_PARAM_CHECK(p_key_dist);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+    VERIFY_DEVICE_INSTANCE(p_handle->device_id);
+
+    DM_MUTEX_LOCK();
+
+    DM_TRC("[DM]: >> dm_distributed_keys_get\r\n");
+
+    ret_code_t        err_code;
+    ble_gap_enc_key_t peer_enc_key;
+    pstorage_handle_t block_handle;
+
+    err_code                                   = NRF_ERROR_NOT_FOUND;
+    p_key_dist->keys_central.enc_key.p_enc_key = NULL;
+    p_key_dist->keys_central.p_id_key          = (dm_id_key_t *)&m_peer_table[p_handle->device_id].peer_id;
+    p_key_dist->keys_central.p_sign_key        = NULL;
+    p_key_dist->keys_periph.p_id_key           = (dm_id_key_t *)&m_local_id_info;
+    p_key_dist->keys_periph.p_sign_key         = NULL;
+    p_key_dist->keys_periph.enc_key.p_enc_key  = (dm_enc_key_t *)&peer_enc_key;
+
+    if ((m_peer_table[p_handle->device_id].id_bitmap & IRK_ENTRY) == 0)
+    {
+//        p_key_dist->keys_periph.p_id_key->id_addr_info.addr_type = INVALID_ADDR_TYPE;
+    }
+
+    err_code = pstorage_block_identifier_get(&m_storage_handle, p_handle->device_id, &block_handle);
+    if (err_code == NRF_SUCCESS)
+    {
+
+        err_code = pstorage_load((uint8_t *)&peer_enc_key,
+                                 &block_handle,
+                                 BOND_SIZE,
+                                 BOND_STORAGE_OFFSET);
+
+        if (err_code == NRF_SUCCESS)
+        {
+            p_key_dist->keys_central.enc_key.p_enc_key = NULL;
+            p_key_dist->keys_central.p_id_key          = (dm_id_key_t *)&m_peer_table[p_handle->device_id].peer_id;
+            p_key_dist->keys_central.p_sign_key        = NULL;
+            p_key_dist->keys_periph.p_id_key           = (dm_id_key_t *)&m_local_id_info;
+            p_key_dist->keys_periph.p_sign_key         = NULL;
+            p_key_dist->keys_periph.enc_key.p_enc_key  = (dm_enc_key_t *)&peer_enc_key;
+        }
+    }
+
+    DM_TRC("[DM]: << dm_distributed_keys_get\r\n");
+
+    DM_MUTEX_UNLOCK();
+
+    return err_code;
+}
+
+
+/**@brief Function for loading bond information for a connection instance.
+ */
+void bond_data_load(dm_handle_t * p_handle)
+{
+    pstorage_handle_t block_handle;
+
+    uint32_t err_code = pstorage_block_identifier_get(&m_storage_handle,
+                                                       p_handle->device_id,
+                                                       &block_handle);
+    if (err_code == NRF_SUCCESS)
+    {
+        DM_LOG(
+            "[DM]:[%02X]:[Block ID 0x%08X]:Loading bond information at %p, size 0x%08X, offset 0x%08X.\r\n",
+            p_handle->connection_id,
+            block_handle.block_id,
+            &m_bond_table[p_handle->connection_id],
+            BOND_SIZE,
+            BOND_STORAGE_OFFSET);
+
+        err_code = pstorage_load((uint8_t *)&m_bond_table[p_handle->connection_id],
+                                 &block_handle,
+                                 BOND_SIZE,
+                                 BOND_STORAGE_OFFSET);
+
+        if (err_code != NRF_SUCCESS)
+        {
+            DM_ERR("[DM]:[%02X]: Failed to load Bond information, reason %08X\r\n",
+                   p_handle->connection_id,
+                   err_code);
+        }
+
+        DM_LOG(
+            "[DM]:[%02X]:Loading service context at %p, size 0x%08X, offset 0x%08X.\r\n",
+            p_handle->connection_id,
+            &m_gatts_table[p_handle->connection_id],
+            sizeof(dm_gatts_context_t),
+            SERVICE_STORAGE_OFFSET);
+
+        err_code = m_service_context_load[m_application_table[0].service](
+            &block_handle,
+            p_handle);
+
+        if (err_code != NRF_SUCCESS)
+        {
+            DM_ERR(
+                "[DM]:[%02X]: Failed to load service information, reason %08X\r\n",
+                p_handle->connection_id,
+                err_code);
+        }
+    }
+    else
+    {
+        DM_ERR("[DM]:[%02X]: Failed to get block identifier for "
+               "device %08X, reason %08X.\r\n", p_handle->connection_id, p_handle->device_id, err_code);
+    }
+}
+
+
+void dm_ble_evt_handler(ble_evt_t * p_ble_evt)
+{
+    uint32_t    err_code;
+    uint32_t    index;
+    uint32_t    device_index        = DM_INVALID_ID;
+    bool        notify_app          = false;
+    dm_handle_t handle;
+    dm_event_t  event;
+    uint32_t    event_result;
+    ble_gap_enc_info_t * p_enc_info = NULL;
+
+    VERIFY_MODULE_INITIALIZED_VOID();
+    VERIFY_APP_REGISTERED_VOID(0);
+    DM_MUTEX_LOCK();
+
+    err_code = dm_handle_initialize(&handle);
+    APP_ERROR_CHECK(err_code);
+
+    event_result                    = NRF_SUCCESS;
+    err_code                        = NRF_SUCCESS;
+    event.event_param.p_gap_param   = &p_ble_evt->evt.gap_evt;
+    event.event_paramlen            = sizeof(ble_gap_evt_t);
+    handle.device_id                = DM_INVALID_ID;
+    handle.appl_id                  = 0;
+    index                           = 0x00;
+
+    if (p_ble_evt->header.evt_id != BLE_GAP_EVT_CONNECTED)
+    {
+        err_code = connection_instance_find(p_ble_evt->evt.gap_evt.conn_handle,
+                                            STATE_CONNECTED,
+                                            &index);
+
+        if (err_code == NRF_SUCCESS)
+        {
+            handle.device_id     = m_connection_table[index].bonded_dev_id;
+            handle.connection_id = index;
+        }
+    }
+
+    switch (p_ble_evt->header.evt_id)
+    {
+        case BLE_GAP_EVT_CONNECTED:
+            //Allocate connection instance for a new connection.
+            err_code = connection_instance_allocate(&index);
+
+            //Connection instance is successfully allocated.
+            if (err_code == NRF_SUCCESS)
+            {
+                //Application notification related information.
+                notify_app           = true;
+                event.event_id       = DM_EVT_CONNECTION;
+                handle.connection_id = index;
+
+                m_connection_table[index].conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+                m_connection_table[index].state       = STATE_CONNECTED;
+                m_connection_table[index].peer_addr   =
+                    p_ble_evt->evt.gap_evt.params.connected.peer_addr;
+
+                if (p_ble_evt->evt.gap_evt.params.connected.irk_match == 1)
+                {
+                    if (m_irk_index_table[p_ble_evt->evt.gap_evt.params.connected.irk_match_idx] != DM_INVALID_ID)
+                    {
+                        device_index = m_irk_index_table[p_ble_evt->evt.gap_evt.params.connected.irk_match_idx];
+                        err_code = NRF_SUCCESS;
+                    }
+                }
+                else
+                {
+                    //Use the device address to check if the device exists in the bonded device list.
+                    err_code = device_instance_find(&p_ble_evt->evt.gap_evt.params.connected.peer_addr,
+                                                    &device_index, EDIV_INIT_VAL);
+                }
+
+                if (err_code == NRF_SUCCESS)
+                {
+                    m_connection_table[index].bonded_dev_id = device_index;
+                    m_connection_table[index].state        |= STATE_BONDED;
+                    handle.device_id                        = device_index;
+
+                    bond_data_load(&handle);
+                }
+            }
+            break;
+
+        case BLE_GAP_EVT_DISCONNECTED:
+            //Disconnection could be peer or self initiated hence disconnecting and connecting
+            //both states are permitted, however, connection handle must be known.
+            DM_LOG("[DM]: Disconnect Reason 0x%04X\r\n",
+                   p_ble_evt->evt.gap_evt.params.disconnected.reason);
+
+            m_connection_table[index].state &= (~STATE_CONNECTED);
+
+            if ((m_connection_table[index].state & STATE_BONDED) == STATE_BONDED)
+            {
+                if ((m_connection_table[index].state & STATE_LINK_ENCRYPTED) == STATE_LINK_ENCRYPTED)
+                {
+                    //Write bond information persistently.
+                    device_context_store(&handle, STORE_ALL_CONTEXT);
+                }
+            }
+            else
+            {
+                //Free any allocated instances for devices that is not bonded.
+                if (handle.device_id != DM_INVALID_ID)
+                {
+                    peer_instance_init(handle.device_id);
+                    handle.device_id = DM_INVALID_ID;
+                }
+            }
+
+            m_connection_table[index].state = STATE_DISCONNECTING;
+            notify_app                      = true;
+            event.event_id                  = DM_EVT_DISCONNECTION;
+
+            break;
+
+        case BLE_GAP_EVT_SEC_INFO_REQUEST:
+            DM_LOG("[DM]: >> BLE_GAP_EVT_SEC_INFO_REQUEST\r\n");
+
+            //If the device is already bonded, respond with existing info, else NULL.
+            if (m_connection_table[index].bonded_dev_id == DM_INVALID_ID)
+            {
+                //Find device based on div.
+                err_code = device_instance_find(NULL,&device_index, p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.ediv);
+                if (err_code == NRF_SUCCESS)
+                {
+                    //Load needed bonding information.
+                    m_connection_table[index].bonded_dev_id = device_index;
+                    m_connection_table[index].state        |= STATE_BONDED;
+                    handle.device_id                        = device_index;
+                    bond_data_load(&handle);
+                }
+            }
+
+            if (m_connection_table[index].bonded_dev_id != DM_INVALID_ID)
+            {
+                p_enc_info = &m_bond_table[index].peer_enc_key.enc_info;
+                DM_DUMP((uint8_t *)p_enc_info, sizeof(ble_gap_enc_info_t));
+            }
+
+            err_code = sd_ble_gap_sec_info_reply(p_ble_evt->evt.gap_evt.conn_handle,
+                                                 p_enc_info,
+                                                 &m_peer_table[index].peer_id.id_info,
+                                                 NULL);
+
+            if (err_code != NRF_SUCCESS)
+            {
+                DM_ERR("[DM]:[CI %02X]:[DI %02X]: Security information response failed, reason "
+                       "0x%08X\r\n", index, m_connection_table[index].bonded_dev_id, err_code);
+            }
+            break;
+
+        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+            DM_LOG("[DM]: >> BLE_GAP_EVT_SEC_PARAMS_REQUEST\r\n");
+
+            event.event_id = DM_EVT_SECURITY_SETUP;
+
+            m_connection_table[index].state |= STATE_PAIRING;
+            notify_app                       = true;
+
+            if (m_connection_table[index].bonded_dev_id == DM_INVALID_ID)
+            {
+                //Assign a peer index as a new bond or update existing bonds.
+                err_code = device_instance_allocate((uint8_t *)&device_index,
+                                                    &m_connection_table[index].peer_addr);
+
+                //Allocation successful.
+                if (err_code == NRF_SUCCESS)
+                {
+                    DM_LOG("[DM]:[CI 0x%02X]:[DI 0x%02X]: Bonded!\r\n",index, device_index);
+
+                    handle.device_id                        = device_index;
+                    m_connection_table[index].bonded_dev_id = device_index;
+                }
+                else
+                {
+                    DM_LOG("[DM]: Security parameter request failed, reason 0x%08X.\r\n", err_code);
+                    event_result = err_code;
+                    notify_app   = true;
+                }
+            }
+            else
+            {
+                //Bond/key refresh.
+                event.event_id = DM_EVT_SECURITY_SETUP_REFRESH;
+                memset(m_gatts_table[index].attributes, 0, DM_GATT_SERVER_ATTR_MAX_SIZE);
+
+                //Set the update flag for bond data.
+                m_connection_table[index].state |= STATE_BOND_INFO_UPDATE;
+            }
+
+            ble_gap_sec_keyset_t keys_exchanged;
+
+            DM_LOG("[DM]: 0x%02X, 0x%02X, 0x%02X, 0x%02X\r\n",
+                   p_ble_evt->evt.gap_evt.params.sec_params_request.peer_params.kdist_periph.enc,
+                   p_ble_evt->evt.gap_evt.params.sec_params_request.peer_params.kdist_central.id,
+                   p_ble_evt->evt.gap_evt.params.sec_params_request.peer_params.kdist_periph.sign,
+                   p_ble_evt->evt.gap_evt.params.sec_params_request.peer_params.bond);
+
+            keys_exchanged.keys_central.p_enc_key  = NULL;
+            keys_exchanged.keys_central.p_id_key   = &m_peer_table[m_connection_table[index].bonded_dev_id].peer_id; 
+            keys_exchanged.keys_central.p_sign_key = NULL;
+            keys_exchanged.keys_periph.p_enc_key   = &m_bond_table[index].peer_enc_key;
+            keys_exchanged.keys_periph.p_id_key    = NULL;
+            keys_exchanged.keys_periph.p_sign_key  = NULL;
+
+            err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle,
+                                                   BLE_GAP_SEC_STATUS_SUCCESS,
+                                                   &m_application_table[0].sec_param, 
+                                                   &keys_exchanged);
+
+            if (err_code != NRF_SUCCESS)
+            {
+                DM_LOG("[DM]: Security parameter reply request failed, reason 0x%08X.\r\n", err_code);
+                event_result = err_code;
+                notify_app   = false;
+            }
+            break;
+
+        case BLE_GAP_EVT_AUTH_STATUS:
+        {
+            DM_LOG("[DM]: >> BLE_GAP_EVT_AUTH_STATUS, status %08X\r\n",
+                   p_ble_evt->evt.gap_evt.params.auth_status.auth_status);
+
+            m_application_table[0].state    &= (~STATE_CONTROL_PROCEDURE_IN_PROGRESS);
+            m_connection_table[index].state &= (~STATE_PAIRING);
+            event.event_id                   = DM_EVT_SECURITY_SETUP_COMPLETE;
+            notify_app                       = true;
+
+            if (p_ble_evt->evt.gap_evt.params.auth_status.auth_status != BLE_GAP_SEC_STATUS_SUCCESS)
+            {
+                // Free the allocation as bonding failed.
+                ret_code_t result = device_instance_free(m_connection_table[index].bonded_dev_id);
+                (void) result;
+                event_result = p_ble_evt->evt.gap_evt.params.auth_status.auth_status;
+            }
+            else
+            {
+                DM_DUMP((uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status,
+                        sizeof(ble_gap_evt_auth_status_t));
+                DM_DUMP((uint8_t *)&m_bond_table[index], sizeof(bond_context_t));
+
+                if (p_ble_evt->evt.gap_evt.params.auth_status.bonded == 1)
+                {
+                    if (handle.device_id != DM_INVALID_ID)
+                    {
+                        m_connection_table[index].state |= STATE_BONDED;
+
+                        //IRK and/or public address is shared, update it.
+                        if (p_ble_evt->evt.gap_evt.params.auth_status.kdist_central.id == 1)
+                        {
+                            m_peer_table[handle.device_id].id_bitmap &= (~IRK_ENTRY);
+                        }
+
+                        if (m_connection_table[index].bonded_dev_id != DM_INVALID_ID)
+                        {
+                            DM_LOG("[DM]:[CI 0x%02X]:[DI 0x%02X]: Bonded!\r\n",
+                                   index,
+                                   handle.device_id);
+
+                            if (m_connection_table[index].peer_addr.addr_type !=
+                                BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+                            {
+                               m_peer_table[handle.device_id].peer_id.id_addr_info =
+                                    m_connection_table[index].peer_addr;
+                               m_peer_table[handle.device_id].id_bitmap &= (~ADDR_ENTRY);
+
+                               DM_DUMP((uint8_t *)&m_peer_table[handle.device_id].peer_id.id_addr_info,
+                                       sizeof(m_peer_table[handle.device_id].peer_id.id_addr_info));
+                            }
+                            else
+                            {
+                                // Here we must fetch the keys from the keyset distributed.
+                                m_peer_table[handle.device_id].ediv       = m_bond_table[index].peer_enc_key.master_id.ediv;
+                                m_peer_table[handle.device_id].id_bitmap &= (~IRK_ENTRY);
+                            }
+
+                            device_context_store(&handle, FIRST_BOND_STORE);
+                        }
+                    }
+                }
+                else
+                {
+                    //Pairing request, no need to touch the bonding info.
+                }
+            }
+            break;
+        }
+
+        case BLE_GAP_EVT_CONN_SEC_UPDATE:
+            DM_LOG("[DM]: >> BLE_GAP_EVT_CONN_SEC_UPDATE, Mode 0x%02X, Level 0x%02X\r\n",
+                   p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.sm,
+                   p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv);
+
+            if ((p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv == 1) &&
+                (p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.sm == 1) &&
+                ((m_connection_table[index].state & STATE_BONDED) == STATE_BONDED))
+            {
+                //Lost bond case, generate a security refresh event!
+                memset(m_gatts_table[index].attributes, 0, DM_GATT_SERVER_ATTR_MAX_SIZE);
+                
+                event.event_id                   = DM_EVT_SECURITY_SETUP_REFRESH;
+                m_connection_table[index].state |= STATE_PAIRING_PENDING;
+                m_connection_table[index].state |= STATE_BOND_INFO_UPDATE;
+                m_application_table[0].state    |= STATE_QUEUED_CONTROL_REQUEST;
+            }
+            else
+            {
+                m_connection_table[index].state |= STATE_LINK_ENCRYPTED;
+                event.event_id                   = DM_EVT_LINK_SECURED;
+
+                //Apply service context.
+                err_code = m_service_context_apply[m_application_table[0].service](&handle);
+
+                if (err_code != NRF_SUCCESS)
+                {
+                    DM_ERR("[DM]:[CI 0x%02X]:[DI 0x%02X]: Failed to apply service context\r\n",
+                            handle.connection_id, 
+                            handle.device_id);
+
+                    event_result = DM_SERVICE_CONTEXT_NOT_APPLIED;
+                }
+            }
+            event_result = NRF_SUCCESS;
+            notify_app   = true;
+            
+            break;
+
+        case BLE_GATTS_EVT_SYS_ATTR_MISSING:
+            DM_LOG("[DM]: >> BLE_GATTS_EVT_SYS_ATTR_MISSING\r\n");
+
+            //Apply service context.
+            event_result = m_service_context_apply[m_application_table[0].service](&handle);
+            break;
+
+        case BLE_GAP_EVT_SEC_REQUEST:
+            DM_LOG("[DM]: >> BLE_GAP_EVT_SEC_REQUEST\r\n");
+            
+            //Verify if the device is already bonded, and if it is bonded, initiate encryption.
+            //If the device is not bonded, an instance needs to be allocated in order to initiate 
+            //bonding. The application have to initiate the procedure, the module will not do this 
+            //automatically.
+            event.event_id = DM_EVT_SECURITY_SETUP;
+            notify_app     = true;
+            
+            break;
+
+        default:
+            break;
+    }
+
+    if (notify_app)
+    {
+        app_evt_notify(&handle, &event, event_result);
+
+        //Freeing the instance after the event is notified so the application can get the context.
+        if (event.event_id == DM_EVT_DISCONNECTION)
+        {
+            //Free the instance.
+            connection_instance_free(&index);
+        }
+    }
+
+    UNUSED_VARIABLE(err_code);
+
+    DM_MUTEX_UNLOCK();
+}
+
+
+ret_code_t dm_handle_get(uint16_t conn_handle, dm_handle_t * p_handle)
+{
+    ret_code_t err_code;
+    uint32_t   index;
+
+    NULL_PARAM_CHECK(p_handle);
+    VERIFY_APP_REGISTERED(p_handle->appl_id);
+
+    p_handle->device_id  = DM_INVALID_ID;
+
+    err_code = NRF_ERROR_NOT_FOUND;
+
+    for (index = 0; index < DEVICE_MANAGER_MAX_CONNECTIONS; index++)
+    {
+        //Search for matching connection handle.
+        if (conn_handle == m_connection_table[index].conn_handle)
+        {
+            p_handle->connection_id = index;
+            p_handle->device_id     = m_connection_table[index].bonded_dev_id;
+
+            err_code = NRF_SUCCESS;
+            break;
+        }
+    }
+    return err_code;
+}