Merge branch 'master' into security-summit
authorSachin Agrawal <sachin.agrawal@intel.com>
Wed, 16 Sep 2015 19:11:45 +0000 (12:11 -0700)
committerSachin Agrawal <sachin.agrawal@intel.com>
Wed, 16 Sep 2015 19:11:45 +0000 (12:11 -0700)
* master: (50 commits)
  Update the stack to use the new CoAP return code 2.04/2.05 values.
  resolve memory leak of ip monitor
  removed warning message for CA
  Add frag/defrag logic in EDR
  Add support for and handle presence of the coap ACCEPT option.
  Addressed endpoint pointer type mismatches in LE adapter.
  modify the OCTransportAdapter structure in RI
  apply smack rule and make resource samples package
  [Resource-Encapsulation] Updated Java SDK and RE Android Samples
  Enable error responses to be sent back to the client.
  Updated Android Sample App for block-wise transfer
  Enabled CoAP over TCP in RI Layer.
  [TIZEN] Updated properties of Configuration resource in Things manager.
  resource: Add test for ConstructResourceObject with InvalidUri
  [Services - Things Manager] Removed Things Manager class and exposed its component classes for SDK
  [Things-Manager] Updated Things Manager Sample Applications
  Fixed pointer-type arrays with NULL values
  Remove ifaddr files
  replaced some ERROR tag with DEBUG
  [TIZEN] Removed things manager class dependency from TIZEN SDK and used its component class.
  ...

Conflicts:
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/doxmresource.c
resource/src/SConscript

Change-Id: I615c48ee6066873b9a5bb1dc27fff7e2490fb68f
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
1  2 
resource/csdk/security/provisioning/src/provisioningdatabasemanager.c
resource/csdk/security/provisioning/src/secureresourceprovider.c
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/credresource.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/unittest/aclresourcetest.cpp
resource/csdk/security/unittest/credentialresource.cpp
resource/csdk/security/unittest/doxmresource.cpp
resource/csdk/stack/include/octypes.h
resource/src/SConscript

index 1f5c461,0000000..5a910f6
mode 100644,000000..100644
--- /dev/null
@@@ -1,682 -1,0 +1,682 @@@
-   { OC_LOG(ERROR, (tag), PCF("PDB is not initialized")); \
 +/* *****************************************************************
 + *
 + * Copyright 2015 Samsung Electronics All Rights Reserved.
 + *
 + *
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + *
 + * *****************************************************************/
 +
 +#include <stdio.h>
 +#include <stdbool.h>
 +#include <sqlite3.h>
 +#include <string.h>
 +#include <stdlib.h>
 +
 +#include "logger.h"
 +#include "oic_malloc.h"
 +#include "provisioningdatabasemanager.h"
 +#include "pmutility.h"
 +#include "oic_string.h"
 +#include "utlist.h"
 +
 +
 +#define DB_FILE "PDM.db"
 +
 +#define TAG "PDM"
 +
 +#define PDM_STALE_STATE 1
 +#define PDM_ACTIVE_STATE 0
 +
 +#define PDM_FIRST_INDEX 0
 +#define PDM_SECOND_INDEX 1
 +
 +#define PDM_BIND_INDEX_FIRST 1
 +#define PDM_BIND_INDEX_SECOND 2
 +#define PDM_BIND_INDEX_THIRD 3
 +
 +#define PDM_CREATE_T_DEVICE_LIST "create table T_DEVICE_LIST(ID INTEGER PRIMARY KEY AUTOINCREMENT,\
 +                                  UUID BLOB NOT NULL UNIQUE);"
 +
 +#define PDM_CREATE_T_DEVICE_LINK  "create table T_DEVICE_LINK_STATE(ID INT NOT NULL, ID2 INT NOT \
 +                                   NULL,STATE INT NOT NULL, PRIMARY KEY (ID, ID2));"
 +/**
 + * Macro to verify sqlite success.
 + * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
 + */
 +#define PDM_VERIFY_SQLITE_OK(tag, arg, logLevel, retValue) do{ if (SQLITE_OK != (arg)) \
 +            { OC_LOG_V((logLevel), tag, ("Error in " #arg ", Error Message: %s"), \
 +               sqlite3_errmsg(g_db)); return retValue; }}while(0)
 +
 +#define PDM_SQLITE_TRANSACTION_BEGIN "BEGIN TRANSACTION;"
 +#define PDM_SQLITE_TRANSACTION_COMMIT "COMMIT;"
 +#define PDM_SQLITE_TRANSACTION_ROLLBACK "ROLLBACK;"
 +#define PDM_SQLITE_GET_STALE_INFO "SELECT ID,ID2 FROM T_DEVICE_LINK_STATE WHERE STATE = ?"
 +#define PDM_SQLITE_INSERT_T_DEVICE_LIST "INSERT INTO T_DEVICE_LIST VALUES(?,?)"
 +#define PDM_SQLITE_GET_ID "SELECT ID FROM T_DEVICE_LIST WHERE UUID like ?"
 +#define PDM_SQLITE_INSERT_LINK_DATA "INSERT INTO T_DEVICE_LINK_STATE VALUES(?,?,?)"
 +#define PDM_SQLITE_DELETE_LINK "DELETE FROM T_DEVICE_LINK_STATE WHERE ID = ? and ID2 = ?"
 +#define PDM_SQLITE_DELETE_DEVICE_LINK "DELETE FROM T_DEVICE_LINK_STATE WHERE ID = ? or ID2 = ?"
 +#define PDM_SQLITE_DELETE_DEVICE "DELETE FROM T_DEVICE_LIST  WHERE ID = ?"
 +#define PDM_SQLITE_UPDATE_LINK "UPDATE T_DEVICE_LINK_STATE SET STATE = ?  WHERE ID = ? and ID2 = ?"
 +#define PDM_SQLITE_LIST_ALL_UUID "SELECT UUID FROM T_DEVICE_LIST"
 +#define PDM_SQLITE_GET_UUID "SELECT UUID FROM T_DEVICE_LIST WHERE ID = ?"
 +#define PDM_SQLITE_GET_LINKED_DEVICES "SELECT ID,ID2 FROM T_DEVICE_LINK_STATE WHERE ID = ? or ID2 = ?"
 +
 +#define ASCENDING_ORDER(id1, id2) do{if( (id1) > (id2) )\
 +  { int temp; temp = id1; id1 = id2; id2 = temp; }}while(0)
 +
 +#define CHECK_PDM_INIT(tag) do{if(true != gInit)\
