[IOT-1884] Allow IoTivity to generate and persist PIID
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocresource.c
index 2bf6d8e..3b5db32 100755 (executable)
 #include "oic_malloc.h"
 #include "oic_string.h"
 #include "logger.h"
-#include "cJSON.h"
 #include "ocpayload.h"
 #include "secureresourcemanager.h"
 #include "cacommon.h"
 #include "cainterface.h"
 #include "ocpayload.h"
+#include "oickeepalive.h"
 #include "platform_features.h"
 #include "payload_logging.h"
+#include "ocendpoint.h"
+#include "ocstackinternal.h"
+#include "oickeepalive.h"
+#include "ocpayloadcbor.h"
+#include "psinterface.h"
+
 #ifdef ROUTING_GATEWAY
 #include "routingmanager.h"
 #endif
 /// Module Name
 #define TAG "OIC_RI_RESOURCE"
 
+// Using 1k as block size since most persistent storage implementations use a power of 2.
+#define INTROSPECTION_FILE_SIZE_BLOCK  1024
+
 #define VERIFY_SUCCESS(op) { if (op != (OC_STACK_OK)) \
             {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
 
+/**
+ * Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
+ * The value of payload size is increased up to CBOR_MAX_SIZE.
+ */
+static const uint16_t CBOR_SIZE = 512;
+
+/**
+ * Max cbor size payload.
+ */
+static const uint16_t CBOR_MAX_SIZE = 4400;
+
 extern OCResource *headResource;
 
 /**
  * Prepares a Payload for response.
  */
 static OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
-                                                  OCDiscoveryPayload* payload,
-                                                  OCDevAddr *endpoint);
+                                                  OCDiscoveryPayload *payload,
+                                                  OCDevAddr *endpoint,
+                                                  CAEndpoint_t *networkInfo,
+                                                  size_t infoSize);
+
+/**
+ * Sets the value of an attribute on a resource.
+ */
+static OCStackResult SetAttributeInternal(OCResource *resource,
+                                          const char *attribute,
+                                          const void *value,
+                                          bool updateDatabase);
 
 //-----------------------------------------------------------------------------
 // Default resource entity handler function
@@ -108,7 +138,7 @@ static OCStackResult GetSecurePortInfo(OCDevAddr *endpoint, uint16_t *port)
 
 #ifdef TCP_ADAPTER
 /* This method will retrieve the tcp port */
-static OCStackResult GetTCPPortInfo(OCDevAddr *endpoint, uint16_t *port)
+static OCStackResult GetTCPPortInfo(OCDevAddr *endpoint, uint16_t *port, bool secured)
 {
     uint16_t p = 0;
 
@@ -116,11 +146,11 @@ static OCStackResult GetTCPPortInfo(OCDevAddr *endpoint, uint16_t *port)
     {
         if (endpoint->flags & OC_IP_USE_V4)
         {
-            p = caglobals.tcp.ipv4.port;
+            p = secured ? caglobals.tcp.ipv4s.port : caglobals.tcp.ipv4.port;
         }
         else if (endpoint->flags & OC_IP_USE_V6)
         {
-            p = caglobals.tcp.ipv6.port;
+            p = secured ? caglobals.tcp.ipv6s.port : caglobals.tcp.ipv6.port;
         }
     }
 
@@ -136,8 +166,13 @@ static OCStackResult GetTCPPortInfo(OCDevAddr *endpoint, uint16_t *port)
  * Resource and device filters in the SAME query are NOT validated
  * and resources will likely not clear filters.
  */
-static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char **filterTwo)
+OCStackResult ExtractFiltersFromQuery(const char *query, char **filterOne, char **filterTwo)
 {
+    if (!query)
+    {
+        OIC_LOG(ERROR, TAG, "Query is empty!");
+        return OC_STACK_INVALID_QUERY;
+    }
     char *key = NULL;
     char *value = NULL;
     char *queryDup = NULL;
@@ -151,7 +186,7 @@ static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char
     queryDup = OICStrdup(query);
     if (NULL == queryDup)
     {
-        OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
+        OIC_LOG(ERROR, TAG, "Creating duplicate string failed!");
         return OC_STACK_NO_MEMORY;
     }
 
@@ -203,7 +238,7 @@ static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char
         *filterOne = OICStrdup(*filterOne);
         if (NULL == *filterOne)
         {
-            OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
+            OIC_LOG(ERROR, TAG, "Creating duplicate string failed!");
             eCode = OC_STACK_NO_MEMORY;
             goto exit;
         }
@@ -214,7 +249,7 @@ static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char
         *filterTwo = OICStrdup(*filterTwo);
         if (NULL == *filterTwo)
         {
-            OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
+            OIC_LOG(ERROR, TAG, "Creating duplicate string failed!");
             OICFree(*filterOne);
             eCode = OC_STACK_NO_MEMORY;
             goto exit;
@@ -232,7 +267,7 @@ exit:
     return eCode;
 }
 
-static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
+OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
 {
     if (strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_URI) == 0)
     {
@@ -250,6 +285,14 @@ static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
     {
         return OC_RESOURCE_TYPES_URI;
     }
+    else if (strcmp(uriInRequest, OC_RSRVD_INTROSPECTION_URI) == 0)
+    {
+        return OC_INTROSPECTION_URI;
+    }
+    else if (strcmp(uriInRequest, OC_RSRVD_INTROSPECTION_PAYLOAD_URI) == 0)
+    {
+        return OC_INTROSPECTION_PAYLOAD_URI;
+    }
 #ifdef ROUTING_GATEWAY
     else if (0 == strcmp(uriInRequest, OC_RSRVD_GATEWAY_URI))
     {
@@ -291,14 +334,14 @@ static OCStackResult getQueryParamsForFiltering (OCVirtualResources uri, char *q
     *filterOne = NULL;
     *filterTwo = NULL;
 
-    #ifdef WITH_PRESENCE
+#ifdef WITH_PRESENCE
     if (uri == OC_PRESENCE)
     {
         //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
         OIC_LOG(INFO, TAG, "OC_PRESENCE Request for virtual resource.");
         return OC_STACK_OK;
     }
-    #endif
+#endif
 
     OCStackResult result = OC_STACK_OK;
 
@@ -310,36 +353,78 @@ static OCStackResult getQueryParamsForFiltering (OCVirtualResources uri, char *q
     return result;
 }
 
-bool appendOCStringLL(OCRepPayload *device, OCStringLL *dmv)
+static OCStackResult BuildDevicePlatformPayload(const OCResource *resourcePtr, OCRepPayload** payload,
+    bool addDeviceId)
 {
-    int size = 0;
-    for (OCStringLL *ll = dmv; ll; ll = ll->next, size++);
-    size_t dim[MAX_REP_ARRAY_DEPTH] = {size, 0, 0};
-    char **dt = (char **)OICMalloc(sizeof(char *) * size);
-    int i = 0;
-    VERIFY_PARAM_NON_NULL(TAG, dt, "Data Model Version allocation failed.");
-    for (OCStringLL *ll = dmv; ll; ll = ll->next, i++)
+    OCRepPayload *tempPayload = OCRepPayloadCreate();
+
+    if (!resourcePtr)
     {
-        dt[i] = OICStrdup(ll->value);
-        VERIFY_PARAM_NON_NULL(TAG, dt[i], "Data Model Version adding failed.");
+        OCRepPayloadDestroy(tempPayload);
+        return OC_STACK_INVALID_PARAM;
     }
-    if (!OCRepPayloadSetStringArrayAsOwner(device, OC_RSRVD_DATA_MODEL_VERSION, dt, dim))
+
+    if (!tempPayload)
     {
-        goto exit;
+        return OC_STACK_NO_MEMORY;
     }
-    return true;
 
-exit:
-    for (int i = 0; i < size; i++)
+    if (addDeviceId)
+    {
+        const char *deviceId = OCGetServerInstanceIDString();
+        if (!deviceId)
+        {
+            OIC_LOG(ERROR, TAG, "Failed retrieving device id.");
+            return OC_STACK_ERROR;
+        }
+        OCRepPayloadSetPropString(tempPayload, OC_RSRVD_DEVICE_ID, deviceId);
+    }
+
+    for (OCResourceType *resType = resourcePtr->rsrcType; resType; resType = resType->next)
     {
-        OICFree(dt[i]);
+        OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename);
     }
-    OICFree(dt);
-    return false;
+
+    for (OCResourceInterface *resInterface = resourcePtr->rsrcInterface; resInterface;
+        resInterface = resInterface->next)
+    {
+        OCRepPayloadAddInterface(tempPayload, resInterface->name);
+    }
+
+    for (OCAttribute *resAttrib = resourcePtr->rsrcAttributes; resAttrib; resAttrib = resAttrib->next)
+    {
+        if (resAttrib->attrName && resAttrib->attrValue)
+        {
+            if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, resAttrib->attrName))
+            {
+                char *dmv = OCCreateString((OCStringLL *)resAttrib->attrValue);
+                if (dmv)
+                {
+                    OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, dmv);
+                    OICFree(dmv);
+                }
+            }
+            else
+            {
+                OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, (char *)resAttrib->attrValue);
+            }
+        }
+    }
+
+    if (!*payload)
+    {
+        *payload = tempPayload;
+    }
+    else
+    {
+        OCRepPayloadAppend(*payload, tempPayload);
+    }
+
+    return OC_STACK_OK;
 }
 
 OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
