Add gPstat null check
[platform/upstream/iotivity.git] / resource / csdk / security / src / pstatresource.c
index b3e63ac..f9834d1 100644 (file)
@@ -24,6 +24,7 @@
 #include "ocstack.h"
 #include "oic_malloc.h"
 #include "ocpayload.h"
+#include "ocpayloadcbor.h"
 #include "payload_logging.h"
 #include "resourcemanager.h"
 #include "pstatresource.h"
 #include "psinterface.h"
 #include "srmresourcestrings.h"
 #include "srmutility.h"
+#include "aclresource.h"
+#include "credresource.h"
+#include "ocprovisioningmanager.h"
 
-#define TAG  "SRM-PSTAT"
+#define TAG  "OIC_SRM_PSTAT"
 
 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
  * The value of payload size is increased until reaching below max cbor size. */
@@ -42,7 +46,10 @@ static const uint16_t CBOR_SIZE = 512;
 static const uint16_t CBOR_MAX_SIZE = 4400;
 
 // PSTAT Map size - Number of mandatory items
-static const uint8_t PSTAT_MAP_SIZE = 7;
+static const uint8_t PSTAT_MAP_SIZE = 6;
+
+// Number of writeable property
+static const uint8_t WRITEABLE_PROPERTY_SIZE = 3;
 
 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
 static OicSecPstat_t gDefaultPstat =
@@ -64,6 +71,14 @@ static OicSecPstat_t    *gPstat = NULL;
 
 static OCResourceHandle gPstatHandle = NULL;
 
+/**
+ * This method is internal method.
+ * the param roParsed is optionally used to know whether cborPayload has
+ * at least read only property value or not.
+ */
+static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
+                                 OicSecPstat_t **secPstat, bool *roParsed);
+
 void DeletePstatBinData(OicSecPstat_t* pstat)
 {
     if (pstat)
@@ -76,7 +91,8 @@ void DeletePstatBinData(OicSecPstat_t* pstat)
     }
 }
 
-OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size)
+OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size,
+                                 bool writableOnly)
 {
     if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
     {
@@ -93,7 +109,7 @@ OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload,
     *size = 0;
 
     OCStackResult ret = OC_STACK_ERROR;
-
+    size_t pstatMapSize = PSTAT_MAP_SIZE;
     CborEncoder encoder;
     CborEncoder pstatMap;
     char* strUuid = NULL;
@@ -104,7 +120,12 @@ OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload,
     VERIFY_NON_NULL(TAG, outPayload, ERROR);
     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
 
-    cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, PSTAT_MAP_SIZE);
+    if (false == writableOnly)
+    {
+        pstatMapSize += WRITEABLE_PROPERTY_SIZE;
+    }
+
+    cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, pstatMapSize);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
 
     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
@@ -113,16 +134,6 @@ OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload,
     cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
 
-    cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
-        strlen(OIC_JSON_DEVICE_ID_NAME));
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
-    ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
-    VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
-    cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
-    OICFree(strUuid);
-    strUuid = NULL;
-
     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
         strlen(OIC_JSON_CM_NAME));
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
@@ -141,28 +152,73 @@ OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload,
     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
 
-    cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
-        strlen(OIC_JSON_SM_NAME));
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
-    cborEncoderResult = cbor_encode_int(&pstatMap, pstat->sm[0]);
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Value.");
-
-    cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
-        strlen(OIC_JSON_ROWNERID_NAME));
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
-    ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
-    VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
-    cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
-    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
-    OICFree(strUuid);
-    strUuid = NULL;
+    if (false == writableOnly)
+    {
+        cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
+            strlen(OIC_JSON_SM_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
+        cborEncoderResult = cbor_encode_int(&pstatMap, pstat->sm[0]);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Value.");
+
+        cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
+            strlen(OIC_JSON_DEVICE_ID_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
+        ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+        cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
+        OICFree(strUuid);
+        strUuid = NULL;
+
+        cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
+            strlen(OIC_JSON_ROWNERID_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
+        ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+        cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
+        OICFree(strUuid);
+        strUuid = NULL;
+    }
+
+    //RT -- Mandatory
+    CborEncoder rtArray;
+    cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_RT_NAME,
+            strlen(OIC_JSON_RT_NAME));
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
+    cborEncoderResult = cbor_encoder_create_array(&pstatMap, &rtArray, 1);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_PSTAT,
+                strlen(OIC_RSRC_TYPE_SEC_PSTAT));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&pstatMap, &rtArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
+
+    //IF-- Mandatory
+     CborEncoder ifArray;
+     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_IF_NAME,
+             strlen(OIC_JSON_IF_NAME));
+     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
+     cborEncoderResult = cbor_encoder_create_array(&pstatMap, &ifArray, 1);
+     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
+    for (size_t i = 0; i < 1; i++)
+    {
+        cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
+                strlen(OC_RSRVD_INTERFACE_DEFAULT));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
+    }
+    cborEncoderResult = cbor_encoder_close_container(&pstatMap, &ifArray);
+    VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
 
     cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
 
     if (CborNoError == cborEncoderResult)
     {
-        *size = encoder.ptr - outPayload;
+        *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
         *payload = outPayload;
         ret = OC_STACK_OK;
     }