-     OC_LOG(ERROR, TAG, PCF("PDB is not initialized"));
++  { OC_LOG(ERROR, (tag), "PDB is not initialized"); \
 +    return OC_STACK_PDM_IS_NOT_INITIALIZED; }}while(0)
 +
 +static sqlite3 *g_db = NULL;
 +static bool gInit = false;  /* Only if we can open sqlite db successfully, gInit is true. */
 +
 +/**
 + * function to create DB in case DB doesn't exists
 + */
 +static OCStackResult createDB(const char* path)
 +{
 +
 +    int result = 0;
 +    result = sqlite3_open_v2(path, &g_db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, result, ERROR, OC_STACK_ERROR);
 +
 +    result = sqlite3_exec(g_db, PDM_CREATE_T_DEVICE_LIST, NULL, NULL, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, result, ERROR, OC_STACK_ERROR);
 +
 +    OC_LOG(INFO, TAG, "Created T_DEVICE_LIST");
 +    result = sqlite3_exec(g_db, PDM_CREATE_T_DEVICE_LINK, NULL, NULL, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, result, ERROR, OC_STACK_ERROR);
 +
 +    OC_LOG(INFO, TAG, "Created T_DEVICE_LINK_STATE");
 +    gInit = true;
 +    return OC_STACK_OK;
 +}
 +
 +
 +/**
 + * Function to begin any transaction
 + */
 +static OCStackResult begin()
 +{
 +    int res = 0;
 +    res = sqlite3_exec(g_db, PDM_SQLITE_TRANSACTION_BEGIN, NULL, NULL, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +    return OC_STACK_OK;
 +}
 +
 +/**
 + * Function to commit any transaction
 + */
 +static OCStackResult commit()
 +{
 +    int res = 0;
 +    res = sqlite3_exec(g_db, PDM_SQLITE_TRANSACTION_COMMIT, NULL, NULL, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +    return OC_STACK_OK;
 +}
 +
 +/**
 + * Function to rollback any transaction
 + */
 +static OCStackResult rollback()
 +{
 +    int res = 0;
 +    res = sqlite3_exec(g_db, PDM_SQLITE_TRANSACTION_ROLLBACK, NULL, NULL, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +    return OC_STACK_OK;
 +}
 +
 +/**
 + * Error log callback called by SQLite stack in case of error
 + */
 +void errLogCallback(void *pArg, int iErrCode, const char *zMsg)
 +{
 +    (void) pArg;
 +    (void) iErrCode;
 +    (void) zMsg;
 +    OC_LOG_V(DEBUG,TAG, "(%d) %s", iErrCode, zMsg);
 +}
 +
 +OCStackResult PDMInit(const char *path)
 +{
 +    int rc;
 +    const char *dbPath = NULL;
 +    if (SQLITE_OK !=  sqlite3_config(SQLITE_CONFIG_LOG, errLogCallback, NULL))
 +    {
 +        OC_LOG(INFO, TAG, "Unable to enable debug log of sqlite");
 +    }
 +
 +    if (NULL == path || !*path)
 +    {
 +        dbPath = DB_FILE;
 +    }
 +    else
 +    {
 +        dbPath = path;
 +    }
 +    rc = sqlite3_open_v2(dbPath, &g_db, SQLITE_OPEN_READWRITE, NULL);
 +    if (SQLITE_OK != rc)
 +    {
 +        OC_LOG_V(INFO, TAG, "ERROR: Can't open database: %s", sqlite3_errmsg(g_db));
 +        return createDB(dbPath);
 +    }
 +    gInit = true;
 +    return OC_STACK_OK;
 +}
 +
 +
 +OCStackResult PDMAddDevice(const OicUuid_t *UUID)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL == UUID)
 +    {
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    sqlite3_stmt *stmt = 0;
 +    int res =0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_INSERT_T_DEVICE_LIST,
 +                              strlen(PDM_SQLITE_INSERT_T_DEVICE_LIST) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_blob(stmt, PDM_BIND_INDEX_SECOND, UUID, UUID_LENGTH, SQLITE_STATIC);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_step(stmt);
 +    if (SQLITE_DONE != res)
 +    {
 +        if (SQLITE_CONSTRAINT == res)
 +        {
 +            //new OCStack result code
 +            OC_LOG_V(ERROR, TAG, "Error Occured: %s",sqlite3_errmsg(g_db));
 +            sqlite3_finalize(stmt);
 +            return OC_STACK_DUPLICATE_UUID;
 +        }
 +        OC_LOG_V(ERROR, TAG, "Error Occured: %s",sqlite3_errmsg(g_db));
 +        sqlite3_finalize(stmt);
 +        return OC_STACK_ERROR;
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +/**
 + *function to get Id for given UUID
 + */
 +static OCStackResult getIdForUUID(const OicUuid_t *UUID , int *id)
 +{
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_GET_ID, strlen(PDM_SQLITE_GET_ID) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_blob(stmt, PDM_BIND_INDEX_FIRST, UUID, UUID_LENGTH, SQLITE_STATIC);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    OC_LOG(DEBUG, TAG, "Binding Done");
 +    while (SQLITE_ROW == sqlite3_step(stmt))
 +    {
 +        int tempId = sqlite3_column_int(stmt, PDM_FIRST_INDEX);
 +        OC_LOG_V(DEBUG, TAG, "ID is %d", tempId);
 +        *id = tempId;
 +        sqlite3_finalize(stmt);
 +        return OC_STACK_OK;
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_INVALID_PARAM;
 +}
 +
 +/**
 + * Function to check duplication of device's Device ID.
 + */
 +bool PDMIsDuplicateDevice(const OicUuid_t* UUID)
 +{
 +    if(gInit)
 +    {
 +        if (NULL == UUID)
 +        {
 +            OC_LOG(ERROR, TAG, "UUID is NULL");
 +            return true;
 +        }
 +
 +        sqlite3_stmt *stmt = 0;
 +        int res = 0;
 +        res = sqlite3_prepare_v2(g_db, PDM_SQLITE_GET_ID, strlen(PDM_SQLITE_GET_ID) + 1, &stmt, NULL);
 +        PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +        res = sqlite3_bind_blob(stmt, PDM_BIND_INDEX_FIRST, UUID, UUID_LENGTH, SQLITE_STATIC);
 +        PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +        OC_LOG(DEBUG, TAG, "Binding Done");
 +
 +        while (SQLITE_ROW == sqlite3_step(stmt))
 +        {
 +            OC_LOG(ERROR, TAG, "UUID is duplicated");
 +            sqlite3_finalize(stmt);
 +            return true;
 +        }
 +        sqlite3_finalize(stmt);
 +        return false;
 +    }
++    OC_LOG(ERROR, TAG, "PDB is not initialized");
 +    return true; // return true will stop futher process.
 +}
 +
 +/**
 + * Function to add link in sqlite
 + */
 +static OCStackResult addlink(int id1, int id2)
 +{
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_INSERT_LINK_DATA,
 +                              strlen(PDM_SQLITE_INSERT_LINK_DATA) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, id1);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_SECOND, id2);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_THIRD, PDM_ACTIVE_STATE);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    if (sqlite3_step(stmt) != SQLITE_DONE)
 +    {
 +        OC_LOG_V(ERROR, TAG, "Error Occured: %s",sqlite3_errmsg(g_db));
 +        sqlite3_finalize(stmt);
 +        return OC_STACK_ERROR;
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMLinkDevices(const OicUuid_t *UUID1, const OicUuid_t *UUID2)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL == UUID1 || NULL == UUID2)
 +    {
 +        OC_LOG(ERROR, TAG, "Invalid PARAM");
 +        return  OC_STACK_INVALID_PARAM;
 +    }
 +    int id1 = 0;
 +    if (OC_STACK_OK != getIdForUUID(UUID1, &id1))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    int id2 = 0;
 +    if (OC_STACK_OK != getIdForUUID(UUID2, &id2))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    ASCENDING_ORDER(id1, id2);
 +    return addlink(id1, id2);
 +}
 +
 +/**
 + * Function to remove created link
 + */
 +static OCStackResult removeLink(int id1, int id2)
 +{
 +    int res = 0;
 +    sqlite3_stmt *stmt = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_DELETE_LINK, strlen(PDM_SQLITE_DELETE_LINK) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, id1);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_SECOND, id2);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    if (SQLITE_DONE != sqlite3_step(stmt))
 +    {
 +        OC_LOG_V(ERROR, TAG, "Error message: %s", sqlite3_errmsg(g_db));
 +        sqlite3_finalize(stmt);
 +        return OC_STACK_ERROR;
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMUnlinkDevices(const OicUuid_t *UUID1, const OicUuid_t *UUID2)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL == UUID1 || NULL == UUID2)
 +    {
 +        OC_LOG(ERROR, TAG, "Invalid PARAM");
 +        return  OC_STACK_INVALID_PARAM;
 +    }
 +
 +    int id1 = 0;
 +    if (OC_STACK_OK != getIdForUUID(UUID1, &id1))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    int id2 = 0;
 +    if (OC_STACK_OK != getIdForUUID(UUID2, &id2))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    ASCENDING_ORDER(id1, id2);
 +    return removeLink(id1, id2);
 +}
 +
 +static OCStackResult removeFromDeviceList(int id)
 +{
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_DELETE_DEVICE,
 +                              strlen(PDM_SQLITE_DELETE_DEVICE) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, id);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    if (sqlite3_step(stmt) != SQLITE_DONE)
 +    {
 +        OC_LOG_V(ERROR, TAG, "Error message: %s", sqlite3_errmsg(g_db));
 +        sqlite3_finalize(stmt);
 +        return OC_STACK_ERROR;
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMDeleteDevice(const OicUuid_t *UUID)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL == UUID)
 +    {
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    int id = 0;
 +    if (OC_STACK_OK != getIdForUUID(UUID, &id))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    begin();
 +    if(OC_STACK_OK != removeFromDeviceList(id))
 +    {
 +        rollback();
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_ERROR;
 +    }
 +    commit();
 +    return OC_STACK_OK;
 +}
 +
 +
 +static OCStackResult updateLinkState(int id1, int id2, int state)
 +{
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0 ;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_UPDATE_LINK,
 +                              strlen(PDM_SQLITE_UPDATE_LINK) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, state);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_SECOND, id1);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_THIRD, id2);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    if (SQLITE_DONE != sqlite3_step(stmt))
 +    {
 +        OC_LOG_V(ERROR, TAG, "Error message: %s", sqlite3_errmsg(g_db));
 +        sqlite3_finalize(stmt);
 +        return OC_STACK_ERROR;
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMSetLinkStale(const OicUuid_t* uuidOfDevice1, const OicUuid_t* uuidOfDevice2)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL == uuidOfDevice1 || NULL == uuidOfDevice2)
 +    {
 +        OC_LOG(ERROR, TAG, "Invalid PARAM");
 +        return  OC_STACK_INVALID_PARAM;
 +    }
 +
 +    int id1 = 0;
 +    if (OC_STACK_OK != getIdForUUID(uuidOfDevice1, &id1))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    int id2 = 0;
 +    if (OC_STACK_OK != getIdForUUID(uuidOfDevice2, &id2))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    ASCENDING_ORDER(id1, id2);
 +    return updateLinkState(id1, id2, PDM_STALE_STATE);
 +
 +}
 +
 +OCStackResult PDMGetOwnedDevices(OCUuidList_t **uuidList, size_t *numOfDevices)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL != *uuidList)
 +    {
 +        OC_LOG(ERROR, TAG, "Not null list will cause memory leak");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_LIST_ALL_UUID,
 +                              strlen(PDM_SQLITE_LIST_ALL_UUID) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    int counter  = 0;
 +    while (SQLITE_ROW == sqlite3_step(stmt))
 +    {
 +
 +        const void *ptr = sqlite3_column_blob(stmt, PDM_FIRST_INDEX);
 +        OicUuid_t *uid = (OicUuid_t *)ptr;
 +        OCUuidList_t *temp = (OCUuidList_t *) OICCalloc(1,sizeof(OCUuidList_t));
 +        if (NULL == temp)
 +        {
 +            OC_LOG_V(ERROR, TAG, "Memory allocation problem");
 +            sqlite3_finalize(stmt);
 +            return OC_STACK_NO_MEMORY;
 +        }
 +        memcpy(&temp->dev.id, uid->id, UUID_LENGTH);
 +        LL_PREPEND(*uuidList,temp);
 +        ++counter;
 +    }
 +    *numOfDevices = counter;
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +static OCStackResult getUUIDforId(int id, OicUuid_t *uid)
 +{
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_GET_UUID,
 +                              strlen(PDM_SQLITE_GET_UUID) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, id);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    while (SQLITE_ROW == sqlite3_step(stmt))
 +    {
 +        const void *ptr = sqlite3_column_blob(stmt, PDM_FIRST_INDEX);
 +        memcpy(uid, ptr, sizeof(OicUuid_t));
 +    }
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMGetLinkedDevices(const OicUuid_t *UUID, OCUuidList_t **UUIDLIST, size_t *numOfDevices)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL != *UUIDLIST)
 +    {
 +        OC_LOG(ERROR, TAG, "Not null list will cause memory leak");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    if (NULL == UUID)
 +    {
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    int id = 0;
 +    if (OC_STACK_OK != getIdForUUID(UUID, &id))
 +    {
 +        OC_LOG(ERROR, TAG, "Requested value not found");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_GET_LINKED_DEVICES,
 +                              strlen(PDM_SQLITE_GET_LINKED_DEVICES) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, id);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_SECOND, id);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    int counter  = 0;
 +    while (SQLITE_ROW == sqlite3_step(stmt))
 +    {
 +        int i1 = sqlite3_column_int(stmt, PDM_FIRST_INDEX);
 +        int i2 = sqlite3_column_int(stmt, PDM_SECOND_INDEX);
 +
 +        OicUuid_t temp = {{0,}};
 +        if (i1 != id)
 +        {
 +            getUUIDforId(i1, &temp);
 +        }
 +        if (i2 != id)
 +        {
 +            getUUIDforId(i2, &temp);
 +        }
 +
 +        OCUuidList_t *tempNode = (OCUuidList_t *) OICCalloc(1,sizeof(OCUuidList_t));
 +        if (NULL == tempNode)
 +        {
 +            OC_LOG(ERROR, TAG, "No Memory");
 +            sqlite3_finalize(stmt);
 +            return OC_STACK_NO_MEMORY;
 +        }
 +        memcpy(&tempNode->dev.id, &temp.id, UUID_LENGTH);
 +        LL_PREPEND(*UUIDLIST,tempNode);
 +        ++counter;
 +    }
 +    *numOfDevices = counter;
 +     sqlite3_finalize(stmt);
 +     return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMGetToBeUnlinkedDevices(OCPairList_t **staleDevList, size_t *numOfDevices)
 +{
 +    CHECK_PDM_INIT(TAG);
 +    if (NULL != *staleDevList)
 +    {
 +        OC_LOG(ERROR, TAG, "Not null list will cause memory leak");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    sqlite3_stmt *stmt = 0;
 +    int res = 0;
 +    res = sqlite3_prepare_v2(g_db, PDM_SQLITE_GET_STALE_INFO,
 +                              strlen(PDM_SQLITE_GET_STALE_INFO) + 1, &stmt, NULL);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    res = sqlite3_bind_int(stmt, PDM_BIND_INDEX_FIRST, PDM_STALE_STATE);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +
 +    int counter  = 0;
 +    while (SQLITE_ROW == sqlite3_step(stmt))
 +    {
 +        int i1 = sqlite3_column_int(stmt, PDM_FIRST_INDEX);
 +        int i2 = sqlite3_column_int(stmt, PDM_SECOND_INDEX);
 +        OicUuid_t temp1 = {{0,}};
 +        OicUuid_t temp2 = {{0,}};;
 +        getUUIDforId(i1, &temp1);
 +        getUUIDforId(i2, &temp2);
 +
 +        OCPairList_t *tempNode = (OCPairList_t *) OICCalloc(1, sizeof(OCPairList_t));
 +        if (NULL == tempNode)
 +        {
 +            OC_LOG(ERROR, TAG, "No Memory");
 +            sqlite3_finalize(stmt);
 +            return OC_STACK_NO_MEMORY;
 +        }
 +        memcpy(&tempNode->dev.id, &temp1.id, UUID_LENGTH);
 +        memcpy(&tempNode->dev2.id, &temp2.id, UUID_LENGTH);
 +        LL_PREPEND(*staleDevList, tempNode);
 +        ++counter;
 +    }
 +    *numOfDevices = counter;
 +    sqlite3_finalize(stmt);
 +    return OC_STACK_OK;
 +}
 +
 +OCStackResult PDMClose()
 +{
 +    CHECK_PDM_INIT(TAG);
 +    int res = 0;
 +    res = sqlite3_close(g_db);
 +    PDM_VERIFY_SQLITE_OK(TAG, res, ERROR, OC_STACK_ERROR);
 +    return OC_STACK_OK;
 +}
 +
 +void PDMDestoryOicUuidLinkList(OCUuidList_t* ptr)
 +{
 +    if(ptr)
 +    {
 +        OCUuidList_t *tmp1 = NULL,*tmp2=NULL;
 +        LL_FOREACH_SAFE(ptr, tmp1, tmp2)
 +        {
 +            LL_DELETE(ptr, tmp1);
 +            OICFree(tmp1);
 +        }
 +    }
 +}
 +
 +void PDMDestoryStaleLinkList(OCPairList_t* ptr)
 +{
 +    if(ptr)
 +    {
 +        OCPairList_t *tmp1 = NULL,*tmp2=NULL;
 +        LL_FOREACH_SAFE(ptr, tmp1, tmp2)
 +        {
 +            LL_DELETE(ptr, tmp1);
 +            OICFree(tmp1);
 +        }
 +    }
 +}
@@@ -538,608 -494,3 +538,608 @@@ OCStackResult SRPProvisionACL(void *ctx
      VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
      return OC_STACK_OK;
  }
-     char reqBuf[MAX_REQUEST_LENGTH] = {0};
 +
 +static void DeleteUnlinkData_t(UnlinkData_t *unlinkData)
 +{
 +    if (unlinkData)
 +    {
 +        OICFree(unlinkData->unlinkDev);
 +        OICFree(unlinkData->unlinkRes);
 +        OICFree(unlinkData);
 +    }
 +}
 +
 +static void registerResultForUnlinkDevices(UnlinkData_t *unlinkData, OCStackResult stackresult,
 +                                           IdxUnlinkRes_t idx)
 +{
 +    if (NULL != unlinkData)
 +    {
 +        OC_LOG_V(INFO, TAG, "Inside registerResultForUnlinkDevices unlinkData->numOfResults is %d\n",
 +                            unlinkData->numOfResults);
 +        OC_LOG_V(INFO, TAG, "Stack result :: %d", stackresult);
 +
 +        OicUuid_t *pUuid = &unlinkData->unlinkRes[(unlinkData->numOfResults)].deviceId;
 +
 +        // Set result in the result array according to the position (devNum).
 +        if (idx != IDX_DB_UPDATE_RES)
 +        {
 +            memcpy(pUuid->id, unlinkData->unlinkDev[idx].doxm->deviceID.id, sizeof(pUuid->id));
 +        }
 +        else
 +        {   // When deivce ID is 000... this means it's the result of database update.
 +            memset(pUuid->id, 0, sizeof(pUuid->id));
 +        }
 +        unlinkData->unlinkRes[(unlinkData->numOfResults)].res = stackresult;
 +        ++(unlinkData->numOfResults);
 +        OC_LOG (INFO, TAG, "Out registerResultForUnlinkDevices");
 +    }
 +}
 +
 +static OCStackResult SendDeleteCredentialRequest(void* ctx,
 +                                                 OCClientResponseHandler respHandler,
 +                                                 const OCProvisionDev_t* revokedDev,
 +                                                 const OCProvisionDev_t* destDev)
 +{
 +    OC_LOG(DEBUG, TAG, "IN SendDeleteCredentialRequest");
 +
 +    if (NULL == ctx || NULL == respHandler || NULL == revokedDev || NULL == destDev)
 +    {
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(revokedDev->doxm->deviceID.id)) + 1] = {};
 +    uint32_t base64Len = 0;
 +    if (B64_OK != b64Encode(revokedDev->doxm->deviceID.id, sizeof(revokedDev->doxm->deviceID.id),
 +                           base64Buff, sizeof(base64Buff), &base64Len))
 +    {
 +        OC_LOG(ERROR, TAG, "SendDeleteCredentialRequest : Failed to base64 encoding");
 +        return OC_STACK_ERROR;
 +    }
 +
++    char reqBuf[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
 +    int snRet = 0;
 +                    //coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
 +    snRet = snprintf(reqBuf, sizeof(reqBuf), SRP_FORM_DELETE_CREDENTIAL, destDev->endpoint.addr,
 +                     destDev->securePort, OIC_RSRC_CRED_URI, OIC_JSON_SUBJECT_NAME, base64Buff);
 +    if (snRet < 0)
 +    {
 +        OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error (snprintf) %d\n", snRet);
 +        return OC_STACK_ERROR;
 +    }
 +    else if ((size_t)snRet >= sizeof(reqBuf))
 +    {
 +        OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Truncated (snprintf) %d\n", snRet);
 +        return OC_STACK_ERROR;
 +    }
 +
 +    OCCallbackData cbData;
 +    memset(&cbData, 0, sizeof(cbData));
 +    cbData.context = ctx;
 +    cbData.cb = respHandler;
 +    cbData.cd = NULL;
 +    OC_LOG_V(INFO, TAG, "URI: %s",reqBuf);
 +
 +    OC_LOG(DEBUG, TAG, "Sending remove credential request to resource server");
 +
 +    OCStackResult ret = OCDoResource(NULL, OC_REST_DELETE, reqBuf,
 +                                     &destDev->endpoint, NULL,
 +                                     CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
 +    if (OC_STACK_OK != ret)
 +    {
 +        OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error in OCDoResource %d", ret);
 +    }
 +    OC_LOG(DEBUG, TAG, "OUT SendDeleteCredentialRequest");
 +
 +    return ret;
 +}
 +
 +/**
 + * Callback handler of unlink second device.
 + *
 + * @param[in] ctx             ctx value passed to callback from calling function.
 + * @param[in] handle          handle to an invocation
 + * @param[in] clientResponse  Response from queries to remote servers.
 + * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction and
 + *          OC_STACK_KEEP_TRANSACTION to keep it.
 + */
 +static OCStackApplicationResult SRPUnlinkDevice2CB(void *unlinkCtx, OCDoHandle handle,
 +        OCClientResponse *clientResponse)
 +{
 +    (void) handle;
 +    OC_LOG(DEBUG, TAG, "IN SRPUnlinkDevice2CB");
 +    VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
 +    UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
 +
 +    if (clientResponse)
 +    {
 +        OC_LOG(DEBUG, TAG, "Valid client response for device 2");
 +        registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_SECOND_DEVICE_RES);
 +
 +        if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
 +        {
 +            OC_LOG(DEBUG, TAG, "Credential of device2 revoked");
 +        }
 +        else
 +        {
 +            OC_LOG(ERROR, TAG, "Unable to delete credential information from device 2");
 +            unlinkData->resultCallback(unlinkData->ctx,
 +                                       unlinkData->numOfResults, unlinkData->unlinkRes, true);
 +            goto error;
 +        }
 +    }
 +    else
 +    {
 +        registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
 +                                       IDX_SECOND_DEVICE_RES);
 +        unlinkData->resultCallback(unlinkData->ctx,
 +                                   unlinkData->numOfResults, unlinkData->unlinkRes, true);
 +        OC_LOG(ERROR, TAG, "SRPUnlinkDevice2CB received Null clientResponse");
 +        goto error;
 +    }
 +
 +    //Update provisioning DB when succes case.
 +    if (OC_STACK_OK != PDMUnlinkDevices(&unlinkData->unlinkDev[0].doxm->deviceID,
 +                                       &unlinkData->unlinkDev[1].doxm->deviceID))
 +    {
 +        OC_LOG(FATAL, TAG, "All requests are successfully done but update provisioning DB FAILED.");
 +        registerResultForUnlinkDevices(unlinkData, OC_STACK_INCONSISTENT_DB, IDX_DB_UPDATE_RES);
 +        unlinkData->resultCallback(unlinkData->ctx,
 +                                   unlinkData->numOfResults, unlinkData->unlinkRes, true);
 +        goto error;
 +    }
 +    unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, unlinkData->unlinkRes,
 +                               false);
 +
 +error:
 +    DeleteUnlinkData_t(unlinkData);
 +    OC_LOG(DEBUG, TAG, "OUT SRPUnlinkDevice2CB");
 +    return OC_STACK_DELETE_TRANSACTION;
 +
 +}
 +
 +/**
 + * Callback handler of unlink first device.
 + *
 + * @param[in] ctx             ctx value passed to callback from calling function.
 + * @param[in] handle          handle to an invocation
 + * @param[in] clientResponse  Response from queries to remote servers.
 + * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction and
 + *          OC_STACK_KEEP_TRANSACTION to keep it.
 + */
 +static OCStackApplicationResult SRPUnlinkDevice1CB(void *unlinkCtx, OCDoHandle handle,
 +        OCClientResponse *clientResponse)
 +{
 +    OC_LOG_V(INFO, TAG, "Inside SRPUnlinkDevice1CB ");
 +    VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
 +    UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
 +    (void) handle;
 +
 +    if (clientResponse)
 +    {
 +        OC_LOG(DEBUG, TAG, "Valid client response for device 1");
 +        registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_FIRST_DEVICE_RES);
 +
 +        if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
 +        {
 +            OC_LOG(DEBUG, TAG, "Credential of device 1 is revoked");
 +
 +            // Second revocation request to second device.
 +            OCStackResult res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice2CB,
 +                                                    &unlinkData->unlinkDev[0],
 +                                                    &unlinkData->unlinkDev[1] /*Dest*/);
 +            OC_LOG_V(DEBUG, TAG, "Credential revocation request device 2, result :: %d",res);
 +            if (OC_STACK_OK != res)
 +            {
 +                 OC_LOG(ERROR, TAG, "Error while sending revocation request for device 2");
 +                 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
 +                                                IDX_SECOND_DEVICE_RES);
 +                 unlinkData->resultCallback(unlinkData->ctx,
 +                                            unlinkData->numOfResults, unlinkData->unlinkRes, true);
 +                 goto error;
 +            }
 +            else
 +            {
 +                OC_LOG(DEBUG, TAG, "Request for credential revocation successfully sent");
 +                return OC_STACK_DELETE_TRANSACTION;
 +            }
 +        }
 +        else
 +        {
 +            OC_LOG(ERROR, TAG, "Unable to delete credential information from device 1");
 +
 +            unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults,
 +                                            unlinkData->unlinkRes, true);
 +            goto error;
 +        }
 +    }
 +    else
 +    {
 +        OC_LOG(DEBUG, TAG, "Invalid response from server");
 +        registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
 +                                       IDX_FIRST_DEVICE_RES );
 +        unlinkData->resultCallback(unlinkData->ctx,
 +                                   unlinkData->numOfResults, unlinkData->unlinkRes,
 +                                   true);
 +        OC_LOG(ERROR, TAG, "SRPUnlinkDevice1CB received Null clientResponse");
 +    }
 +
 +error:
 +    OC_LOG_V(INFO, TAG, "Out SRPUnlinkDevice1CB");
 +    DeleteUnlinkData_t(unlinkData);
 +    return OC_STACK_DELETE_TRANSACTION;
 +}
 +
 +/*
 +* Function to unlink devices.
 +* This function will remove the credential & relationship between the two devices.
 +*
 +* @param[in] ctx Application context would be returned in result callback
 +* @param[in] pTargetDev1 first device information to be unlinked.
 +* @param[in] pTargetDev2 second device information to be unlinked.
 +* @param[in] resultCallback callback provided by API user, callback will be called when
 +*            device unlink is finished.
 + * @return  OC_STACK_OK in case of success and other value otherwise.
 +*/
 +OCStackResult SRPUnlinkDevices(void* ctx,
 +                               const OCProvisionDev_t* pTargetDev1,
 +                               const OCProvisionDev_t* pTargetDev2,
 +                               OCProvisionResultCB resultCallback)
 +{
 +    OC_LOG(INFO, TAG, "IN SRPUnlinkDevices");
 +
 +    if (!pTargetDev1 || !pTargetDev2 || !resultCallback)
 +    {
 +        OC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL parameters");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +    OC_LOG(INFO, TAG, "Unlinking following devices: ");
 +    PMPrintOCProvisionDev(pTargetDev1);
 +    PMPrintOCProvisionDev(pTargetDev2);
 +
 +    // Mark the link status stale
 +    OCStackResult res = PDMSetLinkStale(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID);
 +    if (OC_STACK_OK != res)
 +    {
 +        OC_LOG(FATAL, TAG, "unable to update DB. Try again.");
 +        return res;
 +    }
 +
 +    UnlinkData_t* unlinkData = (UnlinkData_t*)OICCalloc(1, sizeof(UnlinkData_t));
 +    VERIFY_NON_NULL(TAG, unlinkData, ERROR, OC_STACK_NO_MEMORY);
 +
 +    //Initialize unlink data
 +    unlinkData->ctx = ctx;
 +    unlinkData->unlinkDev = (OCProvisionDev_t*)OICCalloc(2, sizeof(OCProvisionDev_t));
 +    if (NULL == unlinkData->unlinkDev)
 +    {
 +        OC_LOG(ERROR, TAG, "Memory allocation failed");
 +        res = OC_STACK_NO_MEMORY;
 +        goto error;
 +    }
 +
 +    unlinkData->unlinkRes = (OCProvisionResult_t*)OICCalloc(3, sizeof(OCProvisionResult_t));
 +    if (NULL == unlinkData->unlinkRes)
 +    {
 +        OC_LOG(ERROR, TAG, "Memory allocation failed");
 +        res = OC_STACK_NO_MEMORY;
 +        goto error;
 +    }
 +
 +    memcpy(&unlinkData->unlinkDev[0], pTargetDev1, sizeof(OCProvisionDev_t));
 +    memcpy(&unlinkData->unlinkDev[1], pTargetDev2, sizeof(OCProvisionDev_t));
 +
 +    unlinkData->numOfResults = 0;
 +    unlinkData->resultCallback = resultCallback;
 +
 +    res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice1CB,
 +                                       &unlinkData->unlinkDev[1], &unlinkData->unlinkDev[0]);
 +    if (OC_STACK_OK != res)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPUnlinkDevices : SendDeleteCredentialRequest failed");
 +        goto error;
 +    }
 +
 +    return res;
 +
 +error:
 +    OC_LOG(INFO, TAG, "OUT SRPUnlinkDevices");
 +    DeleteUnlinkData_t(unlinkData);
 +    return res;
 +}
 +
 +static void DeleteRemoveData_t(RemoveData_t* pRemoveData)
 +{
 +    if (pRemoveData)
 +    {
 +        OICFree(pRemoveData->revokeTargetDev);
 +        OCDeleteDiscoveredDevices(pRemoveData->linkedDevList);
 +        OICFree(pRemoveData->removeRes);
 +        OICFree(pRemoveData);
 +    }
 +}
 +
 +static void registerResultForRemoveDevice(RemoveData_t *removeData, OicUuid_t *pLinkedDevId,
 +                                          OCStackResult stackresult, bool hasError)
 +{
 +    OC_LOG_V(INFO, TAG, "Inside registerResultForRemoveDevice removeData->numOfResults is %d\n",
 +                         removeData->numOfResults + 1);
 +    if (pLinkedDevId)
 +    {
 +        memcpy(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
 +               &pLinkedDevId->id, sizeof(pLinkedDevId->id));
 +    }
 +    else
 +    {
 +        memset(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
 +               0, sizeof(pLinkedDevId->id) );
 +    }
 +    removeData->removeRes[(removeData->numOfResults)].res = stackresult;
 +    removeData->hasError = hasError;
 +    ++(removeData->numOfResults);
 +
 +    // If we get suffcient result from linked devices, we have to call user callback and do free
 +    if (removeData->sizeOfResArray == removeData->numOfResults)
 +    {
 +        removeData->resultCallback(removeData->ctx, removeData->numOfResults, removeData->removeRes,
 +                                   removeData->hasError);
 +        DeleteRemoveData_t(removeData);
 +    }
 + }
 +
 +/**
 + * Callback handler of unlink first device.
 + *
 + * @param[in] ctx             ctx value passed to callback from calling function.
 + * @param[in] handle          handle to an invocation
 + * @param[in] clientResponse  Response from queries to remote servers.
 + * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
 + *          and  OC_STACK_KEEP_TRANSACTION to keep it.
 + */
 +static OCStackApplicationResult SRPRemoveDeviceCB(void *delDevCtx, OCDoHandle handle,
 +        OCClientResponse *clientResponse)
 +{
 +    //Update the delete credential into delete device context
 +    //Save the deleted status in delDevCtx
 +    (void)handle;
 +    OC_LOG_V(INFO, TAG, "Inside SRPRemoveDeviceCB.");
 +    VERIFY_NON_NULL(TAG, delDevCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
 +    OCStackResult res = OC_STACK_ERROR;
 +
 +    RemoveData_t* removeData = (RemoveData_t*)delDevCtx;
 +    if (clientResponse)
 +    {
 +        // If we can get device's UUID from OCClientResponse, it'd be good to use it in here
 +        // but OCIdentity in OCClientResponse is emtpy now.
 +        // It seems that we can set identity to CAData_t *cadata in CAPrepareSendData() API
 +        // but CA doesn't have deviceID yet.
 +        //
 +        //TODO: Get OCIdentity from OCClientResponse and use it for 'registerResultForRemoveDevice'
 +        //      If we can't complete this task, Provisioning Database has always stale link status
 +        //      when Remove device is called.
 +
 +        if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
 +        {
 +            res = PDMUnlinkDevices(&removeData->revokeTargetDev->doxm->deviceID,
 +                                   NULL /*TODO: Replace NULL to uuid from OCClientResponse*/);
 +            if (OC_STACK_OK != res)
 +            {
 +                OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
 +                registerResultForRemoveDevice(removeData,
 +                                          NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
 +                                          OC_STACK_INCONSISTENT_DB, true);
 +                return OC_STACK_DELETE_TRANSACTION;
 +            }
 +            registerResultForRemoveDevice(removeData,
 +                                          NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
 +                                          OC_STACK_RESOURCE_DELETED, false);
 +        }
 +        else
 +        {
 +            registerResultForRemoveDevice(removeData,
 +                                          NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
 +                                          clientResponse->result, true);
 +            OC_LOG(ERROR, TAG, "Unexpected result from DELETE credential request!");
 +        }
 +    }
 +    else
 +    {
 +        registerResultForRemoveDevice(removeData, NULL, OC_STACK_ERROR, true);
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevices received Null clientResponse");
 +    }
 +
 +    return OC_STACK_DELETE_TRANSACTION;
 +}
 +
 +static OCStackResult GetListofDevToReqDeleteCred(const OCProvisionDev_t* pRevokeTargetDev,
 +                                                 OCProvisionDev_t* pOwnedDevList,
 +                                                 OCUuidList_t* pLinkedUuidList,
 +                                                 OCProvisionDev_t** ppLinkedDevList,
 +                                                 size_t *numOfLinkedDev)
 +{
 +    // pOwnedDevList could be NULL. It means no alived and owned device now.
 +    if (pRevokeTargetDev == NULL || pLinkedUuidList == NULL ||\
 +        ppLinkedDevList == NULL || numOfLinkedDev == NULL)
 +    {
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    size_t cnt = 0;
 +    OCUuidList_t *curUuid = NULL, *tmpUuid = NULL;
 +    LL_FOREACH_SAFE(pLinkedUuidList, curUuid, tmpUuid)
 +    {
 +        // Mark the link status stale.
 +        OCStackResult res = PDMSetLinkStale(&curUuid->dev, &pRevokeTargetDev->doxm->deviceID);
 +        if (OC_STACK_OK != res)
 +        {
 +            OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
 +            return OC_STACK_INCONSISTENT_DB;
 +        }
 +
 +        if (pOwnedDevList)
 +        {
 +            // If this linked device is alive (power-on), add the deivce to the list.
 +            OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
 +            LL_FOREACH_SAFE(pOwnedDevList, curDev, tmpDev)
 +            {
 +                if (memcmp(curDev->doxm->deviceID.id, curUuid->dev.id, sizeof(curUuid->dev.id)) == 0)
 +                {
 +                    OCProvisionDev_t* targetDev = PMCloneOCProvisionDev(curDev);
 +                    if (NULL == targetDev)
 +                    {
 +                        OC_LOG(ERROR, TAG, "SRPRemoveDevice : Cloning OCProvisionDev_t Failed.");
 +                        return OC_STACK_NO_MEMORY;
 +                    }
 +
 +                    LL_PREPEND(*ppLinkedDevList, targetDev);
 +                    cnt++;
 +                    break;
 +                }
 +            }
 +        }
 +    }
 +    *numOfLinkedDev = cnt;
 +    return OC_STACK_OK;
 +}
 +
 +/*
 +* Function to device revocation
 +* This function will remove credential of target device from all devices in subnet.
 +*
 +* @param[in] ctx Application context would be returned in result callback
 +* @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
 +* @param[in] pTargetDev Device information to be revoked.
 +* @param[in] resultCallback callback provided by API user, callback will be called when
 +*            credential revocation is finished.
 +* @return  OC_STACK_OK in case of success and other value otherwise.
 +*          If OC_STACK_OK is returned, the caller of this API should wait for callback.
 +*          OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
 +*/
 +OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
 +                             const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback)
 +{
 +    OC_LOG(INFO, TAG, "IN SRPRemoveDevice");
 +
 +    if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery)
 +    {
 +        OC_LOG(INFO, TAG, "SRPRemoveDevice : NULL parameters");
 +        return OC_STACK_INVALID_PARAM;
 +    }
 +
 +    // Declare variables in here to handle error cases with goto statement.
 +    OCProvisionDev_t* pOwnedDevList = NULL;
 +    OCProvisionDev_t* pLinkedDevList = NULL;
 +    RemoveData_t* removeData = NULL;
 +
 +    //1. Find all devices that has a credential of the revoked device
 +    OCUuidList_t* pLinkedUuidList = NULL;
 +    size_t numOfDevices = 0;
 +    OCStackResult res = OC_STACK_ERROR;
 +    res = PDMGetLinkedDevices(&pTargetDev->doxm->deviceID, &pLinkedUuidList, &numOfDevices);
 +    if (OC_STACK_OK != res)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to get linked devices information");
 +        return res;
 +    }
 +    // if there is no related device, we can skip further process.
 +    if (0 == numOfDevices)
 +    {
 +        OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No linked device found.");
 +        res = OC_STACK_CONTINUE;
 +        goto error;
 +    }
 +
 +    //2. Find owned device from the network
 +    res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList);
 +    if (OC_STACK_OK != res)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to PMDeviceDiscovery");
 +        goto error;
 +    }
 +
 +    //3. Make a list of devices to send DELETE credential request
 +    //   by comparing owned devices from provisioning database with mutlicast discovery result.
 +    size_t numOfLinkedDev = 0;
 +    res = GetListofDevToReqDeleteCred(pTargetDev, pOwnedDevList, pLinkedUuidList,
 +                                      &pLinkedDevList, &numOfLinkedDev);
 +    if (OC_STACK_OK != res)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevice : GetListofDevToReqDeleteCred() failed");
 +        goto error;
 +    }
 +    if (0 == numOfLinkedDev) // This case means, there is linked device but it's not alive now.
 +    {                       // So we don't have to send request message.
 +        OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No alived & linked device found.");
 +        res = OC_STACK_CONTINUE;
 +        goto error;
 +    }
 +
 +    // 4. Prepare RemoveData Context data.
 +    removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
 +    if (!removeData)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
 +        res = OC_STACK_NO_MEMORY;
 +        goto error;
 +    }
 +
 +    removeData->revokeTargetDev = PMCloneOCProvisionDev(pTargetDev);
 +    if (!removeData->revokeTargetDev)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevices : PMCloneOCProvisionDev Failed");
 +        res = OC_STACK_NO_MEMORY;
 +        goto error;
 +    }
 +
 +    removeData->removeRes =
 +        (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
 +    if (!removeData->removeRes)
 +    {
 +        OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
 +        res = OC_STACK_NO_MEMORY;
 +        goto error;
 +    }
 +
 +    removeData->ctx = ctx;
 +    removeData->linkedDevList = pLinkedDevList;
 +    removeData->resultCallback = resultCallback;
 +    removeData->numOfResults = 0;
 +    removeData->sizeOfResArray = numOfLinkedDev;
 +    removeData->hasError = false;
 +
 +    // 5. Send DELETE credential request to linked devices.
 +    OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
 +    OCStackResult totalRes = OC_STACK_ERROR;  /* variable for checking request is sent or not */
 +    LL_FOREACH_SAFE(pLinkedDevList, curDev, tmpDev)
 +    {
 +        res = SendDeleteCredentialRequest((void*)removeData, &SRPRemoveDeviceCB,
 +                                           removeData->revokeTargetDev, curDev);
 +        if (OC_STACK_OK != res)
 +        {
 +            OC_LOG_V(ERROR, TAG, "SRPRemoveDevice : Fail to send the DELETE credential request to\
 +                     %s:%u", curDev->endpoint.addr, curDev->endpoint.port);
 +        }
 +        else
 +        {
 +            totalRes = OC_STACK_OK; // This means at least one request is successfully sent.
 +        }
 +    }
 +
 +    PDMDestoryOicUuidLinkList(pLinkedUuidList); //TODO: Modify API name to have unified convention.
 +    PMDeleteDeviceList(pOwnedDevList);
 +    OC_LOG(INFO, TAG, "OUT SRPRemoveDevice");
 +
 +    return totalRes; // Caller of this API should wait callback if totalRes == OC_STACK_OK.
 +
 +error:
 +    PDMDestoryOicUuidLinkList(pLinkedUuidList);
 +    PMDeleteDeviceList(pOwnedDevList);
 +    PMDeleteDeviceList(pLinkedDevList);
 +    if (removeData)
 +    {
 +        OICFree(removeData->revokeTargetDev);
 +        OICFree(removeData->removeRes);
 +        OICFree(removeData);
 +    }
 +    OC_LOG(INFO, TAG, "OUT ERROR case SRPRemoveDevice");
 +    return res;
 +}