-                    OCRepPayload** payload)
+                    OCRepPayload** payload, OCDevAddr *devAddr)
 {
     OCRepPayload *tempPayload = OCRepPayloadCreate();
 
@@ -354,46 +439,833 @@ OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
         return OC_STACK_NO_MEMORY;
     }
 
-    OCRepPayloadSetUri(tempPayload, resourcePtr->uri);
+    OCRepPayloadSetPropString(tempPayload, OC_RSRVD_HREF, resourcePtr->uri);
 
-    OCResourceType *resType = resourcePtr->rsrcType;
-    while(resType)
+    uint8_t numElement = 0;
+    if (OC_STACK_OK == OCGetNumberOfResourceTypes((OCResource *)resourcePtr, &numElement))
     {
-        OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename);
+        size_t rtDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
+        char **rt = (char **)OICMalloc(sizeof(char *) * numElement);
+        for (uint8_t i = 0; i < numElement; ++i)
+        {
+            const char *value = OCGetResourceTypeName((OCResource *)resourcePtr, i);
+            OIC_LOG_V(DEBUG, TAG, "value: %s", value);
+            rt[i] = OICStrdup(value);
+        }
+        OCRepPayloadSetStringArrayAsOwner(tempPayload, OC_RSRVD_RESOURCE_TYPE, rt, rtDim);
+    }
+
+    numElement = 0;
+    if (OC_STACK_OK == OCGetNumberOfResourceInterfaces((OCResource *)resourcePtr, &numElement))
+    {
+        size_t ifDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
+        char **itf = (char **)OICMalloc(sizeof(char *) * numElement);
+        for (uint8_t i = 0; i < numElement; ++i)
+        {
+            const char *value = OCGetResourceInterfaceName((OCResource *)resourcePtr, i);
+            OIC_LOG_V(DEBUG, TAG, "value: %s", value);
+            itf[i] = OICStrdup(value);
+        }
+        OCRepPayloadSetStringArrayAsOwner(tempPayload, OC_RSRVD_INTERFACE, itf, ifDim);
+    }
+
+    for (OCAttribute *resAttrib = resourcePtr->rsrcAttributes; resAttrib; resAttrib = resAttrib->next)
+    {
+        if (resAttrib->attrName && resAttrib->attrValue)
+        {
+            OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, (char *)resAttrib->attrValue);
+        }
+    }
+
+    OCResourceProperty p = OCGetResourceProperties((OCResourceHandle *)resourcePtr);
+    OCRepPayload *policy = OCRepPayloadCreate();
+    if (!policy)
+    {
+        OCPayloadDestroy((OCPayload *)tempPayload);
+        return OC_STACK_NO_MEMORY;
+    }
+    OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE)));
+    if (p & OC_SECURE)
+    {
+        OCRepPayloadSetPropBool(policy, OC_RSRVD_SECURE, p & OC_SECURE);
+        uint16_t securePort = 0;
+        if (GetSecurePortInfo(devAddr, &securePort) != OC_STACK_OK)
+        {
+            securePort = 0;
+        }
+        OCRepPayloadSetPropInt(policy, OC_RSRVD_HOSTING_PORT, securePort);
+    }
+    OCRepPayloadSetPropObjectAsOwner(tempPayload, OC_RSRVD_POLICY, policy);
+
+    if (!*payload)
+    {
+        *payload = tempPayload;
+    }
+    else
+    {
+        OCRepPayloadAppend(*payload, tempPayload);
+    }
+
+    return OC_STACK_OK;
+}
+
+void CleanUpDeviceProperties(OCDeviceProperties **deviceProperties)
+{
+    if (!deviceProperties || !(*deviceProperties))
+    {
+        return;
+    }
+
+    OICFreeAndSetToNull((void**)(deviceProperties));
+}
+
+static OCStackResult CreateDeviceProperties(const char *piid, OCDeviceProperties **deviceProperties)
+{
+    OIC_LOG(DEBUG, TAG, "CreateDeviceProperties IN");
+
+    OCStackResult result = OC_STACK_OK;
+
+    if (!piid || !deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *deviceProperties = (OCDeviceProperties*)OICCalloc(1, sizeof(OCDeviceProperties));
+    if (*deviceProperties)
+    {
+        OICStrcpy((*deviceProperties)->protocolIndependentId, UUID_STRING_SIZE, piid);
+    }
+    else
+    {
+        result = OC_STACK_NO_MEMORY;
+    }
+
+    OIC_LOG(DEBUG, TAG, "CreateDeviceProperties OUT");
+
+    return result;
+}
+
+static OCStackResult GenerateDeviceProperties(OCDeviceProperties **deviceProperties)
+{
+    OCStackResult result = OC_STACK_OK;
+    OicUuid_t generatedProtocolIndependentId = {.id = {0}};
+    char* protocolIndependentId = NULL;
+
+    if (!deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *deviceProperties = NULL;
+
+    // Generate a UUID for the Protocol Independent ID
+    if (OCGenerateUuid(generatedProtocolIndependentId.id))
+    {
+        protocolIndependentId = (char*)OICCalloc(UUID_STRING_SIZE, sizeof(char));
+        if (protocolIndependentId)
+        {
+            if (!OCConvertUuidToString(generatedProtocolIndependentId.id, protocolIndependentId))
+            {
+                OIC_LOG(ERROR, TAG, "ConvertUuidToStr failed");
+                result = OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            result = OC_STACK_NO_MEMORY;
+        }
+    }
+    else
+    {
+        OIC_LOG(FATAL, TAG, "Generate UUID for Device Properties Protocol Independent ID failed!");
+        result = OC_STACK_ERROR;
+    }
+
+    if (OC_STACK_OK == result)
+    {
+        result = CreateDeviceProperties(protocolIndependentId, deviceProperties);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "CreateDeviceProperties failed");
+        }
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&protocolIndependentId);
+
+    return result;
+}
+
+OCStackResult CBORPayloadToDeviceProperties(const uint8_t *payload, size_t size, OCDeviceProperties **deviceProperties)
+{
+    OCStackResult result = OC_STACK_OK;
+    CborError cborResult = CborNoError;
+    char* protocolIndependentId = NULL;
+    CborParser parser;
+    CborValue dpCbor;
+    CborValue dpMap;
+
+    if (!payload || (size <= 0) || !deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *deviceProperties = NULL;
+
+    cbor_parser_init(payload, size, 0, &parser, &dpCbor);
+
+    // Protocol Independent ID - Mandatory
+    cborResult = cbor_value_map_find_value(&dpCbor, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &dpMap);
+    if ((CborNoError == cborResult) && cbor_value_is_text_string(&dpMap))
+    {
+        size_t len = 0;
+
+        cborResult = cbor_value_dup_text_string(&dpMap, &protocolIndependentId, &len, NULL);
+        if (CborNoError != cborResult)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to get Protocol Independent Id!");
+            result = OC_STACK_ERROR;
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Protocol Independent Id is not present or invalid!");
+        result = OC_STACK_ERROR;
+    }
+
+    if (OC_STACK_OK == result)
+    {
+        result = CreateDeviceProperties(protocolIndependentId, deviceProperties);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "CreateDeviceProperties failed");
+        }
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&protocolIndependentId);
+
+    return result;
+}
+
+OCStackResult DevicePropertiesToCBORPayload(const OCDeviceProperties *deviceProperties, uint8_t **payload, size_t *size)
+{
+    OCStackResult result = OC_STACK_OK;
+    CborError cborResult = CborNoError;
+    uint8_t *cborPayload = NULL;
+    size_t cborLen = CBOR_SIZE;
+    CborEncoder encoder;
+    CborEncoder dpMap;
+
+    if (!deviceProperties || !payload || !size || (*size > CBOR_MAX_SIZE))
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    // Reset the CBOR length if we need to
+    if (*size > 0)
+    {
+        cborLen = *size;
+    }
+
+    *payload = NULL;
+    *size = 0;
+
+    cborPayload = (uint8_t*)OICCalloc(1, cborLen);
+    if (NULL != cborPayload)
+    {
+        cbor_encoder_init(&encoder, cborPayload, cborLen, 0);
+
+        // Create the Device Properties encoder map
+        cborResult = cbor_encoder_create_map(&encoder, &dpMap, CborIndefiniteLength);
+        if (CborNoError != cborResult)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to create encoder map!");
+            result = OC_STACK_ERROR;
+        }
+    }
+    else
+    {
+        result = OC_STACK_NO_MEMORY;
+    }
+
+    // Protocol Independent ID - Mandatory
+    if (OC_STACK_OK == result)
+    {
+        cborResult = cbor_encode_text_string(&dpMap, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, strlen(OC_RSRVD_PROTOCOL_INDEPENDENT_ID));
+        if (CborNoError == cborResult)
+        {
+            cborResult = cbor_encode_text_string(&dpMap,
+                                                 deviceProperties->protocolIndependentId,
+                                                 strlen(deviceProperties->protocolIndependentId));
+            if (CborNoError != cborResult)
+            {
+                OIC_LOG(ERROR, TAG, "Failed to encode protocolIndependentId!");
+                result = OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "Failed to encode OC_RSRVD_PROTOCOL_INDEPENDENT_ID!");
+            result = OC_STACK_ERROR;
+        }
+    }
+
+    // Encoding is finished
+    if (OC_STACK_OK == result)
+    {
+        cborResult = cbor_encoder_close_container(&encoder, &dpMap);
+        if (CborNoError != cborResult)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to close dpMap container!");
+            result = OC_STACK_ERROR;
+        }
+    }
+
+    if (OC_STACK_OK == result)
+    {
+        *size = cbor_encoder_get_buffer_size(&encoder, cborPayload);
+        *payload = cborPayload;
+        cborPayload = NULL;
+    }
+    else if ((CborErrorOutOfMemory == cborResult) && (cborLen < CBOR_MAX_SIZE))
+    {
+        OICFreeAndSetToNull((void**)&cborPayload);
+
+        // Realloc and try again
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
+        result = DevicePropertiesToCBORPayload(deviceProperties, payload, &cborLen);
+        if (OC_STACK_OK == result)
+        {
+            *size = cborLen;
+        }
+    }
+    else
+    {
+        OICFreeAndSetToNull((void**)&cborPayload);
+    }
+
+    return result;
+}
+
+static OCStackResult UpdateDeviceInfoResourceWithDeviceProperties(const OCDeviceProperties *deviceProperties, bool updateDatabase)
+{
+    OCStackResult result = OC_STACK_OK;
+    OCResource *resource = NULL;
+
+    if (!deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    resource = FindResourceByUri(OC_RSRVD_DEVICE_URI);
+    if (resource)
+    {
+        result = SetAttributeInternal(resource, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, deviceProperties->protocolIndependentId, updateDatabase);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "OCSetPropertyValue failed to set Protocol Independent ID");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Resource does not exist.");
+        result = OC_STACK_NO_RESOURCE;
+    }
+
+    return result;
+}
+
+static OCStackResult ReadDevicePropertiesFromDatabase(OCDeviceProperties **deviceProperties)
+{
+    uint8_t *data = NULL;
+    size_t size = 0;
+
+    OCStackResult result = ReadDatabaseFromPS(OC_DEVICE_PROPS_FILE_NAME, OC_JSON_DEVICE_PROPS_NAME, &data, &size);
+    if (OC_STACK_OK == result)
+    {
+        // Read device properties from PS
+        result = CBORPayloadToDeviceProperties(data, size, deviceProperties);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(WARNING, TAG, "CBORPayloadToDeviceProperties failed");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "ReadDatabaseFromPS failed");
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&data);
+
+    return result;
+}
+
+static OCStackResult UpdateDevicePropertiesDatabase(const OCDeviceProperties *deviceProperties)
+{
+    OCStackResult result = OC_STACK_OK;
+    uint8_t *payload = NULL;
+    size_t size = 0;
+
+    if (!deviceProperties)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    // Check to see if persistent storage exists. If it doesn't then
+    // we just allow the device properties to exist in memory and
+    // it is the application's job to manage them.
+    if (!OCGetPersistentStorageHandler())
+    {
+        OIC_LOG(DEBUG, TAG, "Persistent Storage handler is NULL.");
+        return OC_STACK_OK;
+    }
+
+    // Convert OCDeviceProperties into CBOR to use for updating Persistent Storage
+    result = DevicePropertiesToCBORPayload(deviceProperties, &payload, &size);
+    if ((OC_STACK_OK == result) && payload)
+    {
+        result = UpdateResourceInPS(OC_DEVICE_PROPS_FILE_NAME, OC_JSON_DEVICE_PROPS_NAME, payload, size);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG_V(ERROR, TAG, "UpdateResourceInPS failed with %d!", result);
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "DevicePropertiesToCBORPayload failed with %d!", result);
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull((void**)&payload);
+
+    return result;
+}
+
+OCStackResult InitializeDeviceProperties()
+{
+    OIC_LOG(DEBUG, TAG, "InitializeDeviceProperties IN");
+
+    OCStackResult result = OC_STACK_OK;
+    OCDeviceProperties *deviceProperties = NULL;
+    bool updateDatabase = false;
+
+    // Populate OCDeviceProperties from persistent storage
+    result = ReadDevicePropertiesFromDatabase(&deviceProperties);
+    if (OC_STACK_OK != result)
+    {
+        OIC_LOG(ERROR, TAG, "ReadDevicePropertiesFromDatabase failed");
+    }
+
+    // If the device properties in persistent storage are corrupted or
+    // not available for some reason, a default OCDeviceProperties is created.
+    if ((OC_STACK_OK != result) || !deviceProperties)
+    {
+        result = GenerateDeviceProperties(&deviceProperties);
+        if (OC_STACK_OK == result)
+        {
+            updateDatabase = true;
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "GenerateDeviceProperties failed");
+        }
+    }
+
+    // Set the device properties information on the device info resource. This will
+    // also persist OCDeviceProperties so they can be used in the future if they are
+    // not already in the database.
+    if (OC_STACK_OK == result)
+    {
+        result = UpdateDeviceInfoResourceWithDeviceProperties(deviceProperties, updateDatabase);
+        if (OC_STACK_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "UpdateDeviceInfoResourceWithDeviceProperties failed");
+        }
+    }
+
+    // Clean Up
+    CleanUpDeviceProperties(&deviceProperties);
+
+    OIC_LOG(DEBUG, TAG, "InitializeDeviceProperties OUT");
+
+    return result;
+}
+
+static size_t GetIntrospectionDataSize(const OCPersistentStorage *ps)
+{
+    size_t size = 0;
+    char buffer[INTROSPECTION_FILE_SIZE_BLOCK];
+    FILE *fp;
+
+    if (!ps)
+    {
+        return 0;
+    }
+
+    fp = ps->open(OC_INTROSPECTION_FILE_NAME, "rb");
+    if (fp)
+    {
+        size_t bytesRead = 0;
+        do
+        {
+            bytesRead = ps->read(buffer, 1, INTROSPECTION_FILE_SIZE_BLOCK, fp);
+            size += bytesRead;
+        } while (bytesRead);
+        ps->close(fp);
+    }
+    return size;
+}
+
+OCStackResult GetIntrospectionDataFromPS(char **data, size_t *size)
+{
+    OIC_LOG(DEBUG, TAG, "GetIntrospectionDataFromPS IN");
+
+    FILE *fp = NULL;
+    uint8_t *fsData = NULL;
+    size_t fileSize = 0;
+    OCStackResult ret = OC_STACK_ERROR;
+    OCPersistentStorage *ps = NULL;
+
+    if (!data || *data || !size)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    ps = OCGetPersistentStorageHandler();
+    if (!ps)
+    {
+        OIC_LOG(ERROR, TAG, "Persistent Storage handler is NULL");
+        goto exit;
+    }
+
+    fileSize = GetIntrospectionDataSize(ps);
+    OIC_LOG_V(DEBUG, TAG, "File Read Size: %zu", fileSize);
+    if (fileSize)
+    {
+        // allocate one more byte to accomodate null terminator for string we are reading.
+        fsData = (uint8_t *)OICCalloc(1, fileSize + 1);
+        if (!fsData)
+        {
+            OIC_LOG(ERROR, TAG, "Could not allocate memory for introspection data");
+            goto exit;
+        }
+
+        fp = ps->open(OC_INTROSPECTION_FILE_NAME, "rb");
+        if (!fp)
+        {
+            OIC_LOG(ERROR, TAG, "Could not open persistent storage file for introspection data");
+            goto exit;
+        }
+        if (ps->read(fsData, 1, fileSize, fp) == fileSize)
+        {
+            *size = fileSize;
+            fsData[fileSize] = '\0';
+            *data = (char *)fsData;
+            fsData = NULL;
+            ret = OC_STACK_OK;
+        }
+    }
+    OIC_LOG(DEBUG, TAG, "GetIntrospectionDataFromPS OUT");
+
+exit:
+    if (fp)
+    {
+        ps->close(fp);
+    }
+    if (fsData)
+    {
+        OICFree(fsData);
+    }
+    return ret;
+}
+
+OCStackResult BuildIntrospectionPayloadResponse(const OCResource *resourcePtr,
+    OCRepPayload** payload, OCDevAddr *devAddr)
+{
+    OCRepPayload *tempPayload = NULL;
+    OCStackResult ret;
+    char *introspectionData = NULL;
+    size_t size = 0;
+    ret = GetIntrospectionDataFromPS(&introspectionData, &size);
+    if (OC_STACK_OK == ret)
+    {
+        OCRepPayload *tempPayload = OCRepPayloadCreate();
+        if (tempPayload)
+        {
+            if (OCRepPayloadSetPropStringAsOwner(tempPayload, OC_RSRVD_INTROSPECTION_DATA_NAME, introspectionData))
+            {
+                *payload = tempPayload;
+            }
+        }
+        else
+        {
+            ret = OC_STACK_NO_MEMORY;
+        }
+    }
+    if (ret != OC_STACK_OK)
+    {
+        OICFree(introspectionData);
+        OCRepPayloadDestroy(tempPayload);
+    }
+
+    return ret;
+}
+
+OCRepPayload *BuildUrlInfoWithProtocol(const char *protocol)
+{
+    OCStackResult result = OC_STACK_OK;
+    OCRepPayload *urlInfoPayload = OCRepPayloadCreate();
+    if (!urlInfoPayload)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to create a new RepPayload");
+        result = OC_STACK_NO_MEMORY;
+        goto exit;
+    }
+
+    if (!OCRepPayloadSetPropString(urlInfoPayload, OC_RSRVD_INTROSPECTION_URL, OC_RSRVD_INTROSPECTION_PAYLOAD_URI))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to add url");
+        result = OC_STACK_ERROR;
+        goto exit;
+    }
+    if (!OCRepPayloadSetPropString(urlInfoPayload, OC_RSRVD_INTROSPECTION_PROTOCOL, protocol))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to add protocol");
+        result = OC_STACK_ERROR;
+        goto exit;
+    }
+    if (!OCRepPayloadSetPropString(urlInfoPayload, OC_RSRVD_INTROSPECTION_CONTENT_TYPE, OC_RSRVD_INTROSPECTION_CONTENT_TYPE_VALUE))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to add content type");
+        result = OC_STACK_ERROR;
+        goto exit;
+    }
+    if (!OCRepPayloadSetPropInt(urlInfoPayload, OC_RSRVD_INTROSPECTION_VERSION, OC_RSRVD_INTROSPECTION_VERSION_VALUE))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to add version");
+        result = OC_STACK_ERROR;
+        goto exit;
+    }
+
+exit:
+    if (result != OC_STACK_OK)
+    {
+        OCRepPayloadDestroy(urlInfoPayload);
+        urlInfoPayload = NULL;
+    }
+    return urlInfoPayload;
+}
+
+OCStackResult AddProtocolToLL(OCStringLL **protoLL, const char *protocol)
+{
+    OCStringLL* cur = *protoLL;
+    // Check if protocol is already in list
+    while (cur)
+    {
+        if (strcmp(cur->value, protocol) == 0)
+        {
+            break;
+        }
+        cur = cur->next;
+    }
+    if (cur)
+    {
+        // The intent of the protocol list is to collect all unique protocols available on this
+        // endpoint. Set an error that can be used to skip processing this protocol further as
+        // it already exists in the list.
+        return OC_STACK_INVALID_PARAM;
+    }
+    else
+    {
+        cur = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
+        if (!cur)
+        {
+            return OC_STACK_NO_MEMORY;
+        }
+    }
+
+    cur->value = OICStrdup(protocol);
+    if (!cur->value)
+    {
+        OICFree(cur);
+        return OC_STACK_NO_MEMORY;
+    }
+
+    cur->next = *protoLL;
+    *protoLL = cur;
+    return OC_STACK_OK;
+}
+
+void FreeProtocolLL(OCStringLL *protoLL)
+{
+    OCStringLL* cur = protoLL;
+    while (cur)
+    {
+        OCStringLL *temp = cur;
+        cur = cur->next;
+        OICFree(temp->value);
+        OICFree(temp);
+    }
+}
+
+OCStackResult BuildIntrospectionResponseRepresentation(const OCResource *resourcePtr,
+    OCRepPayload** payload, OCDevAddr *devAddr)
+{
+    size_t dimensions[3] = { 0, 0, 0 };
+    OCRepPayload *tempPayload = NULL;
+    OCRepPayload **urlInfoPayload = NULL;
+    OCStringLL *protoLL = NULL;
+    OCStackResult ret = OC_STACK_OK;
+    OCResourceType *resType = NULL;
+    OCResourceInterface *resInterface = NULL;
+
+    if (!resourcePtr)
+    {
+        ret = OC_STACK_INVALID_PARAM;
+        goto exit;
+    }
+
+    tempPayload = OCRepPayloadCreate();
+    if (!tempPayload)
+    {
+        ret = OC_STACK_NO_MEMORY;
+        goto exit;
+    }
+
+    if (!OCRepPayloadSetUri(tempPayload, resourcePtr->uri))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to set payload URI");
+        ret = OC_STACK_ERROR;
+        goto exit;
+    }
+
+    resType = resourcePtr->rsrcType;
+    while (resType)
+    {
+        if (!OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename))
+        {
+            OIC_LOG(ERROR, TAG, "Failed at add resource type");
+            ret = OC_STACK_ERROR;
+            goto exit;
+        }
         resType = resType->next;
     }
 