@@ -171,10 +227,11 @@ exit:
     {
         // reallocate and try again!
         OICFree(outPayload);
+        outPayload = NULL;
         // Since the allocated initial memory failed, double the memory.
-        cborLen += encoder.ptr - encoder.end;
+        cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
         cborEncoderResult = CborNoError;
-        ret = PstatToCBORPayload(pstat, payload, &cborLen);
+        ret = PstatToCBORPayload(pstat, payload, &cborLen, writableOnly);
         if (OC_STACK_OK == ret)
         {
             *size = cborLen;
@@ -196,6 +253,12 @@ exit:
 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
                                  OicSecPstat_t **secPstat)
 {
+    return CBORPayloadToPstatBin(cborPayload, size, secPstat, NULL);
+}
+
+static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
+                                 OicSecPstat_t **secPstat, bool *roParsed)
+{
     if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat || 0 == size)
     {
         return OC_STACK_INVALID_PARAM;
@@ -226,6 +289,12 @@ OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
         cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
     }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        pstat->isOp = gPstat->isOp;
+        cborFindResult = CborNoError;
+    }
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
@@ -236,37 +305,88 @@ OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
         OICFree(strUuid );
         strUuid  = NULL;
+
+    }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
+        cborFindResult = CborNoError;
     }
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->cm);
+        int cm;
+
+        cborFindResult = cbor_value_get_int(&pstatMap, &cm);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
+        pstat->cm = (OicSecDpm_t)cm;
+    }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        pstat->cm = gPstat->cm;
+        cborFindResult = CborNoError;
     }
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->tm);
+        int tm;
+
+        cborFindResult = cbor_value_get_int(&pstatMap, &tm);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
+        pstat->tm = (OicSecDpm_t)tm;
+    }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        pstat->tm = gPstat->tm;
+        cborFindResult = CborNoError;
     }
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->om);
+        int om;
+
+        cborFindResult = cbor_value_get_int(&pstatMap, &om);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
+        pstat->om = (OicSecDpom_t)om;
+    }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        pstat->om = gPstat->om;
+        cborFindResult = CborNoError;
     }
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
     {
+        int sm;
+
         pstat->smLen = 1;
         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
-        cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->sm[0]);
+        VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
+        cborFindResult = cbor_value_get_int(&pstatMap, &sm);
         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
+        pstat->sm[0] = (OicSecDpom_t)sm;
 
+        if (roParsed)
+        {
+            *roParsed = true;
+        }
+    }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        pstat->smLen = gPstat->smLen;
+        pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
+        VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
+        *pstat->sm = *gPstat->sm;
+        cborFindResult = CborNoError;
     }
 
     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
@@ -279,6 +399,12 @@ OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
         OICFree(strUuid );
         strUuid  = NULL;
     }
+    else
+    {
+        VERIFY_NON_NULL(TAG, gPstat, ERROR);
+        memcpy(pstat->rownerID.id, gPstat->rownerID.id, sizeof(gPstat->rownerID.id));
+        cborFindResult = CborNoError;
+    }
 
     *secPstat = pstat;
     ret = OC_STACK_OK;
@@ -305,7 +431,7 @@ static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
 
     size_t size = 0;
     uint8_t *cborPayload = NULL;
-    OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size);
+    OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size, false);
     if (OC_STACK_OK == ret)
     {
         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
@@ -318,107 +444,361 @@ static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
     return bRet;
 }
 