@@@ -505,139 -505,16 +505,139 @@@ static OCStackResult RemoveACE(const Oi
      return ret;
  }
  
 +/*
 + * This method parses the query string received for REST requests and
 + * retrieves the 'subject' field.
 + *
 + * @param query querystring passed in REST request
 + * @param subject subject UUID parsed from query string
 + *
 + * @return true if query parsed successfully and found 'subject', else false.
 + */
 +static bool GetSubjectFromQueryString(const char *query, OicUuid_t *subject)
 +{
 +    OicParseQueryIter_t parseIter = {.attrPos=NULL};
 +
 +    ParseQueryIterInit((unsigned char *)query, &parseIter);
 +
 +    while(GetNextQuery(&parseIter))
 +    {
 +        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0)
 +        {
 +            VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR);
 +            unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
 +            uint32_t outLen = 0;
 +            B64Result b64Ret = B64_OK;
 +            b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff,
 +                    sizeof(base64Buff), &outLen);
 +            VERIFY_SUCCESS(TAG, (B64_OK == b64Ret && outLen <= sizeof(subject->id)), ERROR);
 +            memcpy(subject->id, base64Buff, outLen);
 +
 +            return true;
 +        }
 +    }
 +
 +exit:
 +   return false;
 +}
 +
 +/*
 + * This method parses the query string received for REST requests and
 + * retrieves the 'resource' field.
 + *
 + * @param query querystring passed in REST request
 + * @param resource resource parsed from query string
 + * @param resourceSize size of the memory pointed to resource
 + *
 + * @return true if query parsed successfully and found 'resource', else false.
 + */
 +static bool GetResourceFromQueryString(const char *query, char *resource, size_t resourceSize)
 +{
 +    OicParseQueryIter_t parseIter = {.attrPos=NULL};
 +
 +    ParseQueryIterInit((unsigned char *)query, &parseIter);
 +
 +    while(GetNextQuery(&parseIter))
 +    {
 +        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0)
 +        {
 +            VERIFY_SUCCESS(TAG, 0 != parseIter.valLen, ERROR);
 +            OICStrcpy(resource, resourceSize, (char *)parseIter.valPos);
 +
 +            return true;
 +        }
 +    }
 +
 +exit:
 +   return false;
 +}
 +
 +
 +
  static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest)
  {
 -    // Convert ACL data into JSON for transmission
 -    char* jsonStr = BinToAclJSON(gAcl);
 +    OCEntityHandlerResult ehRet = OC_EH_ERROR;
 +    char* jsonStr = NULL;
 +
 +    // Process the REST querystring parameters
 +    if(ehRequest->query)
 +    {
-         OC_LOG (INFO, TAG, PCF("HandleACLGetRequest processing query"));
++        OC_LOG (INFO, TAG, "HandleACLGetRequest processing query");
 +
 +        OicUuid_t subject = {.id={0}};
 +        char resource[MAX_URI_LENGTH] = {0};
 +
 +        OicSecAcl_t *savePtr = NULL;
 +        const OicSecAcl_t *currentAce = NULL;
  
 -    /*
 -     * A device should 'always' have a default ACL. Therefore,
 -     * jsonStr should never be NULL.
 -     */
 -    OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
 +        // 'Subject' field is MUST for processing a querystring in REST request.
 +        VERIFY_SUCCESS(TAG,
 +                       true == GetSubjectFromQueryString(ehRequest->query, &subject),
 +                       ERROR);
 +
 +        GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource));
 +
 +        /*
 +         * TODO : Currently, this code only provides one ACE for a Subject.
 +         * Below code needs to be updated for scenarios when Subject have
 +         * multiple ACE's in ACL resource.
 +         */
 +        while((currentAce = GetACLResourceData(&subject, &savePtr)))
 +        {
 +            /*
 +             * If REST querystring contains a specific resource, we need
 +             * to search for that resource in ACE.
 +             */
 +            if (resource[0] != '\0')
 +            {
 +                for(size_t n = 0; n < currentAce->resourcesLen; n++)
 +                {
 +                    if((currentAce->resources[n]) &&
 +                            (0 == strcmp(resource, currentAce->resources[n]) ||
 +                             0 == strcmp(WILDCARD_RESOURCE_URI, currentAce->resources[n])))
 +                    {
 +                        // Convert ACL data into JSON for transmission
 +                        jsonStr = BinToAclJSON(currentAce);
 +                        goto exit;
 +                    }
 +                }
 +            }
 +            else
 +            {
 +                // Convert ACL data into JSON for transmission
 +                jsonStr = BinToAclJSON(currentAce);
 +                goto exit;
 +            }
 +        }
 +    }
 +    else
 +    {
 +        // Convert ACL data into JSON for transmission
 +        jsonStr = BinToAclJSON(gAcl);
 +    }
 +
 +exit:
 +    ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
  
      // Send response payload to request originator
      SendSRMResponse(ehRequest, ehRet, jsonStr);