-    OCResourceInterface *resInterface = resourcePtr->rsrcInterface;
-    while(resInterface)
+    resInterface = resourcePtr->rsrcInterface;
+    while (resInterface)
+    {
+        if (!OCRepPayloadAddInterface(tempPayload, resInterface->name))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to add interface");
+            ret = OC_STACK_ERROR;
+            goto exit;
+        }
+        resInterface = resInterface->next;
+    }
+    if (!OCRepPayloadSetPropString(tempPayload, OC_RSRVD_INTROSPECTION_NAME, OC_RSRVD_INTROSPECTION_NAME_VALUE))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to set Name property.");
+        ret = OC_STACK_ERROR;
+        goto exit;
+    }
+
+    // Figure out which protocols this endpoint supports
+    if (resourcePtr->endpointType & OC_COAP)
+    {
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, COAP_STR))
+        {
+            dimensions[0]++;
+        }
+    }
+    if (resourcePtr->endpointType & OC_COAPS)
+    {
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, COAPS_STR))
+        {
+            dimensions[0]++;
+        }
+    }
+#ifdef TCP_ADAPTER
+    if (resourcePtr->endpointType & OC_COAP_TCP)
+    {
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, COAP_STR))
+        {
+            dimensions[0]++;
+        }
+    }
+    if (resourcePtr->endpointType & OC_COAPS_TCP)
+    {
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, COAPS_STR))
+        {
+            dimensions[0]++;
+        }
+    }
+#endif
+#ifdef HTTP_ADAPTER
+    if (resourcePtr->endpointType & OC_HTTP)
+    {
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, HTTP_STR))
+        {
+            dimensions[0]++;
+        }
+    }
+    if (resourcePtr->endpointType & OC_HTTPS)
+    {
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, HTTPS_STR))
+        {
+            dimensions[0]++;
+        }
+    }
+#endif
+#ifdef EDR_ADAPTER
+    if (resourcePtr->endpointType & OC_COAP_RFCOMM)
     {
-        OCRepPayloadAddInterface(tempPayload, resInterface->name);
-        resInterface = resInterface->next;
+        if (OC_STACK_OK == AddProtocolToLL(&protoLL, COAP_STR))
+        {
+            dimensions[0]++;
+        }
     }
