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