uint32_t iot_context_manager_get_by_cid(const iot_interface_t * p_interface,
                                        uint8_t           context_id,
                                        iot_context_t  ** pp_context)
{
    VERIFY_MODULE_IS_INITIALIZED();
    NULL_PARAM_CHECK(p_interface);
    NULL_PARAM_CHECK(pp_context);
    VERIFY_CID_VALUE(context_id);

    uint32_t err_code;

    CM_ENTRY();

    CM_MUTEX_LOCK();

    const uint32_t table_id = context_table_find(p_interface);

    if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
    {
        err_code = context_find_by_cid(table_id, context_id, pp_context);
    }
    else
    {
        // No free context table found.
        CM_TRC("No context table found.");
        err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
    }

    CM_MUTEX_UNLOCK();

    CM_EXIT();

    return err_code;
}
uint32_t iot_context_manager_table_free(const iot_interface_t * p_interface)
{
    VERIFY_MODULE_IS_INITIALIZED();
    NULL_PARAM_CHECK(p_interface);

    uint32_t err_code = NRF_SUCCESS;

    CM_ENTRY();

    SDK_MUTEX_INIT(m_iot_context_manager_mutex);

    CM_MUTEX_LOCK();

    const uint32_t table_id = context_table_find(p_interface);

    if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
    {
        // Clear context table.
        CM_TRC("Found context table assigned to interface.");
        context_table_init(table_id);
    }
    else
    {
        // No free context table found.
        CM_ERR("No context table found.");
        err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
    }

    CM_MUTEX_UNLOCK();

    CM_EXIT();

    return err_code;
}
uint32_t iot_context_manager_table_alloc(const iot_interface_t * p_interface)
{
    VERIFY_MODULE_IS_INITIALIZED();
    NULL_PARAM_CHECK(p_interface);

    uint32_t err_code = NRF_SUCCESS;

    CM_ENTRY();

    CM_MUTEX_LOCK();

    const uint32_t table_id = context_table_find(NULL);

    if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
    {
        // Found a free context table and assign to it.
        CM_TRC("Assigned new context table.");
        m_context_table[table_id].p_interface = (iot_interface_t *)p_interface;
    }
    else
    {
        // No free context table found.
        CM_ERR("No context table found.");
        err_code = (NRF_ERROR_NO_MEM | IOT_CONTEXT_MANAGER_ERR_BASE);
    }

    CM_MUTEX_UNLOCK();

    CM_EXIT();

    return err_code;
}
uint32_t iot_context_manager_get_by_addr(const iot_interface_t * p_interface, 
                                         const ipv6_addr_t     * p_addr, 
                                         iot_context_t        ** pp_context)
{
    VERIFY_MODULE_IS_INITIALIZED();
    NULL_PARAM_CHECK(p_interface);
    NULL_PARAM_CHECK(p_addr);
    NULL_PARAM_CHECK(pp_context);
    
    uint32_t err_code;

    CM_TRC("[CONTEXT_MANAGER]: >> iot_context_manager_get_by_addr\r\n");

    CM_MUTEX_LOCK();

    const uint32_t table_id = context_table_find(p_interface);

    if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
    {
        err_code = context_find_by_prefix(table_id, p_addr, pp_context);
    }
    else
    {
        // No free context table found.
        CM_TRC("[CONTEXT_MANAGER]: No context table found.\r\n");
        err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
    }

    CM_MUTEX_UNLOCK();

    CM_TRC("[CONTEXT_MANAGER]: << iot_context_manager_get_by_addr\r\n");

    return err_code;
}
uint32_t iot_context_manager_remove(const iot_interface_t * p_interface,
                                    iot_context_t         * p_context)
{
    VERIFY_MODULE_IS_INITIALIZED();
    NULL_PARAM_CHECK(p_interface);
    NULL_PARAM_CHECK(p_context);

    uint32_t err_code  = NRF_SUCCESS;

    CM_ENTRY();

    CM_MUTEX_LOCK();

    const uint32_t table_id = context_table_find(p_interface);

    if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
    {
        if (p_context->context_id != IPV6_CONTEXT_IDENTIFIER_NONE)
        {
            m_context_table[table_id].context_count--;
        }

        // Reinit context entry.
        context_init(p_context);
    }
    else
    {
        // No free context table found.
        CM_ERR("No context table found.");
        err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
    }

    CM_MUTEX_UNLOCK();

    CM_EXIT();

    return err_code;
}
uint32_t iot_context_manager_update(const iot_interface_t * p_interface,
                                    iot_context_t         * p_context)
{
    VERIFY_MODULE_IS_INITIALIZED();
    NULL_PARAM_CHECK(p_context);
    VERIFY_CID_VALUE(p_context->context_id);
    VERIFY_PREFIX_LEN_VALUE(p_context->prefix_len);

    uint32_t        retval   = NRF_SUCCESS;
    uint32_t        err_code = NRF_SUCCESS;
    iot_context_t * p_internal_context;

    CM_ENTRY();

    CM_MUTEX_LOCK();

    const uint32_t table_id = context_table_find(p_interface);

    if (table_id != IOT_CONTEXT_MANAGER_MAX_TABLES)
    {
          // Try to find context in context table.
          retval = context_find_by_cid(table_id, p_context->context_id, &p_internal_context);

          if (retval != NRF_SUCCESS)
          {
              err_code = context_find_free(table_id, &p_internal_context);

              // Increase context count.
              if (err_code == NRF_SUCCESS)
              {
                  m_context_table[table_id].context_count++;
              }
          }

          if (err_code == NRF_SUCCESS)
          {
               // Update context table, with parameters from application.
               p_internal_context->context_id       = p_context->context_id;
               p_internal_context->prefix_len       = p_context->prefix_len;
               p_internal_context->compression_flag = p_context->compression_flag;
               memset(p_internal_context->prefix.u8, 0, IPV6_ADDR_SIZE);
               IPV6_ADDRESS_PREFIX_SET(p_internal_context->prefix.u8, p_context->prefix.u8, p_context->prefix_len);
           }
           else
           {
               CM_ERR("No place in context table.");
           }
    }
    else
    {
        // No free context table found.
        CM_ERR("No context table found.");
        err_code = (NRF_ERROR_NOT_FOUND | IOT_CONTEXT_MANAGER_ERR_BASE);
    }

    CM_MUTEX_UNLOCK();

    CM_EXIT();

    return err_code;
}