-
-    OCAttribute *resAttrib = resourcePtr->rsrcAttributes;
-    while(resAttrib)
+#endif
+    // Add a urlInfo object for each protocol supported
+    if (dimensions[0] >= 0)
     {
-        if (resAttrib->attrName && resAttrib->attrValue)
+        urlInfoPayload = (OCRepPayload **)OICMalloc(dimensions[0] * sizeof(OCRepPayload));
+        if (urlInfoPayload)
         {
-            if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, resAttrib->attrName))
+            OCStringLL *proto = protoLL;
+            size_t i = 0;
+            while (proto)
             {
-                appendOCStringLL(tempPayload, (OCStringLL *)resAttrib->attrValue);
+                urlInfoPayload[i] = BuildUrlInfoWithProtocol(proto->value);
+                if (!urlInfoPayload[i])
+                {
+                    OIC_LOG(ERROR, TAG, "Unable to build urlInfo object for protocol");
+                    ret = OC_STACK_ERROR;
+                    goto exit;
+                }
+                proto = proto->next;
+                i++;
             }
-            else
+            if (!OCRepPayloadSetPropObjectArrayAsOwner(tempPayload,
+                                                       OC_RSRVD_INTROSPECTION_URL_INFO,
+                                                       urlInfoPayload,
+                                                       dimensions))
             {
-                OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, (char *)resAttrib->attrValue);
+                OIC_LOG(ERROR, TAG, "Unable to add urlInfo object to introspection payload ");
+                ret = OC_STACK_ERROR;
+                goto exit;
             }
         }
-        resAttrib = resAttrib->next;
+        else
+        {
+            OIC_LOG(ERROR, TAG, "Unable to allocate memory for urlInfo ");
+            ret = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
     }
 
-    OCResourceProperty p = OCGetResourceProperties((OCResourceHandle *)resourcePtr);
-    p = (OCResourceProperty) ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE));
-    OCRepPayload *policy = OCRepPayloadCreate();
-    OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, p);
-    OCRepPayloadSetPropObjectAsOwner(tempPayload, OC_RSRVD_POLICY, policy);
-
-    if(!*payload)
+    if (!*payload)
     {
         *payload = tempPayload;
     }