+static bool ValidateQuery(const char * query)
+{
+    OIC_LOG (DEBUG, TAG, "In ValidateQuery");
+    if(NULL == gPstat)
+    {
+        return false;
+    }
+
+    bool bInterfaceQry = false;      // does querystring contains 'if' query ?
+    bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
+
+    OicParseQueryIter_t parseIter = {.attrPos = NULL};
+
+    ParseQueryIterInit((unsigned char*)query, &parseIter);
+
+    while (GetNextQuery(&parseIter))
+    {
+        if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
+        {
+            bInterfaceQry = true;
+            if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
+            {
+                bInterfaceMatch = true;
+            }
+        }
+    }
+    return (bInterfaceQry ? bInterfaceMatch: true);
+}
+
+#ifdef MULTIPLE_OWNER
+bool IsValidPstatAccessForSubOwner(const uint8_t *cborPayload, size_t size)
+{
+    OicSecPstat_t* pstat = NULL;
+    bool isValidPstat = true;
+
+    OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
+    VERIFY_NON_NULL(TAG, cborPayload, ERROR);
+    VERIFY_SUCCESS(TAG, 0 != size, ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToPstat(cborPayload, size, &pstat), ERROR);
+    VERIFY_NON_NULL(TAG, pstat, ERROR);
+
+    if (RESET & pstat->cm)
+    {
+        OIC_LOG(ERROR, TAG, "SubOwner can't reset the server.");
+        isValidPstat = false;
+    }
+
+exit:
+    DeletePstatBinData(pstat);
+    return isValidPstat;
+}
+#endif //MULTIPLE_OWNER
 
 /**
  * The entity handler determines how to process a GET request.
  */
 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
 {
+    OCEntityHandlerResult ehRet = OC_EH_OK;
+
     OIC_LOG(INFO, TAG, "HandlePstatGetRequest  processing GET request");
 
-    // Convert ACL data into CBOR for transmission
+    //Checking if Get request is a query.
+    if (ehRequest->query)
+    {
+        OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
+        OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
+        if (!ValidateQuery(ehRequest->query))
+        {
+            ehRet = OC_EH_ERROR;
+        }
+    }
+
+    /*
+     * For GET or Valid Query request return doxm resource CBOR payload.
+     * For non-valid query return NULL json payload.
+     * A device will 'always' have a default Pstat, so PstatToCBORPayload will
+     * return valid pstat resource json.
+     */
     size_t size = 0;
     uint8_t *payload = NULL;
-    OCStackResult res = PstatToCBORPayload(gPstat, &payload, &size);
-
-    // A device should always have a default pstat. Therefore, payload should never be NULL.
-    OCEntityHandlerResult ehRet = (res == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
-
-    // Send response payload to request originator
-    if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, payload, size))
+    if (ehRet == OC_EH_OK)
     {
-        ehRet = OC_EH_ERROR;
-        OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatGetRequest");
+        if(OC_STACK_OK != PstatToCBORPayload(gPstat, &payload, &size, false))
+        {
+            OIC_LOG(WARNING, TAG, "PstatToCBORPayload failed in HandlePstatGetRequest");
+        }
     }
