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