@@ -401,12 +1273,25 @@ OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
     {
         OCRepPayloadAppend(*payload, tempPayload);
     }
+exit:
+    if (ret != OC_STACK_OK)
+    {
+        OCRepPayloadDestroy(tempPayload);
+        if (urlInfoPayload)
+        {
+            OICFree(urlInfoPayload);
+        }
+    }
+    FreeProtocolLL(protoLL);
 
     return OC_STACK_OK;
 }
 
 OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
-                        OCDiscoveryPayload *payload, OCDevAddr *devAddr)
+                                           OCDiscoveryPayload *payload,
+                                           OCDevAddr *devAddr,
+                                           CAEndpoint_t *networkInfo,
+                                           size_t infoSize)
 {
     if (!resourcePtr || !payload)
     {
@@ -421,35 +1306,25 @@ OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
        }
     }
 
-#ifdef TCP_ADAPTER
-    uint16_t tcpPort = 0;
-    if (GetTCPPortInfo(devAddr, &tcpPort) != OC_STACK_OK)
+    bool isVirtual = false;
+    if (GetTypeOfVirtualURI(resourcePtr->uri) != OC_UNKNOWN_URI)
     {
-        tcpPort = 0;
+        isVirtual = true;
     }
-    OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort, tcpPort);
+#ifdef TCP_ADAPTER
+    uint16_t tcpPort = 0;
+    GetTCPPortInfo(devAddr, &tcpPort, (resourcePtr->resourceProperties & OC_SECURE));
+
+    OCDiscoveryPayloadAddResourceWithEps(payload, resourcePtr, securePort,
+                                         isVirtual, networkInfo, infoSize, devAddr, tcpPort);
 #else
-    OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort);
+    OCDiscoveryPayloadAddResourceWithEps(payload, resourcePtr, securePort,
+                                         isVirtual, networkInfo, infoSize, devAddr);
 #endif
 
     return OC_STACK_OK;
 }
 
-uint8_t IsCollectionResource (OCResource *resource)
-{
-    if(!resource)
-    {
-        return 0;
-    }
-
-    if(resource->rsrcChildResourcesHead != NULL)
-    {
-        return 1;
-    }
-
-    return 0;
-}
-
 OCResource *FindResourceByUri(const char* resourceUri)
 {
     if(!resourceUri)
@@ -470,6 +1345,37 @@ OCResource *FindResourceByUri(const char* resourceUri)
     return NULL;
 }
 