+
+    // Send response payload to request originator
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
+                   OC_EH_OK : OC_EH_ERROR;
     OICFree(payload);
     return ehRet;
 }
 
 /**
+ * Checks if device can change state to Ready for Normal Operation.
+ */
+static OCEntityHandlerResult ValidateReadyForNOP(const OicSecPstat_t *pstat)
+{
+    OIC_LOG_V(DEBUG, TAG, "%s: IN", __func__);
+
+    const OicSecDoxm_t *doxm = GetDoxmResourceData();
+    OicUuid_t rowneruuid;
+
+    if (!doxm)
+    {
+        OIC_LOG(WARNING, TAG, "DOXM is NULL");
+        return OC_EH_NOT_ACCEPTABLE;
+    }
+
+    if (!doxm->owned)
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device is unowned");
+        return OC_EH_NOT_ACCEPTABLE;
+    }
+
+    if (IsNilUuid(&doxm->owner))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device owner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&doxm->deviceID))
+    {
+        OIC_LOG(WARNING, TAG,
+                "Can't change state to Ready for Normal Operation: the device owner ID is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&doxm->rownerID))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the doxm rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+
+    if (IsNilUuid(&pstat->rownerID))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the pstat rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    memset(&rowneruuid, 0, sizeof(OicUuid_t));
+    if (OC_STACK_OK != GetAclRownerId(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get acl");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the acl rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    memset(&rowneruuid, 0, sizeof(OicUuid_t));
+    if (OC_STACK_OK != GetCredRownerId(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get cred");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    if (IsNilUuid(&rowneruuid))
+    {
+        OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the cred rowner is NIL");
+        return OC_EH_INTERNAL_SERVER_ERROR;
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "%s: OUT", __func__);
+
+    return OC_EH_OK;
+
+}
+
+/**
  * The entity handler determines how to process a POST request.
  * Per the REST paradigm, POST can also be used to update representation of existing
  * resource or create a new resource.
  * For pstat, it updates only tm and om.
  */
-static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest *ehRequest)
+static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRequest)
 {
     OCEntityHandlerResult ehRet = OC_EH_ERROR;
-    OIC_LOG(INFO, TAG, "HandlePstatPutRequest  processing PUT request");
+    OIC_LOG(INFO, TAG, "HandlePstatPostRequest  processing POST request");
     OicSecPstat_t *pstat = NULL;
+    static uint16_t previousMsgId = 0;
+    bool isDuplicatedMsg = false;
 
-    if (ehRequest->payload)
+    if (ehRequest->payload && NULL != gPstat)
     {
         uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
         size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
         VERIFY_NON_NULL(TAG, payload, ERROR);
 
-        OCStackResult ret = CBORPayloadToPstat(payload, size, &pstat);
+        bool roParsed = false;
+        OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
         VERIFY_NON_NULL(TAG, pstat, ERROR);
         if (OC_STACK_OK == ret)
         {
-            if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
+            bool validReq = false;
+
+            /*
+             * message ID is supported for CoAP over UDP only according to RFC 7252
+             * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
+             * In case of other transport adapter, duplicate message check is not required.
+             */
+            if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
+                 previousMsgId == ehRequest->messageID)
             {
-                gPstat->cm = pstat->cm;
-                OIC_LOG (INFO, TAG, "State changed to Ready for Provisioning");
+                isDuplicatedMsg = true;
             }
-            else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
+
+            if (true == roParsed)
             {
-                gPstat->isOp =pstat->isOp;
-                OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
+                    OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
+                    ehRet = OC_EH_NOT_ACCEPTABLE;
+                    goto exit;
             }
-            else
+
+            //operation mode(om) should be one of supported modes(sm)
+            for(size_t i = 0; i < gPstat->smLen; i++)
+            {
+                if(gPstat->sm[i] == pstat->om)
+                {
+                    validReq = true;
+                    break;
+                }
+            }
+
+            if(!validReq)
             {
-                OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
+                OIC_LOG_V(ERROR, TAG, "%d is unsupported Operation Mode", (int) pstat->om);
+                ehRet = OC_EH_BAD_REQ;
+                goto exit;
             }
-            if (pstat->om != MULTIPLE_SERVICE_SERVER_DRIVEN && gPstat)
+            validReq = false;
+
+            //Currently, IoTivity only supports Single Service Client Directed provisioning
+            if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
             {
-                /*
-                 * Check if the operation mode is in the supported provisioning services
-                 * operation mode list.
-                 */
-                for (size_t i=0; i< gPstat->smLen; i++)
+                if ((pstat->cm & RESET) && false == pstat->isOp)
+                {
+                    validReq = true;
+                    OIC_LOG(INFO, TAG, "State changed to Ready for Reset");
+                }
+                else if ((pstat->cm & TAKE_OWNER) && false == pstat->isOp)
+                {
+                    validReq = true;
+                    OIC_LOG (INFO, TAG, "State changed to Ready for Ownership transfer");
+                }
+                else if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
+                {
+                    validReq = true;
+                    OIC_LOG(INFO, TAG, "State changed to Ready for Provisioning");
+                }
+                else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
                 {
-                    if(gPstat->sm[i] == pstat->om)
+                    ehRet = ValidateReadyForNOP(pstat);
+                    if(OC_EH_OK != ehRet)
                     {
-                        gPstat->om = pstat->om;
-                        break;
+                        goto exit;
                     }
+                    validReq = true;
+                    OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
+                }
+                else
+                {
+                    OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
+                    OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
+                    ehRet = OC_EH_BAD_REQ;
+                    goto exit;
                 }
             }
+
+            if (!validReq)
+            {
+                OIC_LOG(DEBUG, TAG, "Bad request for PSTAT");
+                ehRet = OC_EH_BAD_REQ;
+                goto exit;
+            }
+
+            gPstat->isOp = pstat->isOp;
+            gPstat->om = pstat->om;
+            gPstat->tm = pstat->tm;
+            gPstat->cm = pstat->cm;
+            memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
+            memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
+
             // Convert pstat data into CBOR for update to persistent storage
             if (UpdatePersistentStorage(gPstat))
             {
                 ehRet = OC_EH_OK;
             }
+            if (true == (pstat->cm & RESET))
+            {
+                if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
+                {
+                    ehRet = OC_EH_ERROR;
+                    OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
+                    DeletePstatBinData(pstat);
+                    return ehRet;
+                }
+                ret = ResetSecureResourceInPS();
+                if (OC_STACK_OK == ret)
+                {
+                    ehRet = OC_EH_OK;
+                }
+                DeletePstatBinData(pstat);
+                return ehRet;
+            }
         }
     }
  exit:
-    if(OC_EH_OK != ehRet)
-    {
-        /*
-          * If some error is occured while ownership transfer,
-          * ownership transfer related resource should be revert back to initial status.
-          */
-        RestoreDoxmToInitState();
-        RestorePstatToInitState();
-    }
 
-    //Send payload to request originator
-    if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
-    {
-        ehRet = OC_EH_ERROR;
-        OIC_LOG (ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
-    }
+     if(OC_EH_OK != ehRet)
+     {
+         /*
+           * If some error is occured while ownership transfer,
+           * ownership transfer related resource should be revert back to initial status.
+           */
+         const OicSecDoxm_t* doxm = GetDoxmResourceData();
+         if(doxm && !doxm->owned)
+         {
+            OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
+
+            if (!isDuplicatedMsg)
+            {
+#if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
+                InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
+                                          NULL, OIC_OTM_ERROR);
+#endif
+                ResetSecureResourceInPS();
+                OIC_LOG(INFO, TAG, "DOXM will be reverted.");
+            }
+         }
+         else
+         {
+             OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
+             ResetSecureResourceInPS();
+         }
+     }
+     else
+     {
+        if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
+        {
+            previousMsgId = ehRequest->messageID;
+        }
+     }
+
+    // Send response payload to request originator
+    ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+                   OC_EH_OK : OC_EH_ERROR;
+
     DeletePstatBinData(pstat);
     return ehRet;
 }
@@ -441,12 +821,12 @@ static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest
             case OC_REST_GET:
                 ehRet = HandlePstatGetRequest(ehRequest);
                 break;
-            case OC_REST_PUT:
-                ehRet = HandlePstatPutRequest(ehRequest);
+            case OC_REST_POST:
+                ehRet = HandlePstatPostRequest(ehRequest);
                 break;
             default:
-                ehRet = OC_EH_ERROR;
-                SendSRMResponse(ehRequest, ehRet, NULL, 0);
+                ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
+                               OC_EH_OK : OC_EH_ERROR;
                 break;
         }
     }
@@ -460,11 +840,12 @@ static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest
 {
     OCStackResult ret = OCCreateResource(&gPstatHandle,
                                          OIC_RSRC_TYPE_SEC_PSTAT,
-                                         OIC_MI_DEF,
+                                         OC_RSRVD_INTERFACE_DEFAULT,
                                          OIC_RSRC_PSTAT_URI,
                                          PstatEntityHandler,
                                          NULL,
-                                         OC_RES_PROP_NONE);
+                                         OC_SECURE |
+                                         OC_DISCOVERABLE);
 
     if (OC_STACK_OK != ret)
     {
@@ -592,7 +973,7 @@ OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
 
-        ret = PstatToCBORPayload(gPstat, &cborPayload, &size);
+        ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
 
         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
@@ -616,7 +997,15 @@ exit:
  */
 bool GetPstatIsop()
 {
-    return gPstat->isOp;
+    if(NULL != gPstat)
+    {
+        return gPstat->isOp;
+    }
+    else
+    {
+        //In case of gPstat is NULL
+        return false;
+    }
 }
 
 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
@@ -629,3 +1018,44 @@ OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
     }
     return retVal;
 }
+
+OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    uint8_t *cborPayload = NULL;
+    size_t size = 0;
+
+    if(NULL == gPstat)
+    {
+        ret = OC_STACK_NO_RESOURCE;
+        return ret;
+    }
+
+    if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
+    {
+        gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
+        gPstat->isOp = true;
+
+        memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
+        memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
+
+        ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
+
+        OICFree(cborPayload);
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
+    }
+
+    return ret;
+
+exit:
+    OICFree(cborPayload);
+    return ret;
+}
+