fix: messageID for coap over TCP always is null
[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(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 previousMsgId = 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)
641              {
642                 OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
643
644                 if((OC_ADAPTER_IP == ehRequest->devAddr.adapter && previousMsgId != ehRequest->messageID)
645                    || OC_ADAPTER_TCP == ehRequest->devAddr.adapter)
646                 {
647                     RestoreDoxmToInitState();
648                     RestorePstatToInitState();
649                     OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
650                 }
651              }
652          }
653          else
654          {
655              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
656          }
657      }
658      else
659      {
660         if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
661         {
662             previousMsgId = ehRequest->messageID++;
663         }
664      }
665
666     // Send response payload to request originator
667     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
668                    OC_EH_OK : OC_EH_ERROR;
669
670     DeletePstatBinData(pstat);
671     return ehRet;
672 }
673
674 /**
675  * This internal method is the entity handler for pstat resources.
676  */
677  OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
678                                           OCEntityHandlerRequest * ehRequest,
679                                           void *callbackParam)
680 {
681     (void)callbackParam;
682     OCEntityHandlerResult ehRet = OC_EH_ERROR;
683     // This method will handle REST request (GET/POST) for /oic/sec/pstat
684     if (flag & OC_REQUEST_FLAG)
685     {
686         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
687         switch (ehRequest->method)
688         {
689             case OC_REST_GET:
690                 ehRet = HandlePstatGetRequest(ehRequest);
691                 break;
692             case OC_REST_POST:
693                 ehRet = HandlePstatPostRequest(ehRequest);
694                 break;
695             default:
696                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
697                                OC_EH_OK : OC_EH_ERROR;
698                 break;
699         }
700     }
701     return ehRet;
702 }
703
704 /**
705  * This internal method is used to create '/oic/sec/pstat' resource.
706  */
707  OCStackResult CreatePstatResource()
708 {
709     OCStackResult ret = OCCreateResource(&gPstatHandle,
710                                          OIC_RSRC_TYPE_SEC_PSTAT,
711                                          OC_RSRVD_INTERFACE_DEFAULT,
712                                          OIC_RSRC_PSTAT_URI,
713                                          PstatEntityHandler,
714                                          NULL,
715                                          OC_SECURE |
716                                          OC_DISCOVERABLE);
717
718     if (OC_STACK_OK != ret)
719     {
720         OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
721         DeInitPstatResource();
722     }
723     return ret;
724 }
725
726 /**
727  * Get the default value.
728  *
729  * @return the gDefaultPstat pointer.
730  */
731 static OicSecPstat_t* GetPstatDefault()
732 {
733     return &gDefaultPstat;
734 }
735
736 OCStackResult InitPstatResource()
737 {
738     OCStackResult ret = OC_STACK_ERROR;
739
740     // Read Pstat resource from PS
741     uint8_t *data = NULL;
742     size_t size = 0;
743     OicUuid_t emptyUuid = {.id={0}};
744     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
745     // If database read failed
746     if (OC_STACK_OK != ret)
747     {
748         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
749     }
750     if (data)
751     {
752         // Read ACL resource from PS
753         ret = CBORPayloadToPstat(data, size, &gPstat);
754         OICFree(data);
755     }
756     /*
757      * If SVR database in persistent storage got corrupted or
758      * is not available for some reason, a default pstat is created
759      * which allows user to initiate pstat provisioning again.
760      */
761     if ((OC_STACK_OK != ret) || !gPstat)
762     {
763         gPstat = GetPstatDefault();
764     }
765     VERIFY_NON_NULL(TAG, gPstat, FATAL);
766
767     //In case of Pstat's device id is empty, fill the device id as doxm's device id.
768     if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
769     {
770         OicUuid_t doxmUuid = {.id={0}};
771         if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
772         {
773             memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
774         }
775     }
776
777     // Instantiate 'oic.sec.pstat'
778     ret = CreatePstatResource();
779
780 exit:
781     if (OC_STACK_OK != ret)
782     {
783         DeInitPstatResource();
784     }
785     return ret;
786 }
787
788 OCStackResult DeInitPstatResource()
789 {
790     if (gPstat != &gDefaultPstat)
791     {
792         DeletePstatBinData(gPstat);
793         gPstat = NULL;
794     }
795     return OCDeleteResource(gPstatHandle);
796 }
797
798 /**
799  * Function to restore pstat resurce to initial status.
800  * This function will use in case of error while ownership transfer
801  */
802 void RestorePstatToInitState()
803 {
804     if(gPstat)
805     {
806         OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
807
808         gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
809         gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
810         gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
811         if(gPstat->sm && 0 < gPstat->smLen)
812         {
813             gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
814         }
815
816         if (!UpdatePersistentStorage(gPstat))
817         {
818             OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
819         }
820     }
821 }
822
823 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
824 {
825     OCStackResult ret = OC_STACK_ERROR;
826     uint8_t *cborPayload = NULL;
827     size_t size = 0;
828     OicUuid_t prevId = {.id={0}};
829
830     if(NULL == newROwner)
831     {
832         ret = OC_STACK_INVALID_PARAM;
833     }
834     if(NULL == gPstat)
835     {
836         ret = OC_STACK_NO_RESOURCE;
837     }
838
839     if(newROwner && gPstat)
840     {
841         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
842         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
843
844         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
845         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
846
847         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
848         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
849
850         OICFree(cborPayload);
851     }
852
853     return ret;
854
855 exit:
856     OICFree(cborPayload);
857     memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
858     return ret;
859 }
860
861 /**
862  * This function returns the "isop" status of the device.
863  *
864  * @return true iff pstat.isop == 1, else false
865  */
866 bool GetPstatIsop()
867 {
868     return gPstat->isOp;
869 }
870
871 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
872 {
873     OCStackResult retVal = OC_STACK_ERROR;
874     if (gPstat)
875     {
876         *rowneruuid = gPstat->rownerID;
877         retVal = OC_STACK_OK;
878     }
879     return retVal;
880 }