+OCStackResult CheckRequestsEndpoint(const OCDevAddr *reqDevAddr,
+                                    OCTpsSchemeFlags resTpsFlags)
+{
+    if (!reqDevAddr)
+    {
+        OIC_LOG(ERROR, TAG, "OCDevAddr* is NULL!!!");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OCTpsSchemeFlags reqTpsFlags = OC_NO_TPS;
+    OCStackResult result = OCGetMatchedTpsFlags((CATransportAdapter_t)reqDevAddr->adapter,
+                                  (CATransportFlags_t)reqDevAddr->flags, &reqTpsFlags);
+
+    if (result != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed at get TPS flags. errcode is %d", result);
+        return result;
+    }
+
+    // bit compare between request tps flags and resource tps flags
+    if (reqTpsFlags & resTpsFlags)
+    {
+        OIC_LOG(INFO, TAG, "Request come from registered TPS");
+        return OC_STACK_OK;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Request come from unregistered TPS!!!");
+        return OC_STACK_BAD_ENDPOINT;
+    }
+}
 
 OCStackResult DetermineResourceHandling (const OCServerRequest *request,
                                          ResourceHandling *handling,
@@ -500,6 +1406,27 @@ OCStackResult DetermineResourceHandling (const OCServerRequest *request,
     {
         OCResource *resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
         *resource = resourcePtr;
+
+        // Checking resource TPS flags if resource exist in stack.
+        if (resourcePtr)
+        {
+            OCStackResult result = CheckRequestsEndpoint(&(request->devAddr), resourcePtr->endpointType);
+
+            if (result != OC_STACK_OK)
+            {
+                if (result == OC_STACK_BAD_ENDPOINT)
+                {
+                    OIC_LOG(ERROR, TAG, "Request come from bad endpoint. ignore request!!!");
+                    return OC_STACK_BAD_ENDPOINT;
+                }
+                else
+                {
+                    OIC_LOG_V(ERROR, TAG, "Failed at get tps flag errcode: %d", result);
+                    return result;
+                }
+            }
+        }
+
         if (!resourcePtr)
         {
             if(defaultDeviceHandler)
@@ -514,7 +1441,7 @@ OCStackResult DetermineResourceHandling (const OCServerRequest *request,
             return OC_STACK_NO_RESOURCE;
         }
 
-        if (IsCollectionResource (resourcePtr))
+        if (resourcePtr && resourcePtr->rsrcChildResourcesHead != NULL)
         {
             // Collection resource
             if (resourcePtr->entityHandler != defaultResourceEHandler)
@@ -594,21 +1521,26 @@ static bool resourceMatchesRTFilter(OCResource *resource, char *resourceTypeFilt
         return false;
     }
 
-    // Null or empty is analogous to no filter.
-    if (resourceTypeFilter == NULL || *resourceTypeFilter == 0)
+    // Null is analogous to no filter.i.e. query is of form /oic/res?if=oic.if.baseline or /oic/res,
+    // without rt query.
+    if (NULL == resourceTypeFilter)
     {
         return true;
     }
 
-    OCResourceType *resourceTypePtr = resource->rsrcType;
+    // Empty resourceType filter is analogous to error query
+    // It is an error as query is of form /oic/res?rt=
+    if (0 == strlen(resourceTypeFilter))
+    {
+        return false;
+    }
 
-    while (resourceTypePtr)
+    for (OCResourceType *rtPtr = resource->rsrcType; rtPtr; rtPtr = rtPtr->next)
     {
-        if (strcmp (resourceTypePtr->resourcetypename, resourceTypeFilter) == 0)
+        if (0 == strcmp(rtPtr->resourcetypename, resourceTypeFilter))
         {
             return true;
         }
-        resourceTypePtr = resourceTypePtr->next;
     }
 
     OIC_LOG_V(INFO, TAG, "%s does not contain rt=%s.", resource->uri, resourceTypeFilter);
@@ -622,23 +1554,28 @@ static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter)
         return false;
     }
 
-    // Null or empty is analogous to no filter.
-    if (interfaceFilter == NULL || *interfaceFilter == 0)
+    // Null is analogous to no filter i.e. query is of form /oic/res?rt=core.light or /oic/res,
+    // without if query.
+    if (NULL == interfaceFilter)
     {
         return true;
     }
 
-    OCResourceInterface *interfacePtr = resource->rsrcInterface;
+    // Empty interface filter is analogous to error query
+    // It is an error as query is of form /oic/res?if=
+    if (0 == strlen(interfaceFilter))
+    {
+        return false;
+    }
 
-    while (interfacePtr)
+    for (OCResourceInterface *ifPtr = resource->rsrcInterface; ifPtr; ifPtr = ifPtr->next)
     {
-        if (strcmp (interfacePtr->name, interfaceFilter) == 0 ||
-            strcmp (OC_RSRVD_INTERFACE_LL, interfaceFilter) == 0 ||
-            strcmp (OC_RSRVD_INTERFACE_DEFAULT, interfaceFilter) == 0)
+        if (0 == strcmp(ifPtr->name, interfaceFilter) ||
+            0 == strcmp(OC_RSRVD_INTERFACE_LL, interfaceFilter) ||
+            0 == strcmp(OC_RSRVD_INTERFACE_DEFAULT, interfaceFilter))
         {
             return true;
         }
-        interfacePtr = interfacePtr->next;
     }
 
     OIC_LOG_V(INFO, TAG, "%s does not contain if=%s.", resource->uri, interfaceFilter);
@@ -668,12 +1605,12 @@ static bool includeThisResourceInResponse(OCResource *resource,
          */
         if (!(resourceTypeFilter && *resourceTypeFilter))
         {
-            OIC_LOG_V(INFO, TAG, "%s no query string for EXPLICIT_DISCOVERABLE \
+            OIC_LOG_V(INFO, TAG, "%s no query string for EXPLICIT_DISCOVERABLE\
                 resource", resource->uri);
             return false;
         }
     }
-    else if ( !(resource->resourceProperties & OC_ACTIVE) ||
+    else if (!(resource->resourceProperties & OC_ACTIVE) ||
          !(resource->resourceProperties & OC_DISCOVERABLE))
     {
         OIC_LOG_V(INFO, TAG, "%s not ACTIVE or DISCOVERABLE", resource->uri);
@@ -682,47 +1619,78 @@ static bool includeThisResourceInResponse(OCResource *resource,
 
     return resourceMatchesIFFilter(resource, interfaceFilter) &&
            resourceMatchesRTFilter(resource, resourceTypeFilter);
-
 }
 
 OCStackResult SendNonPersistantDiscoveryResponse(OCServerRequest *request, OCResource *resource,
                                 OCPayload *discoveryPayload, OCEntityHandlerResult ehResult)
 {
-    OCEntityHandlerResponse response = {0};
+    OCEntityHandlerResponse *response = NULL;
+    OCStackResult result = OC_STACK_ERROR;
+
+    response = (OCEntityHandlerResponse *)OICCalloc(1, sizeof(*response));
+    VERIFY_PARAM_NON_NULL(TAG, response, "Failed allocating OCEntityHandlerResponse");
+
+    response->ehResult = ehResult;
+    response->payload = discoveryPayload;
+    response->persistentBufferFlag = 0;
+    response->requestHandle = (OCRequestHandle) request;
+    response->resourceHandle = (OCResourceHandle) resource;
+
+    result = OCDoResponse(response);
 
-    response.ehResult = ehResult;
-    response.payload = discoveryPayload;
-    response.persistentBufferFlag = 0;
-    response.requestHandle = (OCRequestHandle) request;
-    response.resourceHandle = (OCResourceHandle) resource;
+    OICFree(response);
+    return result;
+
+exit:
+    return OC_STACK_NO_MEMORY;
+}
 
-    return OCDoResponse(&response);
+static OCStackResult EHRequest(OCEntityHandlerRequest *ehRequest, OCPayloadType type,
+    OCServerRequest *request, OCResource *resource)
+{
+    return FormOCEntityHandlerRequest(ehRequest,
+                                     (OCRequestHandle)request,
+                                     request->method,
+                                     &request->devAddr,
+                                     (OCResourceHandle)resource,
+                                     request->query,
+                                     type,
+                                     request->payload,
+                                     request->payloadSize,
+                                     request->numRcvdVendorSpecificHeaderOptions,
+                                     request->rcvdVendorSpecificHeaderOptions,
+                                     (OCObserveAction)(request->notificationFlag ? OC_OBSERVE_NO_OPTION :
+                                                       request->observationOption),
+                                     (OCObservationId)0,
+                                     request->coapID);
 }
+
 #ifdef RD_SERVER
 /**
- * Find resource at the resource directory server. This resource is not local resource but a
- * remote resource.
+ * Find resources at the resource directory server. These resources are not local resources but
+ * remote resources.
  *
- * @param resource The resource to check the matching resource URI.
  * @param interfaceQuery The interface query parameter.
  * @param resourceTypeQuery The resourceType query parameter.
  * @param discPayload The payload that will be added with the resource information if found at RD.
  *
- * @return ::OC_STACK_OK if the resource is found else ::OC_STACK_NO_RESOURCE.
- * In case if build is not with flag RD_SERVER, it returns ::OC_STACK_NO_RESOURCE.
+ * @return ::OC_STACK_OK if any resources are found else ::OC_STACK_NO_RESOURCE.
+ * In case if RD server is not started, it returns ::OC_STACK_NO_RESOURCE.
  */
-static OCStackResult findResourceAtRD(const OCResource* resource, const char *interfaceQuery,
-    const char *resourceTypeQuery, OCDiscoveryPayload *discPayload)
+static OCStackResult findResourcesAtRD(const char *interfaceQuery,
+                                       const char *resourceTypeQuery, OCDiscoveryPayload **discPayload)
 {
-    if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0)
+    OCStackResult result = OC_STACK_NO_RESOURCE;
+    if (OCGetResourceHandleAtUri(OC_RSRVD_RD_URI) != NULL)
     {
-        if (OC_STACK_OK == OCRDDatabaseCheckResources(interfaceQuery, resourceTypeQuery, discPayload))
-        {
-            return OC_STACK_OK;
-        }
+        result = OCRDDatabaseDiscoveryPayloadCreate(interfaceQuery, resourceTypeQuery,
+            (*discPayload) ? &(*discPayload)->next : discPayload);
     }
-
-    return OC_STACK_NO_RESOURCE;
+    if ((*discPayload) && (*discPayload)->resources)
+    {
+        result = OC_STACK_OK;
+    }
+    return result;
 }
 #endif
 
@@ -739,7 +1707,7 @@ static OCStackResult discoveryPayloadCreateAndAddDeviceId(OCPayload **payload)
 {
     if (*payload)
     {
-        OIC_LOG_V(DEBUG, TAG, "Payload is already allocated");
+        OIC_LOG(DEBUG, TAG, "Payload is already allocated");
         return OC_STACK_OK;
     }
 
@@ -774,10 +1742,13 @@ exit:
  */
 static OCStackResult addDiscoveryBaselineCommonProperties(OCDiscoveryPayload *discPayload)
 {
-    discPayload->uri = OICStrdup(OC_RSRVD_WELL_KNOWN_URI);
-    VERIFY_PARAM_NON_NULL(TAG, discPayload->uri, "Failed adding href to discovery payload.");
+    if (!discPayload)
+    {
+        OIC_LOG(ERROR, TAG, "Payload is not allocated");
+        return OC_STACK_INVALID_PARAM;
+    }
 
-    OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, "deviceName", (void **)&discPayload->name);
+    OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, (void **)&discPayload->name);
 
     discPayload->type = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
     VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt to discovery payload.");
@@ -794,6 +1765,14 @@ exit:
     return OC_STACK_NO_MEMORY;
 }
 
+static bool isUnicast(OCServerRequest *request)
+{
+    bool isMulticast = request->devAddr.flags & OC_MULTICAST;
+    return (isMulticast == false &&
+           (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
+           (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE));
+}
+
 static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource)
 {
     if (!request || !resource)
@@ -801,6 +1780,23 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
         return OC_STACK_INVALID_PARAM;
     }
 
+    OCPayload* payload = NULL;
+    char *interfaceQuery = NULL;
+    char *resourceTypeQuery = NULL;
+
+    OIC_LOG(INFO, TAG, "Entering HandleVirtualResource");
+
+    OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
+
+#ifdef TCP_ADAPTER
+    if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
+    {
+        // Received request for a keepalive
+        OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
+        return HandleKeepAliveRequest(request, resource);
+    }
+#endif
+
     OCStackResult discoveryResult = OC_STACK_ERROR;
     if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
         request->method == OC_REST_DELETE)
@@ -810,14 +1806,21 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
         return OC_STACK_UNAUTHORIZED_REQ;
     }
 
-    OCPayload* payload = NULL;
-    char *interfaceQuery = NULL;
-    char *resourceTypeQuery = NULL;
-    char *dataModelVersions = NULL;
-
-    OIC_LOG(INFO, TAG, "Entering HandleVirtualResource");
-
-    OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
+    discoveryResult = HandleVirtualObserveRequest(request);
+    if (discoveryResult == OC_STACK_DUPLICATE_REQUEST)
+    {
+        // server requests are usually free'd when the response is sent out
+        // for the request in ocserverrequest.c : HandleSingleResponse()
+        // Since we are making an early return and not responding, the server request
+        // needs to be deleted.
+        FindAndDeleteServerRequest (request);
+        discoveryResult = OC_STACK_OK;
+        goto exit;
+    }
+    else if (discoveryResult != OC_STACK_OK)
+    {
+        goto exit;
+    }
 
     // Step 1: Generate the response to discovery request
     if (virtualUriInRequest == OC_WELL_KNOWN_URI
@@ -826,27 +1829,35 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
 #endif
             )
     {
+        char *interfaceQuery = NULL;
+        char *resourceTypeQuery = NULL;
+
+        CAEndpoint_t *networkInfo = NULL;
+        size_t infoSize = 0;
+
+        CAResult_t caResult = CAGetNetworkInformation(&networkInfo, &infoSize);
+        if (CA_STATUS_FAILED == caResult)
+        {
+            OIC_LOG(ERROR, TAG, "CAGetNetworkInformation has error on parsing network infomation");
+            return OC_STACK_ERROR;
+        }
+
         discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
                 &interfaceQuery, &resourceTypeQuery);
         VERIFY_SUCCESS(discoveryResult);
+
         if (!interfaceQuery && !resourceTypeQuery)
         {
             // If no query is sent, default interface is used i.e. oic.if.ll.
             interfaceQuery = OICStrdup(OC_RSRVD_INTERFACE_LL);
         }
 
-        bool baselineQuery = false;
-        if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT))
-        {
-            baselineQuery = true;
-        }
-
         discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload);
         VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload.");
         VERIFY_SUCCESS(discoveryResult);
 
         OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
-        if (baselineQuery)
+        if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT))
         {
             discoveryResult = addDiscoveryBaselineCommonProperties(discPayload);
             VERIFY_SUCCESS(discoveryResult);
@@ -857,44 +1868,60 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
 #endif
         for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
         {
-            discoveryResult = OC_STACK_NO_RESOURCE;
-#ifdef RD_SERVER
-            discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery,
-                discPayload);
-#endif
-            if (OC_STACK_NO_RESOURCE == discoveryResult)
+            // This case will handle when no resource type and it is oic.if.ll.
+            // Do not assume check if the query is ll
+            if (!resourceTypeQuery &&
+                (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_LL)))
             {
-                // This case will handle when no resource type and it is oic.if.ll.
-                if (!resourceTypeQuery && !baselineQuery && (resource->resourceProperties & prop))
+                // Only include discoverable type
+                if (resource->resourceProperties & prop)
                 {
-                    discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
-                }
-                else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery))
-                {
-                    discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
-                }
-                else
-                {
-                    discoveryResult = OC_STACK_OK;
+                    discoveryResult = BuildVirtualResourceResponse(resource,
+                                                                   discPayload,
+                                                                   &request->devAddr,
+                                                                   networkInfo,
+                                                                   infoSize);
                 }
             }
+            else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery))
+            {
+                discoveryResult = BuildVirtualResourceResponse(resource,
+                                                               discPayload,
+                                                               &request->devAddr,
+                                                               networkInfo,
+                                                               infoSize);
+            }
+            else
+            {
+                discoveryResult = OC_STACK_OK;
+            }
         }
         if (discPayload->resources == NULL)
         {
             discoveryResult = OC_STACK_NO_RESOURCE;
+            OCPayloadDestroy(payload);
+            payload = NULL;
+        }
+
+        if (networkInfo)
+        {
+            OICFree(networkInfo);
         }
+#ifdef RD_SERVER
+        discoveryResult = findResourcesAtRD(interfaceQuery, resourceTypeQuery, (OCDiscoveryPayload **)&payload);
+#endif
     }
     else if (virtualUriInRequest == OC_DEVICE_URI)
     {
         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_DEVICE_URI);
         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Device URI not found.");
-        discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload);
+        discoveryResult = BuildDevicePlatformPayload(resourcePtr, (OCRepPayload **)&payload, true);
     }
     else if (virtualUriInRequest == OC_PLATFORM_URI)
     {
         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Platform URI not found.");
-        discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload);
+        discoveryResult = BuildDevicePlatformPayload(resourcePtr, (OCRepPayload **)&payload, false);
     }
 #ifdef ROUTING_GATEWAY
     else if (OC_GATEWAY_URI == virtualUriInRequest)
@@ -904,14 +1931,22 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
         discoveryResult = RMHandleGatewayRequest(request, resource);
     }
 #endif
-#ifdef TCP_ADAPTER
-    else if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
+    else if (OC_INTROSPECTION_URI == virtualUriInRequest)
     {
-        // Received request for a keepalive
-        OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
-        discoveryResult = HandleKeepAliveRequest(request, resource);
+        // Received request for introspection
+        OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_INTROSPECTION_URI);
+        VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Introspection URI not found.");
+        discoveryResult = BuildIntrospectionResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, &request->devAddr);
+        OIC_LOG(INFO, TAG, "Request is for Introspection");
+    }
+    else if (OC_INTROSPECTION_PAYLOAD_URI == virtualUriInRequest)
+    {
+        // Received request for introspection payload
+        OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_INTROSPECTION_PAYLOAD_URI);
+        VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Introspection Payload URI not found.");
+        discoveryResult = BuildIntrospectionPayloadResponse(resourcePtr, (OCRepPayload **)&payload, &request->devAddr);
+        OIC_LOG(INFO, TAG, "Request is for Introspection Payload");
     }
-#endif
     /**
      * Step 2: Send the discovery response
      *
@@ -950,27 +1985,23 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
     if (OC_GATEWAY_URI != virtualUriInRequest)
 #endif
     {
-#if TCP_ADAPTER
-        // KeepAlive uses the HandleKeepAliveRequest to respond to the request.
-        if (OC_KEEPALIVE_RESOURCE_URI != virtualUriInRequest)
-#endif
+        OIC_LOG_PAYLOAD(DEBUG, payload);
+        if(discoveryResult == OC_STACK_OK)
         {
-            OIC_LOG_PAYLOAD(DEBUG, payload);
-            if(discoveryResult == OC_STACK_OK)
-            {
-                SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
-            }
-            else if(((request->devAddr.flags &  OC_MULTICAST) == false) &&
-                (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
-                (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
+
+            SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
+        }
+        else // Error handling
+        {
+            if (isUnicast(request))
             {
                 OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request",
                     discoveryResult, virtualUriInRequest);
                 SendNonPersistantDiscoveryResponse(request, resource, NULL,
                     (discoveryResult == OC_STACK_NO_RESOURCE) ?
-                            OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
+                        OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
             }
-            else
+            else // Multicast
             {
                 // Ignoring the discovery request as per RFC 7252, Section #8.2
                 OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send.");
@@ -978,6 +2009,7 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
                 // since it never remove and causes a big memory waste.
                 FindAndDeleteServerRequest(request);
             }
+            discoveryResult = OC_STACK_CONTINUE;
         }
     }
 
@@ -992,39 +2024,23 @@ exit:
         OICFree(resourceTypeQuery);
     }
     OCPayloadDestroy(payload);
-    if (dataModelVersions)
-    {
-        OICFree(dataModelVersions);
-    }
+
+    // To ignore the message, OC_STACK_CONTINUE is sent
     return discoveryResult;
 }
 
 static OCStackResult
-HandleDefaultDeviceEntityHandler (OCServerRequest *request)
+HandleDefaultDeviceEntityHandler(OCServerRequest *request)
 {
-    if(!request)
+    if (!request)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
-    OCStackResult result = OC_STACK_OK;
     OCEntityHandlerResult ehResult = OC_EH_ERROR;
     OCEntityHandlerRequest ehRequest = {0};
-
     OIC_LOG(INFO, TAG, "Entering HandleResourceWithDefaultDeviceEntityHandler");
-    result = FormOCEntityHandlerRequest(&ehRequest,
-                                        (OCRequestHandle) request,
-                                        request->method,
-                                        &request->devAddr,
-                                        (OCResourceHandle) NULL, request->query,
-                                        PAYLOAD_TYPE_REPRESENTATION,
-                                        request->payload,
-                                        request->payloadSize,
-                                        request->numRcvdVendorSpecificHeaderOptions,
-                                        request->rcvdVendorSpecificHeaderOptions,
-                                        (OCObserveAction)request->observationOption,
-                                        (OCObservationId)0,
-                                        request->coapID);
+    OCStackResult result = EHRequest(&ehRequest, PAYLOAD_TYPE_REPRESENTATION, request, NULL);
     VERIFY_SUCCESS(result);
 
     // At this point we know for sure that defaultDeviceHandler exists
@@ -1046,12 +2062,9 @@ exit:
 }
 
 static OCStackResult
-HandleResourceWithEntityHandler (OCServerRequest *request,
-                                 OCResource *resource,
-                                 uint8_t collectionResource)
+HandleResourceWithEntityHandler(OCServerRequest *request,
+                                OCResource *resource)
 {
-    OC_UNUSED(collectionResource);
-
     if(!request || ! resource)
     {
         return OC_STACK_INVALID_PARAM;
@@ -1073,20 +2086,7 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
 
     }
 
-    result = FormOCEntityHandlerRequest(&ehRequest,
-                                        (OCRequestHandle)request,
-                                        request->method,
-                                        &request->devAddr,
-                                        (OCResourceHandle)resource,
-                                        request->query,
-                                        type,
-                                        request->payload,
-                                        request->payloadSize,
-                                        request->numRcvdVendorSpecificHeaderOptions,
-                                        request->rcvdVendorSpecificHeaderOptions,
-                                        (OCObserveAction)request->observationOption,
-                                        0,
-                                        request->coapID);
+    result = EHRequest(&ehRequest, type, request, resource);
     VERIFY_SUCCESS(result);
 
     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
@@ -1123,7 +2123,7 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
                 (const char *)(request->query),
                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
                 resource, request->qos, request->acceptFormat,
-                &request->devAddr);
+                request->acceptVersion, &request->devAddr);
 
         if(result == OC_STACK_OK)
         {
@@ -1205,32 +2205,16 @@ exit:
     return result;
 }
 
-static OCStackResult
-HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
-                                              OCResource *resource)
+static OCStackResult HandleCollectionResourceDefaultEntityHandler(OCServerRequest *request,
+                                                                  OCResource *resource)
 {
-    if(!request || !resource)
+    if (!request || !resource)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
-    OCStackResult result = OC_STACK_ERROR;
     OCEntityHandlerRequest ehRequest = {0};
-
-    result = FormOCEntityHandlerRequest(&ehRequest,
-                                        (OCRequestHandle)request,
-                                        request->method,
-                                        &request->devAddr,
-                                        (OCResourceHandle)resource,
-                                        request->query,
-                                        PAYLOAD_TYPE_REPRESENTATION,
-                                        request->payload,
-                                        request->payloadSize,
-                                        request->numRcvdVendorSpecificHeaderOptions,
-                                        request->rcvdVendorSpecificHeaderOptions,
-                                        (OCObserveAction)request->observationOption,
-                                        (OCObservationId)0,
-                                        request->coapID);
+    OCStackResult result = EHRequest(&ehRequest, PAYLOAD_TYPE_REPRESENTATION, request, resource);
     if(result == OC_STACK_OK)
     {
         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
@@ -1264,12 +2248,12 @@ ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerReque
         }
         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
         {
-            ret = HandleResourceWithEntityHandler (request, resource, 0);
+            ret = HandleResourceWithEntityHandler (request, resource);
             break;
         }
         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
         {
-            ret = HandleResourceWithEntityHandler (request, resource, 1);
+            ret = HandleResourceWithEntityHandler (request, resource);
             break;
         }
         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
@@ -1317,6 +2301,18 @@ OCStackResult OCSetPlatformInfo(OCPlatformInfo info)
         goto exit;
     }
 
+    /*
+     * @todo (IOT-1541) There are several versions of a UUID structure and conversion
+     * methods scattered around the IoTivity code base.  They need to be combined
+     * into one PAL API.
+     */
+    uint8_t uuid[UUID_SIZE];
+    if (!OCConvertStringToUuid(info.platformID, uuid))
+    {
+        OIC_LOG(ERROR, TAG, "Platform ID is not a UUID.");
+        goto exit;
+    }
+
     resource = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
     if (!resource)
     {
@@ -1344,7 +2340,6 @@ exit:
 
 OCStackResult OCSetDeviceInfo(OCDeviceInfo info)
 {
-    OCStringLL *dataModelVersion = NULL;
     OCResource *resource = FindResourceByUri(OC_RSRVD_DEVICE_URI);
     if (!resource)
     {
@@ -1373,23 +2368,24 @@ OCStackResult OCSetDeviceInfo(OCDeviceInfo info)
     }
     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, info.specVersion ?
         info.specVersion: OC_SPEC_VERSION));