@@@ -675,19 -552,41 +675,19 @@@ static OCEntityHandlerResult HandleACLP
  
  static OCEntityHandlerResult HandleACLDeleteRequest(const OCEntityHandlerRequest *ehRequest)
  {
-     OC_LOG (INFO, TAG, PCF("Processing ACLDeleteRequest"));
+     OC_LOG (INFO, TAG, "Processing ACLDeleteRequest");
      OCEntityHandlerResult ehRet = OC_EH_ERROR;
 -
 -    if(NULL == ehRequest->query)
 -    {
 -        return ehRet;
 -    }
 -    OicParseQueryIter_t parseIter = {.attrPos=NULL};
      OicUuid_t subject = {.id={0}};
 -    char * resource = NULL;
 -
 -    //Parsing REST query to get subject & resource
 -    ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
 +    char resource[MAX_URI_LENGTH] = {0};
  
 -    while(GetNextQuery(&parseIter))
 -    {
 -        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0)
 -        {
 -            unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
 -            uint32_t outLen = 0;
 -            B64Result b64Ret = B64_OK;
 +    VERIFY_NON_NULL(TAG, ehRequest->query, ERROR);
  
 -           b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff,
 -                               sizeof(base64Buff), &outLen);
 +    // 'Subject' field is MUST for processing a querystring in REST request.
 +    VERIFY_SUCCESS(TAG,
 +            true == GetSubjectFromQueryString(ehRequest->query, &subject),
 +            ERROR);
  
 -           VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
 -           memcpy(subject.id, base64Buff, outLen);
 -        }
 -        if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0)
 -        {
 -            resource = (char *)OICMalloc(parseIter.valLen);
 -            VERIFY_NON_NULL(TAG, resource, ERROR);
 -            OICStrcpy(resource, sizeof(resource), (char *)parseIter.valPos);
 -        }
 -    }
 +    GetResourceFromQueryString(ehRequest->query, resource, sizeof(resource));
  
      if(OC_STACK_RESOURCE_DELETED == RemoveACE(&subject, resource))
      {
@@@ -720,8 -620,8 +720,8 @@@ OCEntityHandlerResult ACLEntityHandler 
  
      if (flag & OC_REQUEST_FLAG)
      {
 -        // TODO :  Handle PUT and DEL methods
 +        // TODO :  Handle PUT method
-         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
+         OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
          switch (ehRequest->method)
          {
              case OC_REST_GET:
@@@ -433,8 -389,8 +433,8 @@@ static OCEntityHandlerResult HandleDoxm
      //Checking if Get request is a query.
      if(ehRequest->query)
      {
-         OC_LOG (INFO, TAG, PCF("HandleDoxmGetRequest processing query"));
+         OC_LOG (INFO, TAG, "HandleDoxmGetRequest processing query");
 -        if(!ValidateQuery((unsigned char *)ehRequest->query))
 +        if(!ValidateQuery(ehRequest->query))
          {
              ehRet = OC_EH_ERROR;
          }
Simple merge
@@@ -77,5 -77,11 +77,15 @@@ oclib = oclib_env.SharedLibrary('oc', o
  oclib_env.InstallTarget(oclib, 'liboc')
  oclib_env.UserInstallTargetLib(oclib, 'liboc')
  
+ src_dir = env.get('SRC_DIR')
+ oclib_env.UserInstallTargetHeader(src_dir + '/resource/include/OCApi.h', 'resource', 'OCApi.h')
+ oclib_env.UserInstallTargetHeader(src_dir + '/resource/include/OCPlatform.h', 'resource', 'OCPlatform.h')
+ oclib_env.UserInstallTargetHeader(src_dir + '/resource/include/OCRepresentation.h', 'resource', 'OCRepresentation.h')
+ oclib_env.UserInstallTargetHeader(src_dir + '/resource/include/OCResource.h', 'resource', 'OCResource.h')
+ oclib_env.UserInstallTargetHeader(src_dir + '/resource/include/OCResourceRequest.h', 'resource', 'OCResourceRequest.h')
+ oclib_env.UserInstallTargetHeader(src_dir + '/resource/include/OCResourceResponse.h', 'resource', 'OCResourceResponse.h')
++
++# Add Provisioning library
 +if target_os in ['linux', 'android'] and env.get('SECURED') == '1':
 +        SConscript('../provisioning/SConscript')