1 //******************************************************************
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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 #include "aclresource.h"
36 #include "credresource.h"
37 #include "ocprovisioningmanager.h"
39 #define TAG "OIC_SRM_PSTAT"
41 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
42 * The value of payload size is increased until reaching below max cbor size. */
43 static const uint16_t CBOR_SIZE = 512;
45 // Max cbor size payload.
46 static const uint16_t CBOR_MAX_SIZE = 4400;
48 // PSTAT Map size - Number of mandatory items
49 static const uint8_t PSTAT_MAP_SIZE = 6;
51 // Number of writeable property
52 static const uint8_t WRITEABLE_PROPERTY_SIZE = 3;
54 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
55 static OicSecPstat_t gDefaultPstat =
58 (OicSecDpm_t)(BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
59 PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t cm
60 (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
61 PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t tm
62 {.id = {0}}, // OicUuid_t deviceID
63 SINGLE_SERVICE_CLIENT_DRIVEN, // OicSecDpom_t om */
64 1, // the number of elts in Sms
65 &gSm, // OicSecDpom_t *sm
66 0, // uint16_t commitHash
67 {.id = {0}}, // OicUuid_t rownerID
70 static OicSecPstat_t *gPstat = NULL;
72 static OCResourceHandle gPstatHandle = NULL;
75 * This method is internal method.
76 * the param roParsed is optionally used to know whether cborPayload has
77 * at least read only property value or not.
79 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
80 OicSecPstat_t **secPstat, bool *roParsed);
82 void DeletePstatBinData(OicSecPstat_t* pstat)
86 //Clean 'supported modes' field
94 OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size,
97 if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
99 return OC_STACK_INVALID_PARAM;
102 size_t cborLen = *size;
111 OCStackResult ret = OC_STACK_ERROR;
112 size_t pstatMapSize = PSTAT_MAP_SIZE;
114 CborEncoder pstatMap;
115 char* strUuid = NULL;
117 int64_t cborEncoderResult = CborNoError;
119 uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
120 VERIFY_NON_NULL(TAG, outPayload, ERROR);
121 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
123 if (false == writableOnly)
125 pstatMapSize += WRITEABLE_PROPERTY_SIZE;
128 cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, pstatMapSize);
129 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
131 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
132 strlen(OIC_JSON_ISOP_NAME));
133 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
134 cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
135 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
137 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
138 strlen(OIC_JSON_CM_NAME));
139 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
140 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->cm);
141 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Value.");
143 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_TM_NAME,
144 strlen(OIC_JSON_TM_NAME));
145 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Tag.");
146 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->tm);
147 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Value.");
149 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_OM_NAME,
150 strlen(OIC_JSON_OM_NAME));
151 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Tag.");
152 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
153 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
155 if (false == writableOnly)
157 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
158 strlen(OIC_JSON_SM_NAME));
159 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
160 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->sm[0]);
161 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Value.");
163 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
164 strlen(OIC_JSON_DEVICE_ID_NAME));
165 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
166 ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
167 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
168 cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
169 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
173 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
174 strlen(OIC_JSON_ROWNERID_NAME));
175 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
176 ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
177 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
178 cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
179 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
186 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_RT_NAME,
187 strlen(OIC_JSON_RT_NAME));
188 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
189 cborEncoderResult = cbor_encoder_create_array(&pstatMap, &rtArray, 1);
190 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
191 for (size_t i = 0; i < 1; i++)
193 cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_PSTAT,
194 strlen(OIC_RSRC_TYPE_SEC_PSTAT));
195 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
197 cborEncoderResult = cbor_encoder_close_container(&pstatMap, &rtArray);
198 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
202 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_IF_NAME,
203 strlen(OIC_JSON_IF_NAME));
204 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
205 cborEncoderResult = cbor_encoder_create_array(&pstatMap, &ifArray, 1);
206 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
207 for (size_t i = 0; i < 1; i++)
209 cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
210 strlen(OC_RSRVD_INTERFACE_DEFAULT));
211 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
213 cborEncoderResult = cbor_encoder_close_container(&pstatMap, &ifArray);
214 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
216 cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
217 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
219 if (CborNoError == cborEncoderResult)
221 *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
222 *payload = outPayload;
226 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
228 // reallocate and try again!
231 // Since the allocated initial memory failed, double the memory.
232 cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
233 cborEncoderResult = CborNoError;
234 ret = PstatToCBORPayload(pstat, payload, &cborLen, writableOnly);
235 if (OC_STACK_OK == ret)
241 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
247 ret = OC_STACK_ERROR;
253 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
254 OicSecPstat_t **secPstat)
256 return CBORPayloadToPstatBin(cborPayload, size, secPstat, NULL);
259 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
260 OicSecPstat_t **secPstat, bool *roParsed)
262 if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat || 0 == size)
264 return OC_STACK_INVALID_PARAM;
267 OCStackResult ret = OC_STACK_ERROR;
272 CborError cborFindResult = CborNoError;
273 char *strUuid = NULL;
276 cbor_parser_init(cborPayload, size, 0, &parser, &pstatCbor);
277 CborValue pstatMap = { .parser = NULL };
279 OicSecPstat_t *pstat = NULL;
280 cborFindResult = cbor_value_enter_container(&pstatCbor, &pstatMap);
281 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Map.");
283 pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
284 VERIFY_NON_NULL(TAG, pstat, ERROR);
286 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ISOP_NAME, &pstatMap);
287 if (CborNoError == cborFindResult && cbor_value_is_boolean(&pstatMap))
289 cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
290 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
294 VERIFY_NON_NULL(TAG, gPstat, ERROR);
295 pstat->isOp = gPstat->isOp;
296 cborFindResult = CborNoError;
299 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
300 if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
302 cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
303 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
304 ret = ConvertStrToUuid(strUuid , &pstat->deviceID);
305 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
312 VERIFY_NON_NULL(TAG, gPstat, ERROR);
313 memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
314 cborFindResult = CborNoError;
317 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
318 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
322 cborFindResult = cbor_value_get_int(&pstatMap, &cm);
323 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
324 pstat->cm = (OicSecDpm_t)cm;
328 VERIFY_NON_NULL(TAG, gPstat, ERROR);
329 pstat->cm = gPstat->cm;
330 cborFindResult = CborNoError;
333 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
334 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
338 cborFindResult = cbor_value_get_int(&pstatMap, &tm);
339 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
340 pstat->tm = (OicSecDpm_t)tm;
344 VERIFY_NON_NULL(TAG, gPstat, ERROR);
345 pstat->tm = gPstat->tm;
346 cborFindResult = CborNoError;
349 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
350 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
354 cborFindResult = cbor_value_get_int(&pstatMap, &om);
355 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
356 pstat->om = (OicSecDpom_t)om;
360 VERIFY_NON_NULL(TAG, gPstat, ERROR);
361 pstat->om = gPstat->om;
362 cborFindResult = CborNoError;
365 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
366 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
371 pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
372 VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
373 cborFindResult = cbor_value_get_int(&pstatMap, &sm);
374 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
375 pstat->sm[0] = (OicSecDpom_t)sm;
384 VERIFY_NON_NULL(TAG, gPstat, ERROR);
385 pstat->smLen = gPstat->smLen;
386 pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
387 VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
388 *pstat->sm = *gPstat->sm;
389 cborFindResult = CborNoError;
392 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
393 if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
395 cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
396 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Id Value.");
397 ret = ConvertStrToUuid(strUuid , &pstat->rownerID);
398 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
404 VERIFY_NON_NULL(TAG, gPstat, ERROR);
405 memcpy(pstat->rownerID.id, gPstat->rownerID.id, sizeof(gPstat->rownerID.id));
406 cborFindResult = CborNoError;
413 if (CborNoError != cborFindResult)
415 OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
416 DeletePstatBinData(pstat);
419 ret = OC_STACK_ERROR;
426 * Function to update persistent storage
428 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
433 uint8_t *cborPayload = NULL;
434 OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size, false);
435 if (OC_STACK_OK == ret)
437 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
441 OICFree(cborPayload);
447 static bool ValidateQuery(const char * query)
449 OIC_LOG (DEBUG, TAG, "In ValidateQuery");
455 bool bInterfaceQry = false; // does querystring contains 'if' query ?
456 bool bInterfaceMatch = false; // does 'if' query matches with oic.if.baseline ?
458 OicParseQueryIter_t parseIter = {.attrPos = NULL};
460 ParseQueryIterInit((unsigned char*)query, &parseIter);
462 while (GetNextQuery(&parseIter))
464 if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
466 bInterfaceQry = true;
467 if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
469 bInterfaceMatch = true;
473 return (bInterfaceQry ? bInterfaceMatch: true);
476 #ifdef MULTIPLE_OWNER
477 bool IsValidPstatAccessForSubOwner(const uint8_t *cborPayload, size_t size)
479 OicSecPstat_t* pstat = NULL;
480 bool isValidPstat = true;
482 OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
483 VERIFY_NON_NULL(TAG, cborPayload, ERROR);
484 VERIFY_SUCCESS(TAG, 0 != size, ERROR);
485 VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToPstat(cborPayload, size, &pstat), ERROR);
486 VERIFY_NON_NULL(TAG, pstat, ERROR);
488 if (RESET & pstat->cm)
490 OIC_LOG(ERROR, TAG, "SubOwner can't reset the server.");
491 isValidPstat = false;
495 DeletePstatBinData(pstat);
498 #endif //MULTIPLE_OWNER
501 * The entity handler determines how to process a GET request.
503 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
505 OCEntityHandlerResult ehRet = OC_EH_OK;
507 OIC_LOG(INFO, TAG, "HandlePstatGetRequest processing GET request");
509 //Checking if Get request is a query.
510 if (ehRequest->query)
512 OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
513 OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
514 if (!ValidateQuery(ehRequest->query))
521 * For GET or Valid Query request return doxm resource CBOR payload.
522 * For non-valid query return NULL json payload.
523 * A device will 'always' have a default Pstat, so PstatToCBORPayload will
524 * return valid pstat resource json.
527 uint8_t *payload = NULL;
528 if (ehRet == OC_EH_OK)
530 if(OC_STACK_OK != PstatToCBORPayload(gPstat, &payload, &size, false))
532 OIC_LOG(WARNING, TAG, "PstatToCBORPayload failed in HandlePstatGetRequest");
536 // Send response payload to request originator
537 ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
538 OC_EH_OK : OC_EH_ERROR;
544 * Checks if device can change state to Ready for Normal Operation.
546 static OCEntityHandlerResult ValidateReadyForNOP(const OicSecPstat_t *pstat)
548 OIC_LOG_V(DEBUG, TAG, "%s: IN", __func__);
550 const OicSecDoxm_t *doxm = GetDoxmResourceData();
551 OicUuid_t rowneruuid;
555 OIC_LOG(WARNING, TAG, "DOXM is NULL");
556 return OC_EH_NOT_ACCEPTABLE;
561 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device is unowned");
562 return OC_EH_NOT_ACCEPTABLE;
565 if (IsNilUuid(&doxm->owner))
567 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device owner is NIL");
568 return OC_EH_INTERNAL_SERVER_ERROR;
571 if (IsNilUuid(&doxm->deviceID))
573 OIC_LOG(WARNING, TAG,
574 "Can't change state to Ready for Normal Operation: the device owner ID is NIL");
575 return OC_EH_INTERNAL_SERVER_ERROR;
578 if (IsNilUuid(&doxm->rownerID))
580 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the doxm rowner is NIL");
581 return OC_EH_INTERNAL_SERVER_ERROR;
585 if (IsNilUuid(&pstat->rownerID))
587 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the pstat rowner is NIL");
588 return OC_EH_INTERNAL_SERVER_ERROR;
591 memset(&rowneruuid, 0, sizeof(OicUuid_t));
592 if (OC_STACK_OK != GetAclRownerId(&rowneruuid))
594 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get acl");
595 return OC_EH_INTERNAL_SERVER_ERROR;
598 if (IsNilUuid(&rowneruuid))
600 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the acl rowner is NIL");
601 return OC_EH_INTERNAL_SERVER_ERROR;
604 memset(&rowneruuid, 0, sizeof(OicUuid_t));
605 if (OC_STACK_OK != GetCredRownerId(&rowneruuid))
607 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get cred");
608 return OC_EH_INTERNAL_SERVER_ERROR;
611 if (IsNilUuid(&rowneruuid))
613 OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the cred rowner is NIL");
614 return OC_EH_INTERNAL_SERVER_ERROR;
617 OIC_LOG_V(DEBUG, TAG, "%s: OUT", __func__);
624 * The entity handler determines how to process a POST request.
625 * Per the REST paradigm, POST can also be used to update representation of existing
626 * resource or create a new resource.
627 * For pstat, it updates only tm and om.
629 static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRequest)
631 OCEntityHandlerResult ehRet = OC_EH_ERROR;
632 OIC_LOG(INFO, TAG, "HandlePstatPostRequest processing POST request");
633 OicSecPstat_t *pstat = NULL;
634 static uint16_t previousMsgId = 0;
635 bool isDuplicatedMsg = false;
637 if (ehRequest->payload && NULL != gPstat)
639 uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
640 size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
641 VERIFY_NON_NULL(TAG, payload, ERROR);
643 bool roParsed = false;
644 OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
645 VERIFY_NON_NULL(TAG, pstat, ERROR);
646 if (OC_STACK_OK == ret)
648 bool validReq = false;
651 * message ID is supported for CoAP over UDP only according to RFC 7252
652 * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
653 * In case of other transport adapter, duplicate message check is not required.
655 if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
656 previousMsgId == ehRequest->messageID)
658 isDuplicatedMsg = true;
661 if (true == roParsed)
663 OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
664 ehRet = OC_EH_NOT_ACCEPTABLE;
668 //operation mode(om) should be one of supported modes(sm)
669 for(size_t i = 0; i < gPstat->smLen; i++)
671 if(gPstat->sm[i] == pstat->om)
680 OIC_LOG_V(ERROR, TAG, "%d is unsupported Operation Mode", (int) pstat->om);
681 ehRet = OC_EH_BAD_REQ;
686 //Currently, IoTivity only supports Single Service Client Directed provisioning
687 if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
689 if ((pstat->cm & RESET) && false == pstat->isOp)
692 OIC_LOG(INFO, TAG, "State changed to Ready for Reset");
694 else if ((pstat->cm & TAKE_OWNER) && false == pstat->isOp)
697 OIC_LOG (INFO, TAG, "State changed to Ready for Ownership transfer");
699 else if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
702 OIC_LOG(INFO, TAG, "State changed to Ready for Provisioning");
704 else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
706 ehRet = ValidateReadyForNOP(pstat);
707 if(OC_EH_OK != ehRet)
712 OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
716 OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
717 OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
718 ehRet = OC_EH_BAD_REQ;
725 OIC_LOG(DEBUG, TAG, "Bad request for PSTAT");
726 ehRet = OC_EH_BAD_REQ;
730 gPstat->isOp = pstat->isOp;
731 gPstat->om = pstat->om;
732 gPstat->tm = pstat->tm;
733 gPstat->cm = pstat->cm;
734 memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
735 memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
737 // Convert pstat data into CBOR for update to persistent storage
738 if (UpdatePersistentStorage(gPstat))
742 if (true == (pstat->cm & RESET))
744 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
747 OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
748 DeletePstatBinData(pstat);
751 ret = ResetSecureResourceInPS();
752 if (OC_STACK_OK == ret)
756 DeletePstatBinData(pstat);
763 if(OC_EH_OK != ehRet)
766 * If some error is occured while ownership transfer,
767 * ownership transfer related resource should be revert back to initial status.
769 const OicSecDoxm_t* doxm = GetDoxmResourceData();
770 if(doxm && !doxm->owned)
772 OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
774 if (!isDuplicatedMsg)
776 #if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
777 InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
778 NULL, OIC_OTM_ERROR);
780 ResetSecureResourceInPS();
781 OIC_LOG(INFO, TAG, "DOXM will be reverted.");
786 OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
787 ResetSecureResourceInPS();
792 if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
794 previousMsgId = ehRequest->messageID;
798 // Send response payload to request originator
799 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
800 OC_EH_OK : OC_EH_ERROR;
802 DeletePstatBinData(pstat);
807 * This internal method is the entity handler for pstat resources.
809 OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
810 OCEntityHandlerRequest * ehRequest,
814 OCEntityHandlerResult ehRet = OC_EH_ERROR;
815 // This method will handle REST request (GET/POST) for /oic/sec/pstat
816 if (flag & OC_REQUEST_FLAG)
818 OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
819 switch (ehRequest->method)
822 ehRet = HandlePstatGetRequest(ehRequest);
825 ehRet = HandlePstatPostRequest(ehRequest);
828 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
829 OC_EH_OK : OC_EH_ERROR;
837 * This internal method is used to create '/oic/sec/pstat' resource.
839 OCStackResult CreatePstatResource()
841 OCStackResult ret = OCCreateResource(&gPstatHandle,
842 OIC_RSRC_TYPE_SEC_PSTAT,
843 OC_RSRVD_INTERFACE_DEFAULT,
850 if (OC_STACK_OK != ret)
852 OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
853 DeInitPstatResource();
859 * Get the default value.
861 * @return the gDefaultPstat pointer.
863 static OicSecPstat_t* GetPstatDefault()
865 return &gDefaultPstat;
868 OCStackResult InitPstatResource()
870 OCStackResult ret = OC_STACK_ERROR;
872 // Read Pstat resource from PS
873 uint8_t *data = NULL;
875 OicUuid_t emptyUuid = {.id={0}};
876 ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
877 // If database read failed
878 if (OC_STACK_OK != ret)
880 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
884 // Read ACL resource from PS
885 ret = CBORPayloadToPstat(data, size, &gPstat);
889 * If SVR database in persistent storage got corrupted or
890 * is not available for some reason, a default pstat is created
891 * which allows user to initiate pstat provisioning again.
893 if ((OC_STACK_OK != ret) || !gPstat)
895 gPstat = GetPstatDefault();
897 VERIFY_NON_NULL(TAG, gPstat, FATAL);
899 //In case of Pstat's device id is empty, fill the device id as doxm's device id.
900 if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
902 OicUuid_t doxmUuid = {.id={0}};
903 if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
905 memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
909 // Instantiate 'oic.sec.pstat'
910 ret = CreatePstatResource();
913 if (OC_STACK_OK != ret)
915 DeInitPstatResource();
920 OCStackResult DeInitPstatResource()
922 if (gPstat != &gDefaultPstat)
924 DeletePstatBinData(gPstat);
927 return OCDeleteResource(gPstatHandle);
931 * Function to restore pstat resurce to initial status.
932 * This function will use in case of error while ownership transfer
934 void RestorePstatToInitState()
938 OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
940 gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
941 gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
942 gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
943 if(gPstat->sm && 0 < gPstat->smLen)
945 gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
948 if (!UpdatePersistentStorage(gPstat))
950 OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
955 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
957 OCStackResult ret = OC_STACK_ERROR;
958 uint8_t *cborPayload = NULL;
960 OicUuid_t prevId = {.id={0}};
962 if(NULL == newROwner)
964 ret = OC_STACK_INVALID_PARAM;
968 ret = OC_STACK_NO_RESOURCE;
971 if(newROwner && gPstat)
973 memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
974 memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
976 ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
977 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
979 ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
980 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
982 OICFree(cborPayload);
988 OICFree(cborPayload);
989 memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
994 * This function returns the "isop" status of the device.
996 * @return true iff pstat.isop == 1, else false
1002 return gPstat->isOp;
1006 //In case of gPstat is NULL
1011 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
1013 OCStackResult retVal = OC_STACK_ERROR;
1016 *rowneruuid = gPstat->rownerID;
1017 retVal = OC_STACK_OK;
1022 OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
1024 OCStackResult ret = OC_STACK_ERROR;
1025 uint8_t *cborPayload = NULL;
1030 ret = OC_STACK_NO_RESOURCE;
1034 if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
1036 gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
1037 gPstat->isOp = true;
1039 memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
1040 memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
1042 ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
1043 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1045 ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
1046 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1048 OICFree(cborPayload);
1052 OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
1058 OICFree(cborPayload);