+
     if (info.dataModelVersions)
     {
-        VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, info.dataModelVersions));
+        char *dmv = OCCreateString(info.dataModelVersions);
+        VERIFY_PARAM_NON_NULL(TAG, dmv, "Failed allocating dataModelVersions");
+        OCStackResult r = OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, dmv);
+        OICFree(dmv);
+        VERIFY_SUCCESS(r);
     }
     else
     {
-        dataModelVersion = OCCreateOCStringLL(OC_DATA_MODEL_VERSION);
-        VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, dataModelVersion));
+        VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION,
+            OC_DATA_MODEL_VERSION));
     }
     OIC_LOG(INFO, TAG, "Device parameter initialized successfully.");
     return OC_STACK_OK;
 
 exit:
-    if (dataModelVersion)
-    {
-        OCFreeOCStringLL(dataModelVersion);
-    }
     return OC_STACK_ERROR;
 }
 
@@ -1425,7 +2421,7 @@ OCStackResult OCGetAttribute(const OCResource *resource, const char *attribute,
 
 OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **value)
 {
-    if (!prop || *value)
+    if (!prop)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -1433,6 +2429,10 @@ OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **va
     {
         return OC_STACK_INVALID_PARAM;
     }
+    if (*value)
+    {
+        *value = NULL;
+    }
     OCStackResult res =  OC_STACK_NO_RESOURCE;
     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
     {
@@ -1448,58 +2448,148 @@ OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **va
     return res;
 }
 
-OCStackResult OCSetAttribute(OCResource* resource, const char* attribute, const void* value)
+static OCStackResult SetAttributeInternal(OCResource *resource,
+                                          const char *attribute,
+                                          const void *value,
+                                          bool updateDatabase)
 {
-    OCAttribute *resAttrib = (OCAttribute *)OICCalloc(1, sizeof(OCAttribute));
-    VERIFY_PARAM_NON_NULL(TAG, resAttrib, "Failed allocation OCAttribute");
-    resAttrib->attrName = OICStrdup(attribute);
-    VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrName, "Failed allocating attribute name");
-    // A special case when value is of type OCStringLL
+    OCAttribute *resAttrib = NULL;
+
+    // See if the attribute already exists in the list.
+    for (resAttrib = resource->rsrcAttributes; resAttrib; resAttrib = resAttrib->next)
+    {
+        if (0 == strcmp(attribute, resAttrib->attrName))
+        {
+            // Found, free the old value.
+            if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, resAttrib->attrName))
+            {
+                OCFreeOCStringLL((OCStringLL *)resAttrib->attrValue);
+            }
+            else
+            {
+                OICFree((char *)resAttrib->attrValue);
+            }
+            break;
+        }
+    }
+
+    // If not already in the list, add it.
+    if (NULL == resAttrib)
+    {
+        resAttrib = (OCAttribute *)OICCalloc(1, sizeof(OCAttribute));
+        VERIFY_PARAM_NON_NULL(TAG, resAttrib, "Failed allocating OCAttribute");
+        resAttrib->attrName = OICStrdup(attribute);
+        VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrName, "Failed allocating attribute name");
+        resAttrib->next = resource->rsrcAttributes;
+        resource->rsrcAttributes = resAttrib;
+    }
+
+    // Fill in the new value.
     if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
     {
-        resAttrib->attrValue = CloneOCStringLL((OCStringLL *)value);
+        resAttrib->attrValue = OCCreateOCStringLL((char *)value);
     }
     else
     {
         resAttrib->attrValue = OICStrdup((char *)value);
     }
     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrValue, "Failed allocating attribute value");
-    resAttrib->next = NULL;
 
-    if (!resource->rsrcAttributes)
-    {
-        resource->rsrcAttributes = resAttrib;
-    }
-    else
+    // The resource has changed from what is stored in the database. Update the database to
+    // reflect the new value.
+    if (updateDatabase)
     {
-        OCAttribute *temp = resource->rsrcAttributes;
-        for (; temp->next; temp = temp->next)
+        OCDeviceProperties *deviceProperties = NULL;
+
+        OCStackResult result = CreateDeviceProperties((const char*)value, &deviceProperties);
+        if (OC_STACK_OK == result)
         {
-            if (0 == strcmp(attribute, temp->attrName))
+            result = UpdateDevicePropertiesDatabase(deviceProperties);
+            if (OC_STACK_OK != result)
             {
-                if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, temp->attrName))
-                {
-                    OCFreeOCStringLL((OCStringLL *)temp->attrValue);
-                }
-                 {
-                    OICFree((char *)temp->attrValue);
-                }
-                break;
+                OIC_LOG(ERROR, TAG, "UpdateDevicePropertiesDatabase failed!");
             }
+
+            CleanUpDeviceProperties(&deviceProperties);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "CreateDeviceProperties failed!");
         }
-        temp->next = resAttrib;
     }
+
     return OC_STACK_OK;
 
 exit:
     OCDeleteResourceAttributes(resAttrib);
     return OC_STACK_NO_MEMORY;
+}
 
+static OCStackResult IsDatabaseUpdateNeeded(const char *attribute, const void *value, bool *update)
+{
+    OCStackResult result = OC_STACK_OK;
+    void *currentPIID = NULL;
+
+    if (!attribute || !value || !update)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    *update = false;
+
+    // Protocol Independent ID
+    if (0 == strcmp(OC_RSRVD_PROTOCOL_INDEPENDENT_ID, attribute))
+    {
+        result = OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_PROTOCOL_INDEPENDENT_ID, &currentPIID);
+        if (OC_STACK_OK == result)
+        {
+            // PIID has already been set on the resource and stored in the database. Check to see
+            // if the value is changing so the database can be updated accordingly.
+            if (0 != strcmp((char *)currentPIID, (char*)value))
+            {
+                *update = true;
+            }
+        }
+        else if (OC_STACK_NO_RESOURCE == result)
+        {
+            // PIID has not been set yet so we should always update the database.
+            *update = true;
+            result = OC_STACK_OK;
+        }
+        else
+        {
+            OIC_LOG_V(ERROR, TAG, 
+                "Call to OCGetPropertyValue for the current PIID failed with error: %d", result);
+        }
+    }
+
+    // Clean Up
+    OICFreeAndSetToNull(&currentPIID);
+
+    return result;
+}
+
+OCStackResult OCSetAttribute(OCResource *resource, const char *attribute, const void *value)
+{
+    bool updateDatabase = false;
+
+    // Check to see if we also need to update the database for this attribute. If the current
+    // value matches what is stored in the database we can skip the update and an unnecessary
+    // write.
+    if (OC_STACK_OK != IsDatabaseUpdateNeeded(attribute, value, &updateDatabase))
+    {
+        OIC_LOG_V(WARNING, TAG, 
+            "Could not determine if a database update was needed for %s. Proceeding without updating the database.",
+            attribute);
+        updateDatabase = false;
+    }
+
+    return SetAttributeInternal(resource, attribute, value, updateDatabase);
 }
 
 OCStackResult OCSetPropertyValue(OCPayloadType type, const char *prop, const void *value)
 {
-    if (!prop)
+    if (!prop || !value)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -1517,7 +2607,7 @@ OCStackResult OCSetPropertyValue(OCPayloadType type, const char *prop, const voi
         {
             OIC_LOG(ERROR, TAG, "Resource does not exist.");
         }
-        if (value)
+        else
         {
             res = OCSetAttribute(resource, prop, value);
         }