Change pstat.deviceuuid from R-only to RW
[platform/upstream/iotivity.git] / resource / csdk / security / src / pstatresource.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "ocstack.h"
25 #include "oic_malloc.h"
26 #include "ocpayload.h"
27 #include "ocpayloadcbor.h"
28 #include "payload_logging.h"
29 #include "resourcemanager.h"
30 #include "pstatresource.h"
31 #include "doxmresource.h"
32 #include "psinterface.h"
33 #include "srmresourcestrings.h"
34 #include "srmutility.h"
35
36 #define TAG  "OIC_SRM_PSTAT"
37
38 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
39  * The value of payload size is increased until reaching below max cbor size. */
40 static const uint16_t CBOR_SIZE = 512;
41
42 // Max cbor size payload.
43 static const uint16_t CBOR_MAX_SIZE = 4400;
44
45 // PSTAT Map size - Number of mandatory items
46 static const uint8_t PSTAT_MAP_SIZE = 6;
47
48 // Number of writeable property
49 static const uint8_t WRITEABLE_PROPERTY_SIZE = 3;
50
51 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
52 static OicSecPstat_t gDefaultPstat =
53 {
54     false,                                    // bool isop
55     (OicSecDpm_t)(BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
56     PROVISION_CREDENTIALS | PROVISION_ACLS),   // OicSecDpm_t cm
57     (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
58     PROVISION_CREDENTIALS | PROVISION_ACLS),   // OicSecDpm_t tm
59     {.id = {0}},                              // OicUuid_t deviceID
60     SINGLE_SERVICE_CLIENT_DRIVEN,             // OicSecDpom_t om */
61     1,                                        // the number of elts in Sms
62     &gSm,                                     // OicSecDpom_t *sm
63     0,                                        // uint16_t commitHash
64     {.id = {0}},                              // OicUuid_t rownerID
65 };
66
67 static OicSecPstat_t    *gPstat = NULL;
68
69 static OCResourceHandle gPstatHandle = NULL;
70
71 /**
72  * This method is internal method.
73  * the param roParsed is optionally used to know whether cborPayload has
74  * at least read only property value or not.
75  */
76 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
77                                  OicSecPstat_t **secPstat, bool *roParsed);
78
79 void DeletePstatBinData(OicSecPstat_t* pstat)
80 {
81     if (pstat)
82     {
83         //Clean 'supported modes' field
84         OICFree(pstat->sm);
85
86         //Clean pstat itself
87         OICFree(pstat);
88     }
89 }
90
91 OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size,
92                                  bool writableOnly)
93 {
94     if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
95     {
96         return OC_STACK_INVALID_PARAM;
97     }
98
99     size_t cborLen = *size;
100     if (0 == cborLen)
101     {
102         cborLen = CBOR_SIZE;
103     }
104
105     *payload = NULL;
106     *size = 0;
107
108     OCStackResult ret = OC_STACK_ERROR;
109     size_t pstatMapSize = PSTAT_MAP_SIZE;
110     CborEncoder encoder;
111     CborEncoder pstatMap;
112     char* strUuid = NULL;
113
114     int64_t cborEncoderResult = CborNoError;
115
116     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
117     VERIFY_NON_NULL(TAG, outPayload, ERROR);
118     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
119
120     if (false == writableOnly)
121     {
122         pstatMapSize += WRITEABLE_PROPERTY_SIZE;
123     }
124
125     cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, pstatMapSize);
126     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
127
128     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
129         strlen(OIC_JSON_ISOP_NAME));
130     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
131     cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
132     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
133
134     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
135         strlen(OIC_JSON_CM_NAME));
136     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
137     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->cm);
138     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Value.");
139
140     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_TM_NAME,
141         strlen(OIC_JSON_TM_NAME));
142     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Tag.");
143     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->tm);
144     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Value.");
145
146     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_OM_NAME,
147         strlen(OIC_JSON_OM_NAME));
148     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Tag.");
149     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
150     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
151
152     if (false == writableOnly)
153     {
154         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
155             strlen(OIC_JSON_SM_NAME));
156         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
157         cborEncoderResult = cbor_encode_int(&pstatMap, pstat->sm[0]);
158         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Value.");
159
160         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
161             strlen(OIC_JSON_DEVICE_ID_NAME));
162         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
163         ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
164         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
165         cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
166         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
167         OICFree(strUuid);
168         strUuid = NULL;
169
170         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
171             strlen(OIC_JSON_ROWNERID_NAME));
172         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
173         ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
174         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
175         cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
176         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
177         OICFree(strUuid);
178         strUuid = NULL;
179     }
180
181     //RT -- Mandatory
182     CborEncoder rtArray;
183     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_RT_NAME,
184             strlen(OIC_JSON_RT_NAME));
185     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
186     cborEncoderResult = cbor_encoder_create_array(&pstatMap, &rtArray, 1);
187     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
188     for (size_t i = 0; i < 1; i++)
189     {
190         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_PSTAT,
191                 strlen(OIC_RSRC_TYPE_SEC_PSTAT));
192         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
193     }
194     cborEncoderResult = cbor_encoder_close_container(&pstatMap, &rtArray);
195     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
196
197     //IF-- Mandatory
198      CborEncoder ifArray;
199      cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_IF_NAME,
200              strlen(OIC_JSON_IF_NAME));
201      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
202      cborEncoderResult = cbor_encoder_create_array(&pstatMap, &ifArray, 1);
203      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
204     for (size_t i = 0; i < 1; i++)
205     {
206         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
207                 strlen(OC_RSRVD_INTERFACE_DEFAULT));
208         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
209     }
210     cborEncoderResult = cbor_encoder_close_container(&pstatMap, &ifArray);
211     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
212
213     cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
214     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
215
216     if (CborNoError == cborEncoderResult)
217     {
218         *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
219         *payload = outPayload;
220         ret = OC_STACK_OK;
221     }
222 exit:
223     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
224     {
225         // reallocate and try again!
226         OICFree(outPayload);
227         // Since the allocated initial memory failed, double the memory.
228         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
229         cborEncoderResult = CborNoError;
230         ret = PstatToCBORPayload(pstat, payload, &cborLen, writableOnly);
231         if (OC_STACK_OK == ret)
232         {
233             *size = cborLen;
234         }
235     }
236
237     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
238     {
239         OICFree(outPayload);
240         outPayload = NULL;
241         *payload = NULL;
242         *size = 0;
243         ret = OC_STACK_ERROR;
244     }
245
246     return ret;
247 }
248
249 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
250                                  OicSecPstat_t **secPstat)
251 {
252     return CBORPayloadToPstatBin(cborPayload, size, secPstat, NULL);
253 }
254
255 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
256                                  OicSecPstat_t **secPstat, bool *roParsed)
257 {
258     if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat || 0 == size)
259     {
260         return OC_STACK_INVALID_PARAM;
261     }
262
263     OCStackResult ret = OC_STACK_ERROR;
264     *secPstat = NULL;
265
266     CborValue pstatCbor;
267     CborParser parser;
268     CborError cborFindResult = CborNoError;
269     char *strUuid = NULL;
270     size_t len = 0;
271
272     cbor_parser_init(cborPayload, size, 0, &parser, &pstatCbor);
273     CborValue pstatMap = { .parser = NULL };
274
275     OicSecPstat_t *pstat = NULL;
276     cborFindResult = cbor_value_enter_container(&pstatCbor, &pstatMap);
277     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Map.");
278
279     pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
280     VERIFY_NON_NULL(TAG, pstat, ERROR);
281
282     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ISOP_NAME, &pstatMap);
283     if (CborNoError == cborFindResult && cbor_value_is_boolean(&pstatMap))
284     {
285         cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
286         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
287     }
288     else
289     {
290         pstat->isOp = gPstat->isOp;
291         cborFindResult = CborNoError;
292     }
293
294     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
295     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
296     {
297         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
298         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
299         ret = ConvertStrToUuid(strUuid , &pstat->deviceID);
300         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
301         OICFree(strUuid );
302         strUuid  = NULL;
303
304     }
305     else
306     {
307         memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
308         cborFindResult = CborNoError;
309     }
310
311     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
312     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
313     {
314         int cm;
315
316         cborFindResult = cbor_value_get_int(&pstatMap, &cm);
317         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
318         pstat->cm = (OicSecDpm_t)cm;
319     }
320     else
321     {
322         pstat->cm = gPstat->cm;
323         cborFindResult = CborNoError;
324     }
325
326     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
327     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
328     {
329         int tm;
330
331         cborFindResult = cbor_value_get_int(&pstatMap, &tm);
332         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
333         pstat->tm = (OicSecDpm_t)tm;
334     }
335     else
336     {
337         pstat->tm = gPstat->tm;
338         cborFindResult = CborNoError;
339     }
340
341     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
342     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
343     {
344         int om;
345
346         cborFindResult = cbor_value_get_int(&pstatMap, &om);
347         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
348         pstat->om = (OicSecDpom_t)om;
349     }
350     else
351     {
352         pstat->om = gPstat->om;
353         cborFindResult = CborNoError;
354     }
355
356     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
357     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
358     {
359         int sm;
360
361         pstat->smLen = 1;
362         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
363         cborFindResult = cbor_value_get_int(&pstatMap, &sm);
364         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
365         pstat->sm[0] = (OicSecDpom_t)sm;
366
367         if (roParsed)
368         {
369             *roParsed = true;
370         }
371     }
372     else
373     {
374         VERIFY_NON_NULL(TAG, gPstat, ERROR);
375         pstat->smLen = gPstat->smLen;
376         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
377         *pstat->sm = *gPstat->sm;
378         cborFindResult = CborNoError;
379     }
380
381     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
382     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
383     {
384         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
385         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Id Value.");
386         ret = ConvertStrToUuid(strUuid , &pstat->rownerID);
387         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
388         OICFree(strUuid );
389         strUuid  = NULL;
390     }
391     else
392     {
393         VERIFY_NON_NULL(TAG, gPstat, ERROR);
394         memcpy(pstat->rownerID.id, gPstat->rownerID.id, sizeof(gPstat->rownerID.id));
395         cborFindResult = CborNoError;
396     }
397
398     *secPstat = pstat;
399     ret = OC_STACK_OK;
400
401 exit:
402     if (CborNoError != cborFindResult)
403     {
404         OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
405         DeletePstatBinData(pstat);
406         pstat = NULL;
407         *secPstat = NULL;
408         ret = OC_STACK_ERROR;
409     }
410
411     return ret;
412 }
413
414 /**
415  * Function to update persistent storage
416  */
417 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
418 {
419     bool bRet = false;
420
421     size_t size = 0;
422     uint8_t *cborPayload = NULL;
423     OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size, false);
424     if (OC_STACK_OK == ret)
425     {
426         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
427         {
428             bRet = true;
429         }
430         OICFree(cborPayload);
431     }
432
433     return bRet;
434 }
435
436 static bool ValidateQuery(const char * query)
437 {
438     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
439     if(NULL == gPstat)
440     {
441         return false;
442     }
443
444     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
445     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
446
447     OicParseQueryIter_t parseIter = {.attrPos = NULL};
448
449     ParseQueryIterInit((unsigned char*)query, &parseIter);
450
451     while (GetNextQuery(&parseIter))
452     {
453         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
454         {
455             bInterfaceQry = true;
456             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
457             {
458                 bInterfaceMatch = true;
459             }
460         }
461     }
462     return (bInterfaceQry ? bInterfaceMatch: true);
463 }
464
465 /**
466  * The entity handler determines how to process a GET request.
467  */
468 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
469 {
470     OCEntityHandlerResult ehRet = OC_EH_OK;
471
472     OIC_LOG(INFO, TAG, "HandlePstatGetRequest  processing GET request");
473
474     //Checking if Get request is a query.
475     if (ehRequest->query)
476     {
477         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
478         OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
479         if (!ValidateQuery(ehRequest->query))
480         {
481             ehRet = OC_EH_ERROR;
482         }
483     }
484
485     /*
486      * For GET or Valid Query request return doxm resource CBOR payload.
487      * For non-valid query return NULL json payload.
488      * A device will 'always' have a default Pstat, so PstatToCBORPayload will
489      * return valid pstat resource json.
490      */
491     size_t size = 0;
492     uint8_t *payload = NULL;
493     if (ehRet == OC_EH_OK)
494     {
495         if(OC_STACK_OK != PstatToCBORPayload(gPstat, &payload, &size, false))
496         {
497             OIC_LOG(WARNING, TAG, "PstatToCBORPayload failed in HandlePstatGetRequest");
498         }
499     }
500
501     // Send response payload to request originator
502     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
503                    OC_EH_OK : OC_EH_ERROR;
504     OICFree(payload);
505     return ehRet;
506 }
507
508 /**
509  * The entity handler determines how to process a POST request.
510  * Per the REST paradigm, POST can also be used to update representation of existing
511  * resource or create a new resource.
512  * For pstat, it updates only tm and om.
513  */
514 static OCEntityHandlerResult HandlePstatPostRequest(const OCEntityHandlerRequest *ehRequest)
515 {
516     OCEntityHandlerResult ehRet = OC_EH_ERROR;
517     OIC_LOG(INFO, TAG, "HandlePstatPostRequest  processing POST request");
518     OicSecPstat_t *pstat = NULL;
519     static uint16_t prevMsgId = 0;
520
521     if (ehRequest->payload && NULL != gPstat)
522     {
523         uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
524         size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
525         VERIFY_NON_NULL(TAG, payload, ERROR);
526
527         bool roParsed = false;
528         OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
529         VERIFY_NON_NULL(TAG, pstat, ERROR);
530         if (OC_STACK_OK == ret)
531         {
532             bool validReq = false;
533
534             if (true == roParsed)
535             {
536                     OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
537                     ehRet = OC_EH_NOT_ACCEPTABLE;
538                     goto exit;
539             }
540
541             //operation mode(om) should be one of supported modes(sm)
542             for(size_t i = 0; i < gPstat->smLen; i++)
543             {
544                 if(gPstat->sm[i] == pstat->om)
545                 {
546                     validReq = true;
547                     break;
548                 }
549             }
550
551             if(!validReq)
552             {
553                 OIC_LOG_V(ERROR, TAG, "%d is unsupported Operation Mode", (int) pstat->om);
554                 ehRet = OC_EH_BAD_REQ;
555                 goto exit;
556             }
557             validReq = false;
558
559             //Currently, IoTivity only supports Single Service Client Directed provisioning
560             if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
561             {
562                 if ((pstat->cm & RESET) && false == pstat->isOp)
563                 {
564                     validReq = true;
565                     OIC_LOG(INFO, TAG, "State changed to Ready for Reset");
566                 }
567                 else if ((pstat->cm & TAKE_OWNER) && false == pstat->isOp)
568                 {
569                     validReq = true;
570                     OIC_LOG (INFO, TAG, "State changed to Ready for Ownership transfer");
571                 }
572                 else if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
573                 {
574                     validReq = true;
575                     OIC_LOG(INFO, TAG, "State changed to Ready for Provisioning");
576                 }
577                 else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
578                 {
579                     validReq = true;
580                     OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
581                 }
582                 else
583                 {
584                     OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
585                     OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
586                     ehRet = OC_EH_BAD_REQ;
587                     goto exit;
588                 }
589             }
590
591             if (!validReq)
592             {
593                 OIC_LOG(DEBUG, TAG, "Bad request for PSTAT");
594                 ehRet = OC_EH_BAD_REQ;
595                 goto exit;
596             }
597
598             gPstat->isOp = pstat->isOp;
599             gPstat->om = pstat->om;
600             gPstat->tm = pstat->tm;
601             gPstat->cm = pstat->cm;
602             memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
603             memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
604
605             // Convert pstat data into CBOR for update to persistent storage
606             if (UpdatePersistentStorage(gPstat))
607             {
608                 ehRet = OC_EH_OK;
609             }
610             if (true == (pstat->cm & RESET))
611             {
612                 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
613                 {
614                     ehRet = OC_EH_ERROR;
615                     OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
616                     DeletePstatBinData(pstat);
617                     return ehRet;
618                 }
619                 ret = ResetSecureResourceInPS();
620                 if (OC_STACK_OK == ret)
621                 {
622                     ehRet = OC_EH_OK;
623                 }
624                 DeletePstatBinData(pstat);
625                 return ehRet;
626             }
627         }
628     }
629  exit:
630
631      if(OC_EH_OK != ehRet)
632      {
633          /*
634            * If some error is occured while ownership transfer,
635            * ownership transfer related resource should be revert back to initial status.
636            */
637          const OicSecDoxm_t* doxm = GetDoxmResourceData();
638          if(doxm)
639          {
640              if(!doxm->owned && prevMsgId !=  ehRequest->messageID)
641              {
642                  RestoreDoxmToInitState();
643                  RestorePstatToInitState();
644              }
645          }
646          else
647          {
648              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
649          }
650      }
651      else
652      {
653          prevMsgId = ehRequest->messageID;
654      }
655
656     // Send response payload to request originator
657     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
658                    OC_EH_OK : OC_EH_ERROR;
659
660     DeletePstatBinData(pstat);
661     return ehRet;
662 }
663
664 /**
665  * This internal method is the entity handler for pstat resources.
666  */
667  OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
668                                           OCEntityHandlerRequest * ehRequest,
669                                           void *callbackParam)
670 {
671     (void)callbackParam;
672     OCEntityHandlerResult ehRet = OC_EH_ERROR;
673     // This method will handle REST request (GET/POST) for /oic/sec/pstat
674     if (flag & OC_REQUEST_FLAG)
675     {
676         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
677         switch (ehRequest->method)
678         {
679             case OC_REST_GET:
680                 ehRet = HandlePstatGetRequest(ehRequest);
681                 break;
682             case OC_REST_POST:
683                 ehRet = HandlePstatPostRequest(ehRequest);
684                 break;
685             default:
686                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
687                                OC_EH_OK : OC_EH_ERROR;
688                 break;
689         }
690     }
691     return ehRet;
692 }
693
694 /**
695  * This internal method is used to create '/oic/sec/pstat' resource.
696  */
697  OCStackResult CreatePstatResource()
698 {
699     OCStackResult ret = OCCreateResource(&gPstatHandle,
700                                          OIC_RSRC_TYPE_SEC_PSTAT,
701                                          OC_RSRVD_INTERFACE_DEFAULT,
702                                          OIC_RSRC_PSTAT_URI,
703                                          PstatEntityHandler,
704                                          NULL,
705                                          OC_SECURE |
706                                          OC_DISCOVERABLE);
707
708     if (OC_STACK_OK != ret)
709     {
710         OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
711         DeInitPstatResource();
712     }
713     return ret;
714 }
715
716 /**
717  * Get the default value.
718  *
719  * @return the gDefaultPstat pointer.
720  */
721 static OicSecPstat_t* GetPstatDefault()
722 {
723     return &gDefaultPstat;
724 }
725
726 OCStackResult InitPstatResource()
727 {
728     OCStackResult ret = OC_STACK_ERROR;
729
730     // Read Pstat resource from PS
731     uint8_t *data = NULL;
732     size_t size = 0;
733     OicUuid_t emptyUuid = {.id={0}};
734     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
735     // If database read failed
736     if (OC_STACK_OK != ret)
737     {
738         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
739     }
740     if (data)
741     {
742         // Read ACL resource from PS
743         ret = CBORPayloadToPstat(data, size, &gPstat);
744         OICFree(data);
745     }
746     /*
747      * If SVR database in persistent storage got corrupted or
748      * is not available for some reason, a default pstat is created
749      * which allows user to initiate pstat provisioning again.
750      */
751     if ((OC_STACK_OK != ret) || !gPstat)
752     {
753         gPstat = GetPstatDefault();
754     }
755     VERIFY_NON_NULL(TAG, gPstat, FATAL);
756
757     //In case of Pstat's device id is empty, fill the device id as doxm's device id.
758     if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
759     {
760         OicUuid_t doxmUuid = {.id={0}};
761         if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
762         {
763             memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
764         }
765     }
766
767     // Instantiate 'oic.sec.pstat'
768     ret = CreatePstatResource();
769
770 exit:
771     if (OC_STACK_OK != ret)
772     {
773         DeInitPstatResource();
774     }
775     return ret;
776 }
777
778 OCStackResult DeInitPstatResource()
779 {
780     if (gPstat != &gDefaultPstat)
781     {
782         DeletePstatBinData(gPstat);
783         gPstat = NULL;
784     }
785     return OCDeleteResource(gPstatHandle);
786 }
787
788 /**
789  * Function to restore pstat resurce to initial status.
790  * This function will use in case of error while ownership transfer
791  */
792 void RestorePstatToInitState()
793 {
794     if(gPstat)
795     {
796         OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
797
798         gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
799         gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
800         gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
801         if(gPstat->sm && 0 < gPstat->smLen)
802         {
803             gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
804         }
805
806         if (!UpdatePersistentStorage(gPstat))
807         {
808             OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
809         }
810     }
811 }
812
813 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
814 {
815     OCStackResult ret = OC_STACK_ERROR;
816     uint8_t *cborPayload = NULL;
817     size_t size = 0;
818     OicUuid_t prevId = {.id={0}};
819
820     if(NULL == newROwner)
821     {
822         ret = OC_STACK_INVALID_PARAM;
823     }
824     if(NULL == gPstat)
825     {
826         ret = OC_STACK_NO_RESOURCE;
827     }
828
829     if(newROwner && gPstat)
830     {
831         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
832         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
833
834         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
835         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
836
837         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
838         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
839
840         OICFree(cborPayload);
841     }
842
843     return ret;
844
845 exit:
846     OICFree(cborPayload);
847     memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
848     return ret;
849 }
850
851 /**
852  * This function returns the "isop" status of the device.
853  *
854  * @return true iff pstat.isop == 1, else false
855  */
856 bool GetPstatIsop()
857 {
858     return gPstat->isOp;
859 }
860
861 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
862 {
863     OCStackResult retVal = OC_STACK_ERROR;
864     if (gPstat)
865     {
866         *rowneruuid = gPstat->rownerID;
867         retVal = OC_STACK_OK;
868     }
869     return retVal;